Commit 294bafd8064b09fd220ba38ecc17d97045208e1b
1 parent
d3c3d4e520
Exists in
master
and in
2 other branches
updating icache sizes
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
mips_cpu/mips_core/i_cache.sv
View file @
294bafd
/* | 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 | * Last Revision: 03/13/2022 | |
* | 5 | 5 | * | |
* This is a direct-mapped instruction cache. Line size and depth (number of | 6 | 6 | * 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 | 7 | * 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 | 8 | * 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 | 9 | * 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 | 10 | * INDEX_WIDTH and BLOCK_OFFSET_WIDTH is `ADDR_WIDTH - 2. | |
* | 11 | 11 | * | |
* Typical line sizes are from 2 words to 8 words. The memory interfaces only | 12 | 12 | * Typical line sizes are from 2 words to 8 words. The memory interfaces only | |
* support up to 8 words line size. | 13 | 13 | * support up to 8 words line size. | |
* | 14 | 14 | * | |
* Because we need a hit latency of 1 cycle, we need an asynchronous read port, | 15 | 15 | * 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 | 16 | * 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 | 17 | * 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 | 18 | * 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 | 19 | * 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 | 20 | * the registered version of address and a non-registered version of address | |
* (which will effectively be registered in SRAM). | 21 | 21 | * (which will effectively be registered in SRAM). | |
* | 22 | 22 | * | |
* See wiki page "Synchronous Caches" for details. | 23 | 23 | * See wiki page "Synchronous Caches" for details. | |
*/ | 24 | 24 | */ | |
`include "mips_core.svh" | 25 | 25 | `include "mips_core.svh" | |
26 | 26 | |||
module i_cache #( | 27 | 27 | module i_cache #( | |
parameter INDEX_WIDTH = 5, | 28 | 28 | parameter INDEX_WIDTH = 8, | |
parameter BLOCK_OFFSET_WIDTH = 2 | 29 | 29 | parameter BLOCK_OFFSET_WIDTH = 2 | |
)( | 30 | 30 | )( | |
// General signals | 31 | 31 | // General signals | |
input clk, // Clock | 32 | 32 | input clk, // Clock | |
input rst_n, // Synchronous reset active low | 33 | 33 | input rst_n, // Synchronous reset active low | |
34 | 34 | |||
// Request | 35 | 35 | // Request | |
pc_ifc.in i_pc_current, | 36 | 36 | pc_ifc.in i_pc_current, | |
pc_ifc.in i_pc_next, | 37 | 37 | pc_ifc.in i_pc_next, | |
38 | 38 | |||
// Response | 39 | 39 | // Response | |
cache_output_ifc.out out, | 40 | 40 | cache_output_ifc.out out, | |
41 | 41 | |||
// Memory interface | 42 | 42 | // Memory interface | |
axi_read_address.master mem_read_address, | 43 | 43 | axi_read_address.master mem_read_address, | |
axi_read_data.master mem_read_data | 44 | 44 | axi_read_data.master mem_read_data | |
); | 45 | 45 | ); | |
localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2; | 46 | 46 | localparam TAG_WIDTH = `ADDR_WIDTH - INDEX_WIDTH - BLOCK_OFFSET_WIDTH - 2; | |
localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH; | 47 | 47 | localparam LINE_SIZE = 1 << BLOCK_OFFSET_WIDTH; | |
localparam DEPTH = 1 << INDEX_WIDTH; | 48 | 48 | localparam DEPTH = 1 << INDEX_WIDTH; | |
49 | 49 | |||
// Check if the parameters are set correctly | 50 | 50 | // Check if the parameters are set correctly | |
generate | 51 | 51 | generate | |
if(TAG_WIDTH <= 0 || LINE_SIZE > 16) | 52 | 52 | if(TAG_WIDTH <= 0 || LINE_SIZE > 16) | |
begin | 53 | 53 | begin | |
INVALID_I_CACHE_PARAM invalid_i_cache_param (); | 54 | 54 | INVALID_I_CACHE_PARAM invalid_i_cache_param (); | |
end | 55 | 55 | end | |
endgenerate | 56 | 56 | endgenerate | |
57 | 57 | |||
// Parsing | 58 | 58 | // Parsing | |
logic [TAG_WIDTH - 1 : 0] i_tag; | 59 | 59 | logic [TAG_WIDTH - 1 : 0] i_tag; | |
logic [INDEX_WIDTH - 1 : 0] i_index; | 60 | 60 | logic [INDEX_WIDTH - 1 : 0] i_index; | |
logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset; | 61 | 61 | logic [BLOCK_OFFSET_WIDTH - 1 : 0] i_block_offset; | |
62 | 62 | |||
logic [INDEX_WIDTH - 1 : 0] i_index_next; | 63 | 63 | logic [INDEX_WIDTH - 1 : 0] i_index_next; | |
64 | 64 | |||
assign {i_tag, i_index, i_block_offset} = i_pc_current.pc[`ADDR_WIDTH - 1 : 2]; | 65 | 65 | 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 | 66 | assign i_index_next = i_pc_next.pc[BLOCK_OFFSET_WIDTH + 2 +: INDEX_WIDTH]; | |
// Above line uses +: slice, a feature of SystemVerilog | 67 | 67 | // Above line uses +: slice, a feature of SystemVerilog | |
// See https://stackoverflow.com/questions/18067571 | 68 | 68 | // See https://stackoverflow.com/questions/18067571 | |
69 | 69 | |||
// States | 70 | 70 | // States | |
enum logic[1:0] { | 71 | 71 | enum logic[1:0] { | |
STATE_READY, // Ready for incoming requests | 72 | 72 | STATE_READY, // Ready for incoming requests | |
STATE_REFILL_REQUEST, // Sending out a memory read request | 73 | 73 | STATE_REFILL_REQUEST, // Sending out a memory read request | |
STATE_REFILL_DATA // Missing on a read | 74 | 74 | STATE_REFILL_DATA // Missing on a read | |
} state, next_state; | 75 | 75 | } state, next_state; | |
76 | 76 | |||
// Registers for refilling | 77 | 77 | // Registers for refilling | |
logic [INDEX_WIDTH - 1:0] r_index; | 78 | 78 | logic [INDEX_WIDTH - 1:0] r_index; | |
logic [TAG_WIDTH - 1:0] r_tag; | 79 | 79 | logic [TAG_WIDTH - 1:0] r_tag; | |
80 | 80 | |||
// databank signals | 81 | 81 | // databank signals | |
logic [LINE_SIZE - 1 : 0] databank_select; | 82 | 82 | logic [LINE_SIZE - 1 : 0] databank_select; | |
logic [LINE_SIZE - 1 : 0] databank_we; | 83 | 83 | logic [LINE_SIZE - 1 : 0] databank_we; | |
logic [`DATA_WIDTH - 1 : 0] databank_wdata; | 84 | 84 | logic [`DATA_WIDTH - 1 : 0] databank_wdata; | |
logic [INDEX_WIDTH - 1 : 0] databank_waddr; | 85 | 85 | logic [INDEX_WIDTH - 1 : 0] databank_waddr; | |
logic [INDEX_WIDTH - 1 : 0] databank_raddr; | 86 | 86 | logic [INDEX_WIDTH - 1 : 0] databank_raddr; | |
logic [`DATA_WIDTH - 1 : 0] databank_rdata [LINE_SIZE]; | 87 | 87 | logic [`DATA_WIDTH - 1 : 0] databank_rdata [LINE_SIZE]; | |
88 | 88 | |||
// databanks | 89 | 89 | // databanks | |
genvar g; | 90 | 90 | genvar g; | |
generate | 91 | 91 | generate | |
for (g = 0; g < LINE_SIZE; g++) | 92 | 92 | for (g = 0; g < LINE_SIZE; g++) | |
begin : databanks | 93 | 93 | begin : databanks | |
cache_bank #( | 94 | 94 | cache_bank #( | |
.DATA_WIDTH (`DATA_WIDTH), | 95 | 95 | .DATA_WIDTH (`DATA_WIDTH), | |
.ADDR_WIDTH (INDEX_WIDTH) | 96 | 96 | .ADDR_WIDTH (INDEX_WIDTH) | |
) databank ( | 97 | 97 | ) databank ( | |
.clk, | 98 | 98 | .clk, | |
.i_we (databank_we[g]), | 99 | 99 | .i_we (databank_we[g]), | |
.i_wdata(databank_wdata), | 100 | 100 | .i_wdata(databank_wdata), | |
.i_waddr(databank_waddr), | 101 | 101 | .i_waddr(databank_waddr), | |
.i_raddr(databank_raddr), | 102 | 102 | .i_raddr(databank_raddr), | |
103 | 103 | |||
.o_rdata(databank_rdata[g]) | 104 | 104 | .o_rdata(databank_rdata[g]) | |
); | 105 | 105 | ); | |
end | 106 | 106 | end | |
endgenerate | 107 | 107 | endgenerate | |
108 | 108 | |||
// tagbank signals | 109 | 109 | // tagbank signals | |
logic tagbank_we; | 110 | 110 | logic tagbank_we; | |
logic [TAG_WIDTH - 1 : 0] tagbank_wdata; | 111 | 111 | logic [TAG_WIDTH - 1 : 0] tagbank_wdata; | |
logic [INDEX_WIDTH - 1 : 0] tagbank_waddr; | 112 | 112 | logic [INDEX_WIDTH - 1 : 0] tagbank_waddr; | |
logic [INDEX_WIDTH - 1 : 0] tagbank_raddr; | 113 | 113 | logic [INDEX_WIDTH - 1 : 0] tagbank_raddr; | |
logic [TAG_WIDTH - 1 : 0] tagbank_rdata; | 114 | 114 | logic [TAG_WIDTH - 1 : 0] tagbank_rdata; | |
115 | 115 | |||
cache_bank #( | 116 | 116 | cache_bank #( | |
.DATA_WIDTH (TAG_WIDTH), | 117 | 117 | .DATA_WIDTH (TAG_WIDTH), | |
.ADDR_WIDTH (INDEX_WIDTH) | 118 | 118 | .ADDR_WIDTH (INDEX_WIDTH) | |
) tagbank ( | 119 | 119 | ) tagbank ( | |
.clk, | 120 | 120 | .clk, | |
.i_we (tagbank_we), | 121 | 121 | .i_we (tagbank_we), | |
.i_wdata (tagbank_wdata), | 122 | 122 | .i_wdata (tagbank_wdata), | |
.i_waddr (tagbank_waddr), | 123 | 123 | .i_waddr (tagbank_waddr), | |
.i_raddr (tagbank_raddr), | 124 | 124 | .i_raddr (tagbank_raddr), | |
125 | 125 | |||
.o_rdata (tagbank_rdata) | 126 | 126 | .o_rdata (tagbank_rdata) | |
); | 127 | 127 | ); | |
128 | 128 | |||
// Valid bits | 129 | 129 | // Valid bits | |
logic [DEPTH - 1 : 0] valid_bits; | 130 | 130 | logic [DEPTH - 1 : 0] valid_bits; | |
131 | 131 | |||
// Intermediate signals | 132 | 132 | // Intermediate signals | |
logic hit, miss; | 133 | 133 | logic hit, miss; | |
logic last_refill_word; | 134 | 134 | logic last_refill_word; | |
135 | 135 | |||
136 | 136 | |||
always_comb | 137 | 137 | always_comb | |
begin | 138 | 138 | begin | |
hit = valid_bits[i_index] | 139 | 139 | hit = valid_bits[i_index] | |
& (i_tag == tagbank_rdata) | 140 | 140 | & (i_tag == tagbank_rdata) | |
& (state == STATE_READY); | 141 | 141 | & (state == STATE_READY); | |
miss = ~hit; | 142 | 142 | miss = ~hit; | |
last_refill_word = databank_select[LINE_SIZE - 1] | 143 | 143 | last_refill_word = databank_select[LINE_SIZE - 1] | |
& mem_read_data.RVALID; | 144 | 144 | & mem_read_data.RVALID; | |
end | 145 | 145 | end | |
146 | 146 | |||
always_comb | 147 | 147 | always_comb | |
begin | 148 | 148 | begin | |
mem_read_address.ARADDR = {r_tag, r_index, | 149 | 149 | mem_read_address.ARADDR = {r_tag, r_index, | |
{BLOCK_OFFSET_WIDTH + 2{1'b0}}}; | 150 | 150 | {BLOCK_OFFSET_WIDTH + 2{1'b0}}}; | |
mem_read_address.ARLEN = LINE_SIZE; | 151 | 151 | mem_read_address.ARLEN = LINE_SIZE; | |
mem_read_address.ARVALID = state == STATE_REFILL_REQUEST; | 152 | 152 | mem_read_address.ARVALID = state == STATE_REFILL_REQUEST; | |
mem_read_address.ARID = 4'd0; | 153 | 153 | mem_read_address.ARID = 4'd0; | |
154 | 154 | |||
// Always ready to consume data | 155 | 155 | // Always ready to consume data | |
mem_read_data.RREADY = 1'b1; | 156 | 156 | mem_read_data.RREADY = 1'b1; | |
end | 157 | 157 | end | |
158 | 158 | |||
always_comb | 159 | 159 | always_comb | |
begin | 160 | 160 | begin | |
if (mem_read_data.RVALID) | 161 | 161 | if (mem_read_data.RVALID) | |
databank_we = databank_select; | 162 | 162 | databank_we = databank_select; | |
else | 163 | 163 | else | |
databank_we = '0; | 164 | 164 | databank_we = '0; | |
165 | 165 | |||
databank_wdata = mem_read_data.RDATA; | 166 | 166 | databank_wdata = mem_read_data.RDATA; | |
databank_waddr = r_index; | 167 | 167 | databank_waddr = r_index; | |
databank_raddr = i_index_next; | 168 | 168 | databank_raddr = i_index_next; | |
end | 169 | 169 | end | |
170 | 170 | |||
always_comb | 171 | 171 | always_comb | |
begin | 172 | 172 | begin | |
tagbank_we = last_refill_word; | 173 | 173 | tagbank_we = last_refill_word; | |
tagbank_wdata = r_tag; | 174 | 174 | tagbank_wdata = r_tag; | |
tagbank_waddr = r_index; | 175 | 175 | tagbank_waddr = r_index; | |
tagbank_raddr = i_index_next; | 176 | 176 | tagbank_raddr = i_index_next; | |
end | 177 | 177 | end | |
178 | 178 | |||
always_comb | 179 | 179 | always_comb | |
begin | 180 | 180 | begin | |
out.valid = hit; | 181 | 181 | out.valid = hit; | |
out.data = databank_rdata[i_block_offset]; | 182 | 182 | out.data = databank_rdata[i_block_offset]; | |
end | 183 | 183 | end | |
184 | 184 | |||
always_comb | 185 | 185 | always_comb | |
begin | 186 | 186 | begin | |
next_state = state; | 187 | 187 | next_state = state; | |
unique case (state) | 188 | 188 | unique case (state) | |
STATE_READY: | 189 | 189 | STATE_READY: | |
if (miss) | 190 | 190 | if (miss) | |
next_state = STATE_REFILL_REQUEST; | 191 | 191 | next_state = STATE_REFILL_REQUEST; | |
STATE_REFILL_REQUEST: | 192 | 192 | STATE_REFILL_REQUEST: | |
if (mem_read_address.ARREADY) | 193 | 193 | if (mem_read_address.ARREADY) | |
next_state = STATE_REFILL_DATA; | 194 | 194 | next_state = STATE_REFILL_DATA; | |
STATE_REFILL_DATA: | 195 | 195 | STATE_REFILL_DATA: | |
if (last_refill_word) | 196 | 196 | if (last_refill_word) | |
next_state = STATE_READY; | 197 | 197 | next_state = STATE_READY; | |
endcase | 198 | 198 | endcase | |
end | 199 | 199 | end | |
200 | 200 | |||
always_ff @(posedge clk) | 201 | 201 | always_ff @(posedge clk) | |
begin | 202 | 202 | begin | |
if(~rst_n) | 203 | 203 | if(~rst_n) | |
begin | 204 | 204 | begin | |
state <= STATE_READY; | 205 | 205 | state <= STATE_READY; | |
databank_select <= 1; | 206 | 206 | databank_select <= 1; | |
valid_bits <= '0; | 207 | 207 | valid_bits <= '0; | |
end | 208 | 208 | end | |
else | 209 | 209 | else |