Blame view

mips_cpu/mips_core/i_cache.sv 5.9 KB
2b3f55ff6   zinsser   Modport added to ...
1
2
3
  /*
   * i_cache.sv
   * Author: Zinsser Zhang
60beb38ad   zinsser   Initial v3.0 comm...
4
   * Last Revision: 03/13/2022
2b3f55ff6   zinsser   Modport added to ...
5
6
7
8
9
10
11
   *
   * This is a direct-mapped instruction cache. Line size and depth (number of
   * lines) are set via INDEX_WIDTH and BLOCK_OFFSET_WIDTH parameters. Notice that
   * line size means number of words (each consist of 32 bit) in a line. Because
   * all addresses in mips_core are 26 byte addresses, so the sum of TAG_WIDTH,
   * INDEX_WIDTH and BLOCK_OFFSET_WIDTH is `ADDR_WIDTH - 2.
   *
60beb38ad   zinsser   Initial v3.0 comm...
12
13
   * Typical line sizes are from 2 words to 8 words. The memory interfaces only
   * support up to 8 words line size.
2b3f55ff6   zinsser   Modport added to ...
14
15
16
   *
   * Because we need a hit latency of 1 cycle, we need an asynchronous read port,
   * i.e. data is ready during the same cycle when address is calculated. However,
60beb38ad   zinsser   Initial v3.0 comm...
17
18
19
20
21
   * SRAMs only support synchronous read, i.e. data is ready the cycle after the
   * address is calculated. Due to this conflict, we need to read from the banks
   * on the clock edge at the beginning of the cycle. As a result, we need both
   * the registered version of address and a non-registered version of address
   * (which will effectively be registered in SRAM).
2b3f55ff6   zinsser   Modport added to ...
22
23
24
   *
   * See wiki page "Synchronous Caches" for details.
   */
22d0f7fc2   zinsser   Release v2.0 Rewo...
25
26
  `include "mips_core.svh"
  
2b3f55ff6   zinsser   Modport added to ...
27
  module i_cache #(
294bafd80   Sankara Ramesh   updating icache s...
28
  	parameter INDEX_WIDTH = 8,
2b3f55ff6   zinsser   Modport added to ...
29
30
  	parameter BLOCK_OFFSET_WIDTH = 2
  	)(
22d0f7fc2   zinsser   Release v2.0 Rewo...
31
32
  	// General signals
  	input clk,    // Clock
60beb38ad   zinsser   Initial v3.0 comm...
33
  	input rst_n,  // Synchronous reset active low
22d0f7fc2   zinsser   Release v2.0 Rewo...
34
35
  
  	// Request
2b3f55ff6   zinsser   Modport added to ...
36
37
  	pc_ifc.in i_pc_current,
  	pc_ifc.in i_pc_next,
22d0f7fc2   zinsser   Release v2.0 Rewo...
38
39
  
  	// Response
2b3f55ff6   zinsser   Modport added to ...
40
  	cache_output_ifc.out out,
22d0f7fc2   zinsser   Release v2.0 Rewo...
41
42
  
  	// Memory interface
60beb38ad   zinsser   Initial v3.0 comm...
43
44
  	axi_read_address.master mem_read_address,
  	axi_read_data.master mem_read_data
22d0f7fc2   zinsser   Release v2.0 Rewo...
45
  );
2b3f55ff6   zinsser   Modport added to ...
46
  	localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2;
22d0f7fc2   zinsser   Release v2.0 Rewo...
47
48
49
50
51
  	localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH;
  	localparam DEPTH = 1 << INDEX_WIDTH;
  
  	// Check if the parameters are set correctly
  	generate
2b3f55ff6   zinsser   Modport added to ...
52
  		if(TAG_WIDTH <= 0 || LINE_SIZE > 16)
22d0f7fc2   zinsser   Release v2.0 Rewo...
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  		begin
  			INVALID_I_CACHE_PARAM invalid_i_cache_param ();
  		end
  	endgenerate
  
  	// Parsing
  	logic [TAG_WIDTH - 1 : 0] i_tag;
  	logic [INDEX_WIDTH - 1 : 0] i_index;
  	logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset;
  
  	logic [INDEX_WIDTH - 1 : 0] i_index_next;
  
  	assign {i_tag, i_index, i_block_offset} = i_pc_current.pc[`ADDR_WIDTH - 1 : 2];
  	assign i_index_next = i_pc_next.pc[BLOCK_OFFSET_WIDTH + 2 +: INDEX_WIDTH];
  	// Above line uses +: slice, a feature of SystemVerilog
  	// See https://stackoverflow.com/questions/18067571
  
  	// States
60beb38ad   zinsser   Initial v3.0 comm...
71
72
73
74
  	enum logic[1:0] {
  		STATE_READY,            // Ready for incoming requests
  		STATE_REFILL_REQUEST,   // Sending out a memory read request
  		STATE_REFILL_DATA       // Missing on a read
22d0f7fc2   zinsser   Release v2.0 Rewo...
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  	} state, next_state;
  
  	// Registers for refilling
  	logic [INDEX_WIDTH - 1:0] r_index;
  	logic [TAG_WIDTH - 1:0] r_tag;
  
  	// databank signals
  	logic [LINE_SIZE - 1 : 0] databank_select;
  	logic [LINE_SIZE - 1 : 0] databank_we;
  	logic [`DATA_WIDTH - 1 : 0] databank_wdata;
  	logic [INDEX_WIDTH - 1 : 0] databank_waddr;
  	logic [INDEX_WIDTH - 1 : 0] databank_raddr;
  	logic [`DATA_WIDTH - 1 : 0] databank_rdata [LINE_SIZE];
  
  	// databanks
  	genvar g;
  	generate
  		for (g = 0; g < LINE_SIZE; g++)
  		begin : databanks
  			cache_bank #(
  				.DATA_WIDTH (`DATA_WIDTH),
  				.ADDR_WIDTH (INDEX_WIDTH)
  			) databank (
  				.clk,
  				.i_we (databank_we[g]),
  				.i_wdata(databank_wdata),
  				.i_waddr(databank_waddr),
  				.i_raddr(databank_raddr),
  
  				.o_rdata(databank_rdata[g])
  			);
  		end
  	endgenerate
  
  	// tagbank signals
  	logic tagbank_we;
  	logic [TAG_WIDTH - 1 : 0] tagbank_wdata;
  	logic [INDEX_WIDTH - 1 : 0] tagbank_waddr;
  	logic [INDEX_WIDTH - 1 : 0] tagbank_raddr;
  	logic [TAG_WIDTH - 1 : 0] tagbank_rdata;
  
  	cache_bank #(
  		.DATA_WIDTH (TAG_WIDTH),
  		.ADDR_WIDTH (INDEX_WIDTH)
  	) tagbank (
  		.clk,
  		.i_we    (tagbank_we),
  		.i_wdata (tagbank_wdata),
  		.i_waddr (tagbank_waddr),
  		.i_raddr (tagbank_raddr),
  
  		.o_rdata (tagbank_rdata)
  	);
  
  	// Valid bits
  	logic [DEPTH - 1 : 0] valid_bits;
  
  	// Intermediate signals
  	logic hit, miss;
  	logic last_refill_word;
  
  
  	always_comb
  	begin
  		hit = valid_bits[i_index]
  			& (i_tag == tagbank_rdata)
  			& (state == STATE_READY);
  		miss = ~hit;
  		last_refill_word = databank_select[LINE_SIZE - 1]
60beb38ad   zinsser   Initial v3.0 comm...
144
  			& mem_read_data.RVALID;
22d0f7fc2   zinsser   Release v2.0 Rewo...
145
146
147
148
  	end
  
  	always_comb
  	begin
60beb38ad   zinsser   Initial v3.0 comm...
149
  		mem_read_address.ARADDR = {r_tag, r_index,
22d0f7fc2   zinsser   Release v2.0 Rewo...
150
  			{BLOCK_OFFSET_WIDTH + 2{1'b0}}};
60beb38ad   zinsser   Initial v3.0 comm...
151
152
153
  		mem_read_address.ARLEN = LINE_SIZE;
  		mem_read_address.ARVALID = state == STATE_REFILL_REQUEST;
  		mem_read_address.ARID = 4'd0;
22d0f7fc2   zinsser   Release v2.0 Rewo...
154
  
60beb38ad   zinsser   Initial v3.0 comm...
155
156
  		// Always ready to consume data
  		mem_read_data.RREADY = 1'b1;
22d0f7fc2   zinsser   Release v2.0 Rewo...
157
158
159
160
  	end
  
  	always_comb
  	begin
60beb38ad   zinsser   Initial v3.0 comm...
161
  		if (mem_read_data.RVALID)
22d0f7fc2   zinsser   Release v2.0 Rewo...
162
163
164
165
  			databank_we = databank_select;
  		else
  			databank_we = '0;
  
60beb38ad   zinsser   Initial v3.0 comm...
166
  		databank_wdata = mem_read_data.RDATA;
22d0f7fc2   zinsser   Release v2.0 Rewo...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  		databank_waddr = r_index;
  		databank_raddr = i_index_next;
  	end
  
  	always_comb
  	begin
  		tagbank_we = last_refill_word;
  		tagbank_wdata = r_tag;
  		tagbank_waddr = r_index;
  		tagbank_raddr = i_index_next;
  	end
  
  	always_comb
  	begin
  		out.valid = hit;
  		out.data = databank_rdata[i_block_offset];
  	end
  
  	always_comb
  	begin
02110307c   zinsser   Synthesis and STA...
187
  		next_state = state;
22d0f7fc2   zinsser   Release v2.0 Rewo...
188
189
  		unique case (state)
  			STATE_READY:
22d0f7fc2   zinsser   Release v2.0 Rewo...
190
  				if (miss)
60beb38ad   zinsser   Initial v3.0 comm...
191
  					next_state = STATE_REFILL_REQUEST;
60beb38ad   zinsser   Initial v3.0 comm...
192
  			STATE_REFILL_REQUEST:
60beb38ad   zinsser   Initial v3.0 comm...
193
194
  				if (mem_read_address.ARREADY)
  					next_state = STATE_REFILL_DATA;
60beb38ad   zinsser   Initial v3.0 comm...
195
  			STATE_REFILL_DATA:
22d0f7fc2   zinsser   Release v2.0 Rewo...
196
197
  				if (last_refill_word)
  					next_state = STATE_READY;
22d0f7fc2   zinsser   Release v2.0 Rewo...
198
199
200
  		endcase
  	end
  
60beb38ad   zinsser   Initial v3.0 comm...
201
  	always_ff @(posedge clk)
22d0f7fc2   zinsser   Release v2.0 Rewo...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  	begin
  		if(~rst_n)
  		begin
  			state <= STATE_READY;
  			databank_select <= 1;
  			valid_bits <= '0;
  		end
  		else
  		begin
  			state <= next_state;
  
  			case (state)
  				STATE_READY:
  				begin
  					if (miss)
  					begin
  						r_tag <= i_tag;
  						r_index <= i_index;
  					end
  				end
60beb38ad   zinsser   Initial v3.0 comm...
222
223
224
225
  				STATE_REFILL_REQUEST:
  				begin
  				end
  				STATE_REFILL_DATA:
22d0f7fc2   zinsser   Release v2.0 Rewo...
226
  				begin
60beb38ad   zinsser   Initial v3.0 comm...
227
  					if (mem_read_data.RVALID)
22d0f7fc2   zinsser   Release v2.0 Rewo...
228
229
230
231
232
233
234
235
236
237
  					begin
  						databank_select <= {databank_select[LINE_SIZE - 2 : 0],
  							databank_select[LINE_SIZE - 1]};
  						valid_bits[r_index] <= last_refill_word;
  					end
  				end
  			endcase
  		end
  	end
  endmodule