Commit 825e38c4a22b43f8f8711f34d865fc56a582d487

Authored by Sankara Ramesh
1 parent b3d8984663

updating comments

Showing 2 changed files with 10 additions and 6 deletions Inline Diff

mips_cpu/mips_core/d_cache.sv View file @ 825e38c
/* 1 1 /*
* d_cache.sv 2 2 * d_cache.sv
* Author: Zinsser Zhang 3 3 * Author: Zinsser Zhang
* Last Revision: 03/13/2022 4 4 * Revision : Sankara
5 * Last Revision: 04/04/2023
* 5 6 *
* This is a direct-mapped data cache. Line size and depth (number of lines) are 6 7 * This is a 2-way set associative data cache. Line size and depth (number of lines) are
* set via INDEX_WIDTH and BLOCK_OFFSET_WIDTH parameters. Notice that line size 7 8 * 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 8 9 * 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, 9 10 * addresses in mips_core are 26 byte addresses, so the sum of TAG_WIDTH,
* INDEX_WIDTH and BLOCK_OFFSET_WIDTH is `ADDR_WIDTH - 2. 10 11 * INDEX_WIDTH and BLOCK_OFFSET_WIDTH is `ADDR_WIDTH - 2.
12 * The ASSOCIATIVITY is fixed at 2 because of the replacement policy. The replacement
13 * policy also needs changes when changing the ASSOCIATIVITY
* 11 14 *
* Typical line sizes are from 2 words to 8 words. The memory interfaces only 12 15 * Typical line sizes are from 2 words to 8 words. The memory interfaces only
* support up to 8 words line size. 13 16 * support up to 8 words line size.
* 14 17 *
* Because we need a hit latency of 1 cycle, we need an asynchronous read port, 15 18 * 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, 16 19 * i.e. data is ready during the same cycle when address is calculated. However,
* SRAMs only support synchronous read, i.e. data is ready the cycle after the 17 20 * 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 18 21 * 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 19 22 * 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 20 23 * the registered version of address and a non-registered version of address
* (which will effectively be registered in SRAM). 21 24 * (which will effectively be registered in SRAM).
* 22 25 *
* See wiki page "Synchronous Caches" for details. 23 26 * See wiki page "Synchronous Caches" for details.
*/ 24 27 */
`include "mips_core.svh" 25 28 `include "mips_core.svh"
26 29
interface d_cache_input_ifc (); 27 30 interface d_cache_input_ifc ();
logic valid; 28 31 logic valid;
mips_core_pkg::MemAccessType mem_action; 29 32 mips_core_pkg::MemAccessType mem_action;
logic [`ADDR_WIDTH - 1 : 0] addr; 30 33 logic [`ADDR_WIDTH - 1 : 0] addr;
logic [`ADDR_WIDTH - 1 : 0] addr_next; 31 34 logic [`ADDR_WIDTH - 1 : 0] addr_next;
logic [`DATA_WIDTH - 1 : 0] data; 32 35 logic [`DATA_WIDTH - 1 : 0] data;
33 36
modport in (input valid, mem_action, addr, addr_next, data); 34 37 modport in (input valid, mem_action, addr, addr_next, data);
modport out (output valid, mem_action, addr, addr_next, data); 35 38 modport out (output valid, mem_action, addr, addr_next, data);
endinterface 36 39 endinterface
37 40
module d_cache #( 38 41 module d_cache #(
parameter INDEX_WIDTH = 6, 39 42 parameter INDEX_WIDTH = 6, // 2 * 1 KB Cache Size
parameter BLOCK_OFFSET_WIDTH = 2, 40 43 parameter BLOCK_OFFSET_WIDTH = 2,
parameter ASSOCIATIVITY = 2 41 44 parameter ASSOCIATIVITY = 2
)( 42 45 )(
// General signals 43 46 // General signals
input clk, // Clock 44 47 input clk, // Clock
input rst_n, // Synchronous reset active low 45 48 input rst_n, // Synchronous reset active low
46 49
// Request 47 50 // Request
d_cache_input_ifc.in in, 48 51 d_cache_input_ifc.in in,
49 52
// Response 50 53 // Response
cache_output_ifc.out out, 51 54 cache_output_ifc.out out,
52 55
// AXI interfaces 53 56 // AXI interfaces
axi_write_address.master mem_write_address, 54 57 axi_write_address.master mem_write_address,
axi_write_data.master mem_write_data, 55 58 axi_write_data.master mem_write_data,
axi_write_response.master mem_write_response, 56 59 axi_write_response.master mem_write_response,
axi_read_address.master mem_read_address, 57 60 axi_read_address.master mem_read_address,
axi_read_data.master mem_read_data 58 61 axi_read_data.master mem_read_data
); 59 62 );
localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2; 60 63 localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2;
localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH; 61 64 localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH;
localparam DEPTH = 1 << INDEX_WIDTH; 62 65 localparam DEPTH = 1 << INDEX_WIDTH;
63 66
// Check if the parameters are set correctly 64 67 // Check if the parameters are set correctly
generate 65 68 generate
if(TAG_WIDTH <= 0 || LINE_SIZE > 16) 66 69 if(TAG_WIDTH <= 0 || LINE_SIZE > 16)
begin 67 70 begin
INVALID_D_CACHE_PARAM invalid_d_cache_param (); 68 71 INVALID_D_CACHE_PARAM invalid_d_cache_param ();
end 69 72 end
endgenerate 70 73 endgenerate
71 74
// Parsing 72 75 // Parsing
logic [TAG_WIDTH - 1 : 0] i_tag; 73 76 logic [TAG_WIDTH - 1 : 0] i_tag;
logic [INDEX_WIDTH - 1 : 0] i_index; 74 77 logic [INDEX_WIDTH - 1 : 0] i_index;
logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset; 75 78 logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset;
76 79
logic [INDEX_WIDTH - 1 : 0] i_index_next; 77 80 logic [INDEX_WIDTH - 1 : 0] i_index_next;
78 81
assign {i_tag, i_index, i_block_offset} = in.addr[`ADDR_WIDTH - 1 : 2]; 79 82 assign {i_tag, i_index, i_block_offset} = in.addr[`ADDR_WIDTH - 1 : 2];
assign i_index_next = in.addr_next[BLOCK_OFFSET_WIDTH + 2 +: INDEX_WIDTH]; 80 83 assign i_index_next = in.addr_next[BLOCK_OFFSET_WIDTH + 2 +: INDEX_WIDTH];
// Above line uses +: slice, a feature of SystemVerilog 81 84 // Above line uses +: slice, a feature of SystemVerilog
// See https://stackoverflow.com/questions/18067571 82 85 // See https://stackoverflow.com/questions/18067571
83 86
// States 84 87 // States
enum logic [2:0] { 85 88 enum logic [2:0] {
STATE_READY, // Ready for incoming requests 86 89 STATE_READY, // Ready for incoming requests
STATE_FLUSH_REQUEST, // Sending out memory write request 87 90 STATE_FLUSH_REQUEST, // Sending out memory write request
STATE_FLUSH_DATA, // Writes out a dirty cache line 88 91 STATE_FLUSH_DATA, // Writes out a dirty cache line
STATE_REFILL_REQUEST, // Sending out memory read request 89 92 STATE_REFILL_REQUEST, // Sending out memory read request
STATE_REFILL_DATA // Loads a cache line from memory 90 93 STATE_REFILL_DATA // Loads a cache line from memory
} state, next_state; 91 94 } state, next_state;
logic pending_write_response; 92 95 logic pending_write_response;
93 96
// Registers for flushing and refilling 94 97 // Registers for flushing and refilling
logic [INDEX_WIDTH - 1:0] r_index; 95 98 logic [INDEX_WIDTH - 1:0] r_index;
logic [TAG_WIDTH - 1:0] r_tag; 96 99 logic [TAG_WIDTH - 1:0] r_tag;
97 100
// databank signals 98 101 // databank signals
logic [LINE_SIZE - 1 : 0] databank_select; 99 102 logic [LINE_SIZE - 1 : 0] databank_select;
logic [LINE_SIZE - 1 : 0] databank_we[ASSOCIATIVITY]; 100 103 logic [LINE_SIZE - 1 : 0] databank_we[ASSOCIATIVITY];
logic [`DATA_WIDTH - 1 : 0] databank_wdata; 101 104 logic [`DATA_WIDTH - 1 : 0] databank_wdata;
logic [INDEX_WIDTH - 1 : 0] databank_waddr; 102 105 logic [INDEX_WIDTH - 1 : 0] databank_waddr;
logic [INDEX_WIDTH - 1 : 0] databank_raddr; 103 106 logic [INDEX_WIDTH - 1 : 0] databank_raddr;
logic [`DATA_WIDTH - 1 : 0] databank_rdata [ASSOCIATIVITY][LINE_SIZE]; 104 107 logic [`DATA_WIDTH - 1 : 0] databank_rdata [ASSOCIATIVITY][LINE_SIZE];
105 108
logic select_way; 106 109 logic select_way;
logic r_select_way; 107 110 logic r_select_way;
logic [DEPTH - 1 : 0] lru_rp; 108 111 logic [DEPTH - 1 : 0] lru_rp;
109 112
// databanks 110 113 // databanks
genvar g,w; 111 114 genvar g,w;
generate 112 115 generate
for (g = 0; g < LINE_SIZE; g++) 113 116 for (g = 0; g < LINE_SIZE; g++)
begin : datasets 114 117 begin : datasets
for (w=0; w< ASSOCIATIVITY; w++) 115 118 for (w=0; w< ASSOCIATIVITY; w++)
begin : databanks 116 119 begin : databanks
cache_bank #( 117 120 cache_bank #(
.DATA_WIDTH (`DATA_WIDTH), 118 121 .DATA_WIDTH (`DATA_WIDTH),
.ADDR_WIDTH (INDEX_WIDTH) 119 122 .ADDR_WIDTH (INDEX_WIDTH)
) databank ( 120 123 ) databank (
.clk, 121 124 .clk,
.i_we (databank_we[w][g]), 122 125 .i_we (databank_we[w][g]),
.i_wdata(databank_wdata), 123 126 .i_wdata(databank_wdata),
.i_waddr(databank_waddr), 124 127 .i_waddr(databank_waddr),
.i_raddr(databank_raddr), 125 128 .i_raddr(databank_raddr),
126 129
.o_rdata(databank_rdata[w][g]) 127 130 .o_rdata(databank_rdata[w][g])
); 128 131 );
end 129 132 end
end 130 133 end
endgenerate 131 134 endgenerate
132 135
// tagbank signals 133 136 // tagbank signals
logic tagbank_we[ASSOCIATIVITY]; 134 137 logic tagbank_we[ASSOCIATIVITY];
logic [TAG_WIDTH - 1 : 0] tagbank_wdata; 135 138 logic [TAG_WIDTH - 1 : 0] tagbank_wdata;
logic [INDEX_WIDTH - 1 : 0] tagbank_waddr; 136 139 logic [INDEX_WIDTH - 1 : 0] tagbank_waddr;
logic [INDEX_WIDTH - 1 : 0] tagbank_raddr; 137 140 logic [INDEX_WIDTH - 1 : 0] tagbank_raddr;
logic [TAG_WIDTH - 1 : 0] tagbank_rdata[ASSOCIATIVITY]; 138 141 logic [TAG_WIDTH - 1 : 0] tagbank_rdata[ASSOCIATIVITY];
139 142
generate 140 143 generate
for (w=0; w< ASSOCIATIVITY; w++) 141 144 for (w=0; w< ASSOCIATIVITY; w++)
begin: tagbanks 142 145 begin: tagbanks
cache_bank #( 143 146 cache_bank #(
.DATA_WIDTH (TAG_WIDTH), 144 147 .DATA_WIDTH (TAG_WIDTH),
.ADDR_WIDTH (INDEX_WIDTH) 145 148 .ADDR_WIDTH (INDEX_WIDTH)
) tagbank ( 146 149 ) tagbank (
.clk, 147 150 .clk,
.i_we (tagbank_we[w]), 148 151 .i_we (tagbank_we[w]),
.i_wdata (tagbank_wdata), 149 152 .i_wdata (tagbank_wdata),
.i_waddr (tagbank_waddr), 150 153 .i_waddr (tagbank_waddr),
.i_raddr (tagbank_raddr), 151 154 .i_raddr (tagbank_raddr),
152 155
.o_rdata (tagbank_rdata[w]) 153 156 .o_rdata (tagbank_rdata[w])
); 154 157 );
end 155 158 end
endgenerate 156 159 endgenerate
157 160
// Valid bits 158 161 // Valid bits
logic [DEPTH - 1 : 0] valid_bits[ASSOCIATIVITY]; 159 162 logic [DEPTH - 1 : 0] valid_bits[ASSOCIATIVITY];
// Dirty bits 160 163 // Dirty bits
logic [DEPTH - 1 : 0] dirty_bits[ASSOCIATIVITY]; 161 164 logic [DEPTH - 1 : 0] dirty_bits[ASSOCIATIVITY];
162 165
// Shift registers for flushing 163 166 // Shift registers for flushing
logic [`DATA_WIDTH - 1 : 0] shift_rdata[LINE_SIZE]; 164 167 logic [`DATA_WIDTH - 1 : 0] shift_rdata[LINE_SIZE];
165 168
// Intermediate signals 166 169 // Intermediate signals
logic hit, miss, tag_hit; 167 170 logic hit, miss, tag_hit;
logic last_flush_word; 168 171 logic last_flush_word;
logic last_refill_word; 169 172 logic last_refill_word;
170 173
always_comb 171 174 always_comb
begin 172 175 begin
tag_hit = ( ((i_tag == tagbank_rdata[0]) & valid_bits[0][i_index]) 173 176 tag_hit = ( ((i_tag == tagbank_rdata[0]) & valid_bits[0][i_index])
| ((i_tag == tagbank_rdata[1]) & valid_bits[1][i_index])); 174 177 | ((i_tag == tagbank_rdata[1]) & valid_bits[1][i_index]));
hit = in.valid 175 178 hit = in.valid
& (tag_hit) 176 179 & (tag_hit)
& (state == STATE_READY); 177 180 & (state == STATE_READY);
miss = in.valid & ~hit; 178 181 miss = in.valid & ~hit;
last_flush_word = databank_select[LINE_SIZE - 1] & mem_write_data.WVALID; 179 182 last_flush_word = databank_select[LINE_SIZE - 1] & mem_write_data.WVALID;
last_refill_word = databank_select[LINE_SIZE - 1] & mem_read_data.RVALID; 180 183 last_refill_word = databank_select[LINE_SIZE - 1] & mem_read_data.RVALID;
181 184
if (hit) 182 185 if (hit)
begin 183 186 begin
if (i_tag == tagbank_rdata[0]) 184 187 if (i_tag == tagbank_rdata[0])
begin 185 188 begin
select_way = 'b0; 186 189 select_way = 'b0;
end 187 190 end
else 188 191 else
begin 189 192 begin
select_way = 'b1; 190 193 select_way = 'b1;
end 191 194 end
end 192 195 end
else if (miss) 193 196 else if (miss)
begin 194 197 begin
select_way = lru_rp[i_index]; 195 198 select_way = lru_rp[i_index];
end 196 199 end
else 197 200 else
begin 198 201 begin
select_way = 'b0; 199 202 select_way = 'b0;
end 200 203 end
201 204
end 202 205 end
203 206
always_comb 204 207 always_comb
begin 205 208 begin
mem_write_address.AWVALID = state == STATE_FLUSH_REQUEST; 206 209 mem_write_address.AWVALID = state == STATE_FLUSH_REQUEST;
mem_write_address.AWID = 0; 207 210 mem_write_address.AWID = 0;
mem_write_address.AWLEN = LINE_SIZE; 208 211 mem_write_address.AWLEN = LINE_SIZE;
mem_write_address.AWADDR = {tagbank_rdata[r_select_way], i_index, {BLOCK_OFFSET_WIDTH + 2{1'b0}}}; 209 212 mem_write_address.AWADDR = {tagbank_rdata[r_select_way], i_index, {BLOCK_OFFSET_WIDTH + 2{1'b0}}};
mem_write_data.WVALID = state == STATE_FLUSH_DATA; 210 213 mem_write_data.WVALID = state == STATE_FLUSH_DATA;
mem_write_data.WID = 0; 211 214 mem_write_data.WID = 0;
mem_write_data.WDATA = shift_rdata[0]; 212 215 mem_write_data.WDATA = shift_rdata[0];
mem_write_data.WLAST = last_flush_word; 213 216 mem_write_data.WLAST = last_flush_word;
214 217
// Always ready to consume write response 215 218 // Always ready to consume write response
mem_write_response.BREADY = 1'b1; 216 219 mem_write_response.BREADY = 1'b1;
end 217 220 end
218 221
always_comb begin 219 222 always_comb begin
mem_read_address.ARADDR = {r_tag, r_index, {BLOCK_OFFSET_WIDTH + 2{1'b0}}}; 220 223 mem_read_address.ARADDR = {r_tag, r_index, {BLOCK_OFFSET_WIDTH + 2{1'b0}}};
mem_read_address.ARLEN = LINE_SIZE; 221 224 mem_read_address.ARLEN = LINE_SIZE;
mem_read_address.ARVALID = state == STATE_REFILL_REQUEST; 222 225 mem_read_address.ARVALID = state == STATE_REFILL_REQUEST;
mem_read_address.ARID = 4'd1; 223 226 mem_read_address.ARID = 4'd1;
224 227
// Always ready to consume data 225 228 // Always ready to consume data
mem_read_data.RREADY = 1'b1; 226 229 mem_read_data.RREADY = 1'b1;
end 227 230 end
228 231
always_comb 229 232 always_comb
begin 230 233 begin
for (int i=0; i<ASSOCIATIVITY;i++) 231 234 for (int i=0; i<ASSOCIATIVITY;i++)
databank_we[i] = '0; 232 235 databank_we[i] = '0;
if (mem_read_data.RVALID) // We are refilling data 233 236 if (mem_read_data.RVALID) // We are refilling data
databank_we[r_select_way] = databank_select; 234 237 databank_we[r_select_way] = databank_select;
else if (hit & (in.mem_action == WRITE)) // We are storing a word 235 238 else if (hit & (in.mem_action == WRITE)) // We are storing a word
databank_we[select_way][i_block_offset] = 1'b1; 236 239 databank_we[select_way][i_block_offset] = 1'b1;
end 237 240 end
238 241
always_comb 239 242 always_comb
begin 240 243 begin
if (state == STATE_READY) 241 244 if (state == STATE_READY)
begin 242 245 begin
databank_wdata = in.data; 243 246 databank_wdata = in.data;
databank_waddr = i_index; 244 247 databank_waddr = i_index;
if (next_state == STATE_FLUSH_REQUEST) 245 248 if (next_state == STATE_FLUSH_REQUEST)
databank_raddr = i_index; 246 249 databank_raddr = i_index;
else 247 250 else
databank_raddr = i_index_next; 248 251 databank_raddr = i_index_next;
end 249 252 end
else 250 253 else
begin 251 254 begin
databank_wdata = mem_read_data.RDATA; 252 255 databank_wdata = mem_read_data.RDATA;
databank_waddr = r_index; 253 256 databank_waddr = r_index;
if (next_state == STATE_READY) 254 257 if (next_state == STATE_READY)
databank_raddr = i_index_next; 255 258 databank_raddr = i_index_next;
else 256 259 else
databank_raddr = r_index; 257 260 databank_raddr = r_index;
end 258 261 end
end 259 262 end
260 263
always_comb 261 264 always_comb
begin 262 265 begin
tagbank_we[r_select_way] = last_refill_word; 263 266 tagbank_we[r_select_way] = last_refill_word;
tagbank_we[~r_select_way] = '0; 264 267 tagbank_we[~r_select_way] = '0;
tagbank_wdata = r_tag; 265 268 tagbank_wdata = r_tag;
tagbank_waddr = r_index; 266 269 tagbank_waddr = r_index;
tagbank_raddr = i_index_next; 267 270 tagbank_raddr = i_index_next;
end 268 271 end
269 272
always_comb 270 273 always_comb
begin 271 274 begin
out.valid = hit; 272 275 out.valid = hit;
out.data = databank_rdata[select_way][i_block_offset]; 273 276 out.data = databank_rdata[select_way][i_block_offset];
end 274 277 end
275 278
always_comb 276 279 always_comb
begin 277 280 begin
next_state = state; 278 281 next_state = state;
unique case (state) 279 282 unique case (state)
STATE_READY: 280 283 STATE_READY:
if (miss) 281 284 if (miss)
if (valid_bits[select_way][i_index] & dirty_bits[select_way][i_index]) 282 285 if (valid_bits[select_way][i_index] & dirty_bits[select_way][i_index])
next_state = STATE_FLUSH_REQUEST; 283 286 next_state = STATE_FLUSH_REQUEST;
else 284 287 else
next_state = STATE_REFILL_REQUEST; 285 288 next_state = STATE_REFILL_REQUEST;
286 289
STATE_FLUSH_REQUEST: 287 290 STATE_FLUSH_REQUEST:
if (mem_write_address.AWREADY) 288 291 if (mem_write_address.AWREADY)
next_state = STATE_FLUSH_DATA; 289 292 next_state = STATE_FLUSH_DATA;
290 293
STATE_FLUSH_DATA: 291 294 STATE_FLUSH_DATA:
if (last_flush_word && mem_write_data.WREADY) 292 295 if (last_flush_word && mem_write_data.WREADY)
next_state = STATE_REFILL_REQUEST; 293 296 next_state = STATE_REFILL_REQUEST;
294 297
STATE_REFILL_REQUEST: 295 298 STATE_REFILL_REQUEST:
if (mem_read_address.ARREADY) 296 299 if (mem_read_address.ARREADY)
next_state = STATE_REFILL_DATA; 297 300 next_state = STATE_REFILL_DATA;
298 301
STATE_REFILL_DATA: 299 302 STATE_REFILL_DATA:
if (last_refill_word) 300 303 if (last_refill_word)
next_state = STATE_READY; 301 304 next_state = STATE_READY;
endcase 302 305 endcase
end 303 306 end
304 307
always_ff @(posedge clk) begin 305 308 always_ff @(posedge clk) begin
if (~rst_n) 306 309 if (~rst_n)
pending_write_response <= 1'b0; 307 310 pending_write_response <= 1'b0;
else if (mem_write_address.AWVALID && mem_write_address.AWREADY) 308 311 else if (mem_write_address.AWVALID && mem_write_address.AWREADY)
pending_write_response <= 1'b1; 309 312 pending_write_response <= 1'b1;
else if (mem_write_response.BVALID && mem_write_response.BREADY) 310 313 else if (mem_write_response.BVALID && mem_write_response.BREADY)
pending_write_response <= 1'b0; 311 314 pending_write_response <= 1'b0;
end 312 315 end
313 316
always_ff @(posedge clk) 314 317 always_ff @(posedge clk)
begin 315 318 begin
if (state == STATE_FLUSH_DATA && mem_write_data.WREADY) 316 319 if (state == STATE_FLUSH_DATA && mem_write_data.WREADY)
for (int i = 0; i < LINE_SIZE - 1; i++) 317 320 for (int i = 0; i < LINE_SIZE - 1; i++)
shift_rdata[i] <= shift_rdata[i+1]; 318 321 shift_rdata[i] <= shift_rdata[i+1];
319 322
if (state == STATE_FLUSH_REQUEST && next_state == STATE_FLUSH_DATA) 320 323 if (state == STATE_FLUSH_REQUEST && next_state == STATE_FLUSH_DATA)
for (int i = 0; i < LINE_SIZE; i++) 321 324 for (int i = 0; i < LINE_SIZE; i++)
shift_rdata[i] <= databank_rdata[r_select_way][i]; 322 325 shift_rdata[i] <= databank_rdata[r_select_way][i];
end 323 326 end
324 327
always_ff @(posedge clk) 325 328 always_ff @(posedge clk)
begin 326 329 begin
if(~rst_n) 327 330 if(~rst_n)
begin 328 331 begin
state <= STATE_READY; 329 332 state <= STATE_READY;
databank_select <= 1; 330 333 databank_select <= 1;
for (int i=0; i<ASSOCIATIVITY;i++) 331 334 for (int i=0; i<ASSOCIATIVITY;i++)
valid_bits[i] <= '0; 332 335 valid_bits[i] <= '0;
for (int i=0; i<DEPTH;i++) 333 336 for (int i=0; i<DEPTH;i++)
lru_rp[i] <= 0; 334 337 lru_rp[i] <= 0;
end 335 338 end
else 336 339 else
mips_cpu/mips_core/i_cache.sv View file @ 825e38c
/* 1 1 /*
* i_cache.sv 2 2 * i_cache.sv
* Author: Zinsser Zhang 3 3 * Author: Zinsser Zhang
* Last Revision: 03/13/2022 4 4 * Revision : Sankara
5 * Last Revision: 04/04/2023
* 5 6 *
* This is a direct-mapped instruction cache. Line size and depth (number of 6 7 * 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 7 8 * 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 8 9 * 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, 9 10 * 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. 10 11 * INDEX_WIDTH and BLOCK_OFFSET_WIDTH is `ADDR_WIDTH - 2.
* 11 12 *
* Typical line sizes are from 2 words to 8 words. The memory interfaces only 12 13 * Typical line sizes are from 2 words to 8 words. The memory interfaces only
* support up to 8 words line size. 13 14 * support up to 8 words line size.
* 14 15 *
* Because we need a hit latency of 1 cycle, we need an asynchronous read port, 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, 16 17 * i.e. data is ready during the same cycle when address is calculated. However,
* SRAMs only support synchronous read, i.e. data is ready the cycle after the 17 18 * 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 18 19 * 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 19 20 * 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 20 21 * the registered version of address and a non-registered version of address
* (which will effectively be registered in SRAM). 21 22 * (which will effectively be registered in SRAM).
* 22 23 *
* See wiki page "Synchronous Caches" for details. 23 24 * See wiki page "Synchronous Caches" for details.
*/ 24 25 */
`include "mips_core.svh" 25 26 `include "mips_core.svh"
26 27
module i_cache #( 27 28 module i_cache #(
parameter INDEX_WIDTH = 6, 28 29 parameter INDEX_WIDTH = 6, // 1 KB Cahe size
parameter BLOCK_OFFSET_WIDTH = 2 29 30 parameter BLOCK_OFFSET_WIDTH = 2
)( 30 31 )(
// General signals 31 32 // General signals
input clk, // Clock 32 33 input clk, // Clock
input rst_n, // Synchronous reset active low 33 34 input rst_n, // Synchronous reset active low
34 35
// Request 35 36 // Request
pc_ifc.in i_pc_current, 36 37 pc_ifc.in i_pc_current,
pc_ifc.in i_pc_next, 37 38 pc_ifc.in i_pc_next,
38 39
// Response 39 40 // Response
cache_output_ifc.out out, 40 41 cache_output_ifc.out out,
41 42
// Memory interface 42 43 // Memory interface
axi_read_address.master mem_read_address, 43 44 axi_read_address.master mem_read_address,
axi_read_data.master mem_read_data 44 45 axi_read_data.master mem_read_data
); 45 46 );
localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2; 46 47 localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2;
localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH; 47 48 localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH;
localparam DEPTH = 1 << INDEX_WIDTH; 48 49 localparam DEPTH = 1 << INDEX_WIDTH;
49 50
// Check if the parameters are set correctly 50 51 // Check if the parameters are set correctly
generate 51 52 generate
if(TAG_WIDTH <= 0 || LINE_SIZE > 16) 52 53 if(TAG_WIDTH <= 0 || LINE_SIZE > 16)
begin 53 54 begin
INVALID_I_CACHE_PARAM invalid_i_cache_param (); 54 55 INVALID_I_CACHE_PARAM invalid_i_cache_param ();
end 55 56 end
endgenerate 56 57 endgenerate
57 58
// Parsing 58 59 // Parsing
logic [TAG_WIDTH - 1 : 0] i_tag; 59 60 logic [TAG_WIDTH - 1 : 0] i_tag;
logic [INDEX_WIDTH - 1 : 0] i_index; 60 61 logic [INDEX_WIDTH - 1 : 0] i_index;
logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset; 61 62 logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset;
62 63
logic [INDEX_WIDTH - 1 : 0] i_index_next; 63 64 logic [INDEX_WIDTH - 1 : 0] i_index_next;
64 65
assign {i_tag, i_index, i_block_offset} = i_pc_current.pc[`ADDR_WIDTH - 1 : 2]; 65 66 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]; 66 67 assign i_index_next = i_pc_next.pc[BLOCK_OFFSET_WIDTH + 2 +: INDEX_WIDTH];
// Above line uses +: slice, a feature of SystemVerilog 67 68 // Above line uses +: slice, a feature of SystemVerilog
// See https://stackoverflow.com/questions/18067571 68 69 // See https://stackoverflow.com/questions/18067571
69 70
// States 70 71 // States
enum logic[1:0] { 71 72 enum logic[1:0] {
STATE_READY, // Ready for incoming requests 72 73 STATE_READY, // Ready for incoming requests
STATE_REFILL_REQUEST, // Sending out a memory read request 73 74 STATE_REFILL_REQUEST, // Sending out a memory read request
STATE_REFILL_DATA // Missing on a read 74 75 STATE_REFILL_DATA // Missing on a read
} state, next_state; 75 76 } state, next_state;
76 77
// Registers for refilling 77 78 // Registers for refilling
logic [INDEX_WIDTH - 1:0] r_index; 78 79 logic [INDEX_WIDTH - 1:0] r_index;
logic [TAG_WIDTH - 1:0] r_tag; 79 80 logic [TAG_WIDTH - 1:0] r_tag;
80 81
// databank signals 81 82 // databank signals
logic [LINE_SIZE - 1 : 0] databank_select; 82 83 logic [LINE_SIZE - 1 : 0] databank_select;
logic [LINE_SIZE - 1 : 0] databank_we; 83 84 logic [LINE_SIZE - 1 : 0] databank_we;
logic [`DATA_WIDTH - 1 : 0] databank_wdata; 84 85 logic [`DATA_WIDTH - 1 : 0] databank_wdata;
logic [INDEX_WIDTH - 1 : 0] databank_waddr; 85 86 logic [INDEX_WIDTH - 1 : 0] databank_waddr;
logic [INDEX_WIDTH - 1 : 0] databank_raddr; 86 87 logic [INDEX_WIDTH - 1 : 0] databank_raddr;
logic [`DATA_WIDTH - 1 : 0] databank_rdata [LINE_SIZE]; 87 88 logic [`DATA_WIDTH - 1 : 0] databank_rdata [LINE_SIZE];
88 89
// databanks 89 90 // databanks
genvar g; 90 91 genvar g;
generate 91 92 generate
for (g = 0; g < LINE_SIZE; g++) 92 93 for (g = 0; g < LINE_SIZE; g++)
begin : databanks 93 94 begin : databanks
cache_bank #( 94 95 cache_bank #(
.DATA_WIDTH (`DATA_WIDTH), 95 96 .DATA_WIDTH (`DATA_WIDTH),
.ADDR_WIDTH (INDEX_WIDTH) 96 97 .ADDR_WIDTH (INDEX_WIDTH)
) databank ( 97 98 ) databank (
.clk, 98 99 .clk,
.i_we (databank_we[g]), 99 100 .i_we (databank_we[g]),
.i_wdata(databank_wdata), 100 101 .i_wdata(databank_wdata),
.i_waddr(databank_waddr), 101 102 .i_waddr(databank_waddr),
.i_raddr(databank_raddr), 102 103 .i_raddr(databank_raddr),
103 104
.o_rdata(databank_rdata[g]) 104 105 .o_rdata(databank_rdata[g])
); 105 106 );
end 106 107 end
endgenerate 107 108 endgenerate
108 109
// tagbank signals 109 110 // tagbank signals
logic tagbank_we; 110 111 logic tagbank_we;
logic [TAG_WIDTH - 1 : 0] tagbank_wdata; 111 112 logic [TAG_WIDTH - 1 : 0] tagbank_wdata;
logic [INDEX_WIDTH - 1 : 0] tagbank_waddr; 112 113 logic [INDEX_WIDTH - 1 : 0] tagbank_waddr;
logic [INDEX_WIDTH - 1 : 0] tagbank_raddr; 113 114 logic [INDEX_WIDTH - 1 : 0] tagbank_raddr;
logic [TAG_WIDTH - 1 : 0] tagbank_rdata; 114 115 logic [TAG_WIDTH - 1 : 0] tagbank_rdata;
115 116
cache_bank #( 116 117 cache_bank #(
.DATA_WIDTH (TAG_WIDTH), 117 118 .DATA_WIDTH (TAG_WIDTH),
.ADDR_WIDTH (INDEX_WIDTH) 118 119 .ADDR_WIDTH (INDEX_WIDTH)
) tagbank ( 119 120 ) tagbank (
.clk, 120 121 .clk,
.i_we (tagbank_we), 121 122 .i_we (tagbank_we),
.i_wdata (tagbank_wdata), 122 123 .i_wdata (tagbank_wdata),
.i_waddr (tagbank_waddr), 123 124 .i_waddr (tagbank_waddr),
.i_raddr (tagbank_raddr), 124 125 .i_raddr (tagbank_raddr),
125 126
.o_rdata (tagbank_rdata) 126 127 .o_rdata (tagbank_rdata)
); 127 128 );
128 129
// Valid bits 129 130 // Valid bits
logic [DEPTH - 1 : 0] valid_bits; 130 131 logic [DEPTH - 1 : 0] valid_bits;
131 132
// Intermediate signals 132 133 // Intermediate signals
logic hit, miss; 133 134 logic hit, miss;
logic last_refill_word; 134 135 logic last_refill_word;
135 136
136 137
always_comb 137 138 always_comb
begin 138 139 begin
hit = valid_bits[i_index] 139 140 hit = valid_bits[i_index]
& (i_tag == tagbank_rdata) 140 141 & (i_tag == tagbank_rdata)
& (state == STATE_READY); 141 142 & (state == STATE_READY);
miss = ~hit; 142 143 miss = ~hit;
last_refill_word = databank_select[LINE_SIZE - 1] 143 144 last_refill_word = databank_select[LINE_SIZE - 1]
& mem_read_data.RVALID; 144 145 & mem_read_data.RVALID;
end 145 146 end
146 147
always_comb 147 148 always_comb
begin 148 149 begin
mem_read_address.ARADDR = {r_tag, r_index, 149 150 mem_read_address.ARADDR = {r_tag, r_index,
{BLOCK_OFFSET_WIDTH + 2{1'b0}}}; 150 151 {BLOCK_OFFSET_WIDTH + 2{1'b0}}};
mem_read_address.ARLEN = LINE_SIZE; 151 152 mem_read_address.ARLEN = LINE_SIZE;
mem_read_address.ARVALID = state == STATE_REFILL_REQUEST; 152 153 mem_read_address.ARVALID = state == STATE_REFILL_REQUEST;
mem_read_address.ARID = 4'd0; 153 154 mem_read_address.ARID = 4'd0;
154 155
// Always ready to consume data 155 156 // Always ready to consume data
mem_read_data.RREADY = 1'b1; 156 157 mem_read_data.RREADY = 1'b1;
end 157 158 end
158 159
always_comb 159 160 always_comb
begin 160 161 begin
if (mem_read_data.RVALID) 161 162 if (mem_read_data.RVALID)
databank_we = databank_select; 162 163 databank_we = databank_select;
else 163 164 else
databank_we = '0; 164 165 databank_we = '0;
165 166
databank_wdata = mem_read_data.RDATA; 166 167 databank_wdata = mem_read_data.RDATA;
databank_waddr = r_index; 167 168 databank_waddr = r_index;
databank_raddr = i_index_next; 168 169 databank_raddr = i_index_next;
end 169 170 end
170 171
always_comb 171 172 always_comb
begin 172 173 begin
tagbank_we = last_refill_word; 173 174 tagbank_we = last_refill_word;
tagbank_wdata = r_tag; 174 175 tagbank_wdata = r_tag;
tagbank_waddr = r_index; 175 176 tagbank_waddr = r_index;
tagbank_raddr = i_index_next; 176 177 tagbank_raddr = i_index_next;
end 177 178 end
178 179
always_comb 179 180 always_comb
begin 180 181 begin
out.valid = hit; 181 182 out.valid = hit;
out.data = databank_rdata[i_block_offset]; 182 183 out.data = databank_rdata[i_block_offset];
end 183 184 end
184 185
always_comb 185 186 always_comb
begin 186 187 begin
next_state = state; 187 188 next_state = state;
unique case (state) 188 189 unique case (state)
STATE_READY: 189 190 STATE_READY:
if (miss) 190 191 if (miss)
next_state = STATE_REFILL_REQUEST; 191 192 next_state = STATE_REFILL_REQUEST;
STATE_REFILL_REQUEST: 192 193 STATE_REFILL_REQUEST:
if (mem_read_address.ARREADY) 193 194 if (mem_read_address.ARREADY)
next_state = STATE_REFILL_DATA; 194 195 next_state = STATE_REFILL_DATA;
STATE_REFILL_DATA: 195 196 STATE_REFILL_DATA:
if (last_refill_word) 196 197 if (last_refill_word)
next_state = STATE_READY; 197 198 next_state = STATE_READY;
endcase 198 199 endcase
end 199 200 end
200 201
always_ff @(posedge clk) 201 202 always_ff @(posedge clk)
begin 202 203 begin
if(~rst_n) 203 204 if(~rst_n)
begin 204 205 begin
state <= STATE_READY; 205 206 state <= STATE_READY;
databank_select <= 1; 206 207 databank_select <= 1;
valid_bits <= '0; 207 208 valid_bits <= '0;
end 208 209 end
else 209 210 else
begin 210 211 begin
state <= next_state; 211 212 state <= next_state;