Commit 825e38c4a22b43f8f8711f34d865fc56a582d487
1 parent
b3d8984663
Exists in
master
and in
2 other branches
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; |