Mon, 05 Apr 2010 21:00:31 +0100
reduce size of caches to fit in DE1 FPGA
The default cache size makes the Icache and Dcache "just a bit" too big to
fit in the EP2C20 FPGA on the DE1 board. This commit reduces the Icache and
Dcache sizes to the defaults shown in the LatticeMico32 Processor Reference
Manual (pages 36 and 37).
philpem@0 | 1 | // ============================================================================= |
philpem@0 | 2 | // COPYRIGHT NOTICE |
philpem@0 | 3 | // Copyright 2006 (c) Lattice Semiconductor Corporation |
philpem@0 | 4 | // ALL RIGHTS RESERVED |
philpem@0 | 5 | // This confidential and proprietary software may be used only as authorised by |
philpem@0 | 6 | // a licensing agreement from Lattice Semiconductor Corporation. |
philpem@0 | 7 | // The entire notice above must be reproduced on all authorized copies and |
philpem@0 | 8 | // copies may only be made to the extent permitted by a licensing agreement from |
philpem@0 | 9 | // Lattice Semiconductor Corporation. |
philpem@0 | 10 | // |
philpem@0 | 11 | // Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada) |
philpem@0 | 12 | // 5555 NE Moore Court 408-826-6000 (other locations) |
philpem@0 | 13 | // Hillsboro, OR 97124 web : http://www.latticesemi.com/ |
philpem@0 | 14 | // U.S.A email: techsupport@latticesemi.com |
philpem@0 | 15 | // =============================================================================/ |
philpem@0 | 16 | // FILE DETAILS |
philpem@0 | 17 | // Project : LatticeMico32 |
philpem@0 | 18 | // File : lm32_dcache.v |
philpem@0 | 19 | // Title : Data cache |
philpem@0 | 20 | // Dependencies : lm32_include.v |
philpem@0 | 21 | // Version : 6.1.17 |
philpem@0 | 22 | // : Initial Release |
philpem@0 | 23 | // Version : 7.0SP2, 3.0 |
philpem@0 | 24 | // : No Change |
philpem@0 | 25 | // Version : 3.1 |
philpem@0 | 26 | // : Support for user-selected resource usage when implementing |
philpem@0 | 27 | // : cache memory. Additional parameters must be defined when |
philpem@0 | 28 | // : invoking lm32_ram.v |
philpem@0 | 29 | // ============================================================================= |
philpem@0 | 30 | |
philpem@0 | 31 | `include "lm32_include.v" |
philpem@0 | 32 | |
philpem@0 | 33 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 34 | |
philpem@0 | 35 | `define LM32_DC_ADDR_OFFSET_RNG addr_offset_msb:addr_offset_lsb |
philpem@0 | 36 | `define LM32_DC_ADDR_SET_RNG addr_set_msb:addr_set_lsb |
philpem@0 | 37 | `define LM32_DC_ADDR_TAG_RNG addr_tag_msb:addr_tag_lsb |
philpem@0 | 38 | `define LM32_DC_ADDR_IDX_RNG addr_set_msb:addr_offset_lsb |
philpem@0 | 39 | |
philpem@0 | 40 | `define LM32_DC_TMEM_ADDR_WIDTH addr_set_width |
philpem@0 | 41 | `define LM32_DC_TMEM_ADDR_RNG (`LM32_DC_TMEM_ADDR_WIDTH-1):0 |
philpem@0 | 42 | `define LM32_DC_DMEM_ADDR_WIDTH (addr_offset_width+addr_set_width) |
philpem@0 | 43 | `define LM32_DC_DMEM_ADDR_RNG (`LM32_DC_DMEM_ADDR_WIDTH-1):0 |
philpem@0 | 44 | |
philpem@0 | 45 | `define LM32_DC_TAGS_WIDTH (addr_tag_width+1) |
philpem@0 | 46 | `define LM32_DC_TAGS_RNG (`LM32_DC_TAGS_WIDTH-1):0 |
philpem@0 | 47 | `define LM32_DC_TAGS_TAG_RNG (`LM32_DC_TAGS_WIDTH-1):1 |
philpem@0 | 48 | `define LM32_DC_TAGS_VALID_RNG 0 |
philpem@0 | 49 | |
philpem@0 | 50 | `define LM32_DC_STATE_RNG 2:0 |
philpem@0 | 51 | `define LM32_DC_STATE_FLUSH 3'b001 |
philpem@0 | 52 | `define LM32_DC_STATE_CHECK 3'b010 |
philpem@0 | 53 | `define LM32_DC_STATE_REFILL 3'b100 |
philpem@0 | 54 | |
philpem@0 | 55 | ///////////////////////////////////////////////////// |
philpem@0 | 56 | // Module interface |
philpem@0 | 57 | ///////////////////////////////////////////////////// |
philpem@0 | 58 | |
philpem@0 | 59 | module lm32_dcache ( |
philpem@0 | 60 | // ----- Inputs ----- |
philpem@0 | 61 | clk_i, |
philpem@0 | 62 | rst_i, |
philpem@0 | 63 | stall_a, |
philpem@0 | 64 | stall_x, |
philpem@0 | 65 | stall_m, |
philpem@0 | 66 | address_x, |
philpem@0 | 67 | address_m, |
philpem@0 | 68 | load_q_m, |
philpem@0 | 69 | store_q_m, |
philpem@0 | 70 | store_data, |
philpem@0 | 71 | store_byte_select, |
philpem@0 | 72 | refill_ready, |
philpem@0 | 73 | refill_data, |
philpem@0 | 74 | dflush, |
philpem@0 | 75 | // ----- Outputs ----- |
philpem@0 | 76 | stall_request, |
philpem@0 | 77 | restart_request, |
philpem@0 | 78 | refill_request, |
philpem@0 | 79 | refill_address, |
philpem@0 | 80 | refilling, |
philpem@0 | 81 | load_data |
philpem@0 | 82 | ); |
philpem@0 | 83 | |
philpem@0 | 84 | ///////////////////////////////////////////////////// |
philpem@0 | 85 | // Parameters |
philpem@0 | 86 | ///////////////////////////////////////////////////// |
philpem@0 | 87 | |
philpem@0 | 88 | parameter associativity = 1; // Associativity of the cache (Number of ways) |
philpem@0 | 89 | parameter sets = 512; // Number of sets |
philpem@0 | 90 | parameter bytes_per_line = 16; // Number of bytes per cache line |
philpem@0 | 91 | parameter base_address = 0; // Base address of cachable memory |
philpem@0 | 92 | parameter limit = 0; // Limit (highest address) of cachable memory |
philpem@0 | 93 | |
philpem@0 | 94 | localparam addr_offset_width = clogb2(bytes_per_line)-1-2; |
philpem@0 | 95 | localparam addr_set_width = clogb2(sets)-1; |
philpem@0 | 96 | localparam addr_offset_lsb = 2; |
philpem@0 | 97 | localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1); |
philpem@0 | 98 | localparam addr_set_lsb = (addr_offset_msb+1); |
philpem@0 | 99 | localparam addr_set_msb = (addr_set_lsb+addr_set_width-1); |
philpem@0 | 100 | localparam addr_tag_lsb = (addr_set_msb+1); |
philpem@0 | 101 | localparam addr_tag_msb = clogb2(`CFG_DCACHE_LIMIT-`CFG_DCACHE_BASE_ADDRESS)-1; |
philpem@0 | 102 | localparam addr_tag_width = (addr_tag_msb-addr_tag_lsb+1); |
philpem@0 | 103 | |
philpem@0 | 104 | ///////////////////////////////////////////////////// |
philpem@0 | 105 | // Inputs |
philpem@0 | 106 | ///////////////////////////////////////////////////// |
philpem@0 | 107 | |
philpem@0 | 108 | input clk_i; // Clock |
philpem@0 | 109 | input rst_i; // Reset |
philpem@0 | 110 | |
philpem@0 | 111 | input stall_a; // Stall A stage |
philpem@0 | 112 | input stall_x; // Stall X stage |
philpem@0 | 113 | input stall_m; // Stall M stage |
philpem@0 | 114 | |
philpem@0 | 115 | input [`LM32_WORD_RNG] address_x; // X stage load/store address |
philpem@0 | 116 | input [`LM32_WORD_RNG] address_m; // M stage load/store address |
philpem@0 | 117 | input load_q_m; // Load instruction in M stage |
philpem@0 | 118 | input store_q_m; // Store instruction in M stage |
philpem@0 | 119 | input [`LM32_WORD_RNG] store_data; // Data to store |
philpem@0 | 120 | input [`LM32_BYTE_SELECT_RNG] store_byte_select; // Which bytes in store data should be modified |
philpem@0 | 121 | |
philpem@0 | 122 | input refill_ready; // Indicates next word of refill data is ready |
philpem@0 | 123 | input [`LM32_WORD_RNG] refill_data; // Refill data |
philpem@0 | 124 | |
philpem@0 | 125 | input dflush; // Indicates cache should be flushed |
philpem@0 | 126 | |
philpem@0 | 127 | ///////////////////////////////////////////////////// |
philpem@0 | 128 | // Outputs |
philpem@0 | 129 | ///////////////////////////////////////////////////// |
philpem@0 | 130 | |
philpem@0 | 131 | output stall_request; // Request pipeline be stalled because cache is busy |
philpem@0 | 132 | wire stall_request; |
philpem@0 | 133 | output restart_request; // Request to restart instruction that caused the cache miss |
philpem@0 | 134 | reg restart_request; |
philpem@0 | 135 | output refill_request; // Request a refill |
philpem@0 | 136 | reg refill_request; |
philpem@0 | 137 | output [`LM32_WORD_RNG] refill_address; // Address to refill from |
philpem@0 | 138 | reg [`LM32_WORD_RNG] refill_address; |
philpem@0 | 139 | output refilling; // Indicates if the cache is currently refilling |
philpem@0 | 140 | reg refilling; |
philpem@0 | 141 | output [`LM32_WORD_RNG] load_data; // Data read from cache |
philpem@0 | 142 | wire [`LM32_WORD_RNG] load_data; |
philpem@0 | 143 | |
philpem@0 | 144 | ///////////////////////////////////////////////////// |
philpem@0 | 145 | // Internal nets and registers |
philpem@0 | 146 | ///////////////////////////////////////////////////// |
philpem@0 | 147 | |
philpem@0 | 148 | wire read_port_enable; // Cache memory read port clock enable |
philpem@0 | 149 | wire write_port_enable; // Cache memory write port clock enable |
philpem@0 | 150 | wire [0:associativity-1] way_tmem_we; // Tag memory write enable |
philpem@0 | 151 | wire [0:associativity-1] way_dmem_we; // Data memory write enable |
philpem@0 | 152 | wire [`LM32_WORD_RNG] way_data[0:associativity-1]; // Data read from data memory |
philpem@0 | 153 | wire [`LM32_DC_TAGS_TAG_RNG] way_tag[0:associativity-1];// Tag read from tag memory |
philpem@0 | 154 | wire [0:associativity-1] way_valid; // Indicates which ways are valid |
philpem@0 | 155 | wire [0:associativity-1] way_match; // Indicates which ways matched |
philpem@0 | 156 | wire miss; // Indicates no ways matched |
philpem@0 | 157 | |
philpem@0 | 158 | wire [`LM32_DC_TMEM_ADDR_RNG] tmem_read_address; // Tag memory read address |
philpem@0 | 159 | wire [`LM32_DC_TMEM_ADDR_RNG] tmem_write_address; // Tag memory write address |
philpem@0 | 160 | wire [`LM32_DC_DMEM_ADDR_RNG] dmem_read_address; // Data memory read address |
philpem@0 | 161 | wire [`LM32_DC_DMEM_ADDR_RNG] dmem_write_address; // Data memory write address |
philpem@0 | 162 | wire [`LM32_DC_TAGS_RNG] tmem_write_data; // Tag memory write data |
philpem@0 | 163 | reg [`LM32_WORD_RNG] dmem_write_data; // Data memory write data |
philpem@0 | 164 | |
philpem@0 | 165 | reg [`LM32_DC_STATE_RNG] state; // Current state of FSM |
philpem@0 | 166 | wire flushing; // Indicates if cache is currently flushing |
philpem@0 | 167 | wire check; // Indicates if cache is currently checking for hits/misses |
philpem@0 | 168 | wire refill; // Indicates if cache is currently refilling |
philpem@0 | 169 | |
philpem@0 | 170 | wire valid_store; // Indicates if there is a valid store instruction |
philpem@0 | 171 | reg [associativity-1:0] refill_way_select; // Which way should be refilled |
philpem@0 | 172 | reg [`LM32_DC_ADDR_OFFSET_RNG] refill_offset; // Which word in cache line should be refilled |
philpem@0 | 173 | wire last_refill; // Indicates when on last cycle of cache refill |
philpem@0 | 174 | reg [`LM32_DC_TMEM_ADDR_RNG] flush_set; // Which set is currently being flushed |
philpem@0 | 175 | |
philpem@0 | 176 | genvar i, j; |
philpem@0 | 177 | |
philpem@0 | 178 | ///////////////////////////////////////////////////// |
philpem@0 | 179 | // Functions |
philpem@0 | 180 | ///////////////////////////////////////////////////// |
philpem@0 | 181 | |
philpem@0 | 182 | `include "lm32_functions.v" |
philpem@0 | 183 | |
philpem@0 | 184 | ///////////////////////////////////////////////////// |
philpem@0 | 185 | // Instantiations |
philpem@0 | 186 | ///////////////////////////////////////////////////// |
philpem@0 | 187 | |
philpem@0 | 188 | generate |
philpem@0 | 189 | for (i = 0; i < associativity; i = i + 1) |
philpem@0 | 190 | begin : memories |
philpem@0 | 191 | // Way data |
philpem@0 | 192 | if (`LM32_DC_DMEM_ADDR_WIDTH < 11) |
philpem@0 | 193 | begin : data_memories |
philpem@0 | 194 | lm32_ram |
philpem@0 | 195 | #( |
philpem@0 | 196 | // ----- Parameters ------- |
philpem@0 | 197 | .data_width (32), |
philpem@3 | 198 | .address_width (`LM32_DC_DMEM_ADDR_WIDTH) |
philpem@2 | 199 | `ifdef PLATFORM_LATTICE |
philpem@3 | 200 | , |
philpem@2 | 201 | `ifdef CFG_DCACHE_DAT_USE_DP_TRUE |
philpem@0 | 202 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 203 | .RAM_TYPE ("RAM_DP_TRUE") |
philpem@2 | 204 | `else |
philpem@2 | 205 | `ifdef CFG_DCACHE_DAT_USE_SLICE |
philpem@0 | 206 | .RAM_IMPLEMENTATION ("SLICE") |
philpem@2 | 207 | `else |
philpem@0 | 208 | .RAM_IMPLEMENTATION ("AUTO") |
philpem@2 | 209 | `endif |
philpem@0 | 210 | `endif |
philpem@0 | 211 | `endif |
philpem@0 | 212 | ) way_0_data_ram |
philpem@0 | 213 | ( |
philpem@0 | 214 | // ----- Inputs ------- |
philpem@0 | 215 | .read_clk (clk_i), |
philpem@0 | 216 | .write_clk (clk_i), |
philpem@0 | 217 | .reset (rst_i), |
philpem@0 | 218 | .read_address (dmem_read_address), |
philpem@0 | 219 | .enable_read (read_port_enable), |
philpem@0 | 220 | .write_address (dmem_write_address), |
philpem@0 | 221 | .enable_write (write_port_enable), |
philpem@0 | 222 | .write_enable (way_dmem_we[i]), |
philpem@0 | 223 | .write_data (dmem_write_data), |
philpem@0 | 224 | // ----- Outputs ------- |
philpem@0 | 225 | .read_data (way_data[i]) |
philpem@0 | 226 | ); |
philpem@0 | 227 | end |
philpem@0 | 228 | else |
philpem@0 | 229 | begin |
philpem@0 | 230 | for (j = 0; j < 4; j = j + 1) |
philpem@0 | 231 | begin : byte_memories |
philpem@0 | 232 | lm32_ram |
philpem@0 | 233 | #( |
philpem@0 | 234 | // ----- Parameters ------- |
philpem@0 | 235 | .data_width (8), |
philpem@3 | 236 | .address_width (`LM32_DC_DMEM_ADDR_WIDTH) |
philpem@3 | 237 | `ifdef PLATFORM_LATTICE |
philpem@3 | 238 | , |
philpem@3 | 239 | `ifdef CFG_DCACHE_DAT_USE_DP_TRUE |
philpem@0 | 240 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 241 | .RAM_TYPE ("RAM_DP_TRUE") |
philpem@3 | 242 | `else |
philpem@3 | 243 | `ifdef CFG_DCACHE_DAT_USE_SLICE |
philpem@0 | 244 | .RAM_IMPLEMENTATION ("SLICE") |
philpem@3 | 245 | `else |
philpem@0 | 246 | .RAM_IMPLEMENTATION ("AUTO") |
philpem@3 | 247 | `endif |
philpem@0 | 248 | `endif |
philpem@0 | 249 | `endif |
philpem@0 | 250 | ) way_0_data_ram |
philpem@0 | 251 | ( |
philpem@0 | 252 | // ----- Inputs ------- |
philpem@0 | 253 | .read_clk (clk_i), |
philpem@0 | 254 | .write_clk (clk_i), |
philpem@0 | 255 | .reset (rst_i), |
philpem@0 | 256 | .read_address (dmem_read_address), |
philpem@0 | 257 | .enable_read (read_port_enable), |
philpem@0 | 258 | .write_address (dmem_write_address), |
philpem@0 | 259 | .enable_write (write_port_enable), |
philpem@0 | 260 | .write_enable (way_dmem_we[i] & (store_byte_select[j] | refill)), |
philpem@0 | 261 | .write_data (dmem_write_data[(j+1)*8-1:j*8]), |
philpem@0 | 262 | // ----- Outputs ------- |
philpem@0 | 263 | .read_data (way_data[i][(j+1)*8-1:j*8]) |
philpem@0 | 264 | ); |
philpem@0 | 265 | end |
philpem@0 | 266 | end |
philpem@0 | 267 | |
philpem@0 | 268 | // Way tags |
philpem@0 | 269 | lm32_ram |
philpem@0 | 270 | #( |
philpem@0 | 271 | // ----- Parameters ------- |
philpem@0 | 272 | .data_width (`LM32_DC_TAGS_WIDTH), |
philpem@3 | 273 | .address_width (`LM32_DC_TMEM_ADDR_WIDTH) |
philpem@3 | 274 | `ifdef PLATFORM_LATTICE |
philpem@3 | 275 | , |
philpem@3 | 276 | `ifdef CFG_DCACHE_DAT_USE_DP_TRUE |
philpem@0 | 277 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 278 | .RAM_TYPE ("RAM_DP_TRUE") |
philpem@3 | 279 | `else |
philpem@3 | 280 | `ifdef CFG_DCACHE_DAT_USE_SLICE |
philpem@0 | 281 | .RAM_IMPLEMENTATION ("SLICE") |
philpem@3 | 282 | `else |
philpem@0 | 283 | .RAM_IMPLEMENTATION ("AUTO") |
philpem@3 | 284 | `endif |
philpem@0 | 285 | `endif |
philpem@0 | 286 | `endif |
philpem@0 | 287 | ) way_0_tag_ram |
philpem@0 | 288 | ( |
philpem@0 | 289 | // ----- Inputs ------- |
philpem@0 | 290 | .read_clk (clk_i), |
philpem@0 | 291 | .write_clk (clk_i), |
philpem@0 | 292 | .reset (rst_i), |
philpem@0 | 293 | .read_address (tmem_read_address), |
philpem@0 | 294 | .enable_read (read_port_enable), |
philpem@0 | 295 | .write_address (tmem_write_address), |
philpem@0 | 296 | .enable_write (`TRUE), |
philpem@0 | 297 | .write_enable (way_tmem_we[i]), |
philpem@0 | 298 | .write_data (tmem_write_data), |
philpem@0 | 299 | // ----- Outputs ------- |
philpem@0 | 300 | .read_data ({way_tag[i], way_valid[i]}) |
philpem@0 | 301 | ); |
philpem@0 | 302 | end |
philpem@0 | 303 | |
philpem@0 | 304 | endgenerate |
philpem@0 | 305 | |
philpem@0 | 306 | ///////////////////////////////////////////////////// |
philpem@0 | 307 | // Combinational logic |
philpem@0 | 308 | ///////////////////////////////////////////////////// |
philpem@0 | 309 | |
philpem@0 | 310 | // Compute which ways in the cache match the address being read |
philpem@0 | 311 | generate |
philpem@0 | 312 | for (i = 0; i < associativity; i = i + 1) |
philpem@0 | 313 | begin : match |
philpem@0 | 314 | assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE}); |
philpem@0 | 315 | end |
philpem@0 | 316 | endgenerate |
philpem@0 | 317 | |
philpem@0 | 318 | // Select data from way that matched the address being read |
philpem@0 | 319 | generate |
philpem@0 | 320 | if (associativity == 1) |
philpem@0 | 321 | begin : data_1 |
philpem@0 | 322 | assign load_data = way_data[0]; |
philpem@0 | 323 | end |
philpem@0 | 324 | else if (associativity == 2) |
philpem@0 | 325 | begin : data_2 |
philpem@0 | 326 | assign load_data = way_match[0] ? way_data[0] : way_data[1]; |
philpem@0 | 327 | end |
philpem@0 | 328 | endgenerate |
philpem@0 | 329 | |
philpem@0 | 330 | generate |
philpem@0 | 331 | if (`LM32_DC_DMEM_ADDR_WIDTH < 11) |
philpem@0 | 332 | begin |
philpem@0 | 333 | // Select data to write to data memories |
philpem@0 | 334 | always @(*) |
philpem@0 | 335 | begin |
philpem@0 | 336 | if (refill == `TRUE) |
philpem@0 | 337 | dmem_write_data = refill_data; |
philpem@0 | 338 | else |
philpem@0 | 339 | begin |
philpem@0 | 340 | dmem_write_data[`LM32_BYTE_0_RNG] = store_byte_select[0] ? store_data[`LM32_BYTE_0_RNG] : load_data[`LM32_BYTE_0_RNG]; |
philpem@0 | 341 | dmem_write_data[`LM32_BYTE_1_RNG] = store_byte_select[1] ? store_data[`LM32_BYTE_1_RNG] : load_data[`LM32_BYTE_1_RNG]; |
philpem@0 | 342 | dmem_write_data[`LM32_BYTE_2_RNG] = store_byte_select[2] ? store_data[`LM32_BYTE_2_RNG] : load_data[`LM32_BYTE_2_RNG]; |
philpem@0 | 343 | dmem_write_data[`LM32_BYTE_3_RNG] = store_byte_select[3] ? store_data[`LM32_BYTE_3_RNG] : load_data[`LM32_BYTE_3_RNG]; |
philpem@0 | 344 | end |
philpem@0 | 345 | end |
philpem@0 | 346 | end |
philpem@0 | 347 | else |
philpem@0 | 348 | begin |
philpem@0 | 349 | // Select data to write to data memories - FIXME: Should use different write ports on dual port RAMs, but they don't work |
philpem@0 | 350 | always @(*) |
philpem@0 | 351 | begin |
philpem@0 | 352 | if (refill == `TRUE) |
philpem@0 | 353 | dmem_write_data = refill_data; |
philpem@0 | 354 | else |
philpem@0 | 355 | dmem_write_data = store_data; |
philpem@0 | 356 | end |
philpem@0 | 357 | end |
philpem@0 | 358 | endgenerate |
philpem@0 | 359 | |
philpem@0 | 360 | // Compute address to use to index into the data memories |
philpem@0 | 361 | generate |
philpem@0 | 362 | if (bytes_per_line > 4) |
philpem@0 | 363 | assign dmem_write_address = (refill == `TRUE) |
philpem@0 | 364 | ? {refill_address[`LM32_DC_ADDR_SET_RNG], refill_offset} |
philpem@0 | 365 | : address_m[`LM32_DC_ADDR_IDX_RNG]; |
philpem@0 | 366 | else |
philpem@0 | 367 | assign dmem_write_address = (refill == `TRUE) |
philpem@0 | 368 | ? refill_address[`LM32_DC_ADDR_SET_RNG] |
philpem@0 | 369 | : address_m[`LM32_DC_ADDR_IDX_RNG]; |
philpem@0 | 370 | endgenerate |
philpem@0 | 371 | assign dmem_read_address = address_x[`LM32_DC_ADDR_IDX_RNG]; |
philpem@0 | 372 | // Compute address to use to index into the tag memories |
philpem@0 | 373 | assign tmem_write_address = (flushing == `TRUE) |
philpem@0 | 374 | ? flush_set |
philpem@0 | 375 | : refill_address[`LM32_DC_ADDR_SET_RNG]; |
philpem@0 | 376 | assign tmem_read_address = address_x[`LM32_DC_ADDR_SET_RNG]; |
philpem@0 | 377 | |
philpem@0 | 378 | // Compute signal to indicate when we are on the last refill accesses |
philpem@0 | 379 | generate |
philpem@0 | 380 | if (bytes_per_line > 4) |
philpem@0 | 381 | assign last_refill = refill_offset == {addr_offset_width{1'b1}}; |
philpem@0 | 382 | else |
philpem@0 | 383 | assign last_refill = `TRUE; |
philpem@0 | 384 | endgenerate |
philpem@0 | 385 | |
philpem@0 | 386 | // Compute data and tag memory access enable |
philpem@0 | 387 | assign read_port_enable = (stall_x == `FALSE); |
philpem@0 | 388 | assign write_port_enable = (refill_ready == `TRUE) || !stall_m; |
philpem@0 | 389 | |
philpem@0 | 390 | // Determine when we have a valid store |
philpem@0 | 391 | assign valid_store = (store_q_m == `TRUE) && (check == `TRUE); |
philpem@0 | 392 | |
philpem@0 | 393 | // Compute data and tag memory write enables |
philpem@0 | 394 | generate |
philpem@0 | 395 | if (associativity == 1) |
philpem@0 | 396 | begin : we_1 |
philpem@0 | 397 | assign way_dmem_we[0] = (refill_ready == `TRUE) || ((valid_store == `TRUE) && (way_match[0] == `TRUE)); |
philpem@0 | 398 | assign way_tmem_we[0] = (refill_ready == `TRUE) || (flushing == `TRUE); |
philpem@0 | 399 | end |
philpem@0 | 400 | else |
philpem@0 | 401 | begin : we_2 |
philpem@0 | 402 | assign way_dmem_we[0] = ((refill_ready == `TRUE) && (refill_way_select[0] == `TRUE)) || ((valid_store == `TRUE) && (way_match[0] == `TRUE)); |
philpem@0 | 403 | assign way_dmem_we[1] = ((refill_ready == `TRUE) && (refill_way_select[1] == `TRUE)) || ((valid_store == `TRUE) && (way_match[1] == `TRUE)); |
philpem@0 | 404 | assign way_tmem_we[0] = ((refill_ready == `TRUE) && (refill_way_select[0] == `TRUE)) || (flushing == `TRUE); |
philpem@0 | 405 | assign way_tmem_we[1] = ((refill_ready == `TRUE) && (refill_way_select[1] == `TRUE)) || (flushing == `TRUE); |
philpem@0 | 406 | end |
philpem@0 | 407 | endgenerate |
philpem@0 | 408 | |
philpem@0 | 409 | // On the last refill cycle set the valid bit, for all other writes it should be cleared |
philpem@0 | 410 | assign tmem_write_data[`LM32_DC_TAGS_VALID_RNG] = ((last_refill == `TRUE) || (valid_store == `TRUE)) && (flushing == `FALSE); |
philpem@0 | 411 | assign tmem_write_data[`LM32_DC_TAGS_TAG_RNG] = refill_address[`LM32_DC_ADDR_TAG_RNG]; |
philpem@0 | 412 | |
philpem@0 | 413 | // Signals that indicate which state we are in |
philpem@0 | 414 | assign flushing = state[0]; |
philpem@0 | 415 | assign check = state[1]; |
philpem@0 | 416 | assign refill = state[2]; |
philpem@0 | 417 | |
philpem@0 | 418 | assign miss = (~(|way_match)) && (load_q_m == `TRUE) && (stall_m == `FALSE); |
philpem@0 | 419 | assign stall_request = (check == `FALSE); |
philpem@0 | 420 | |
philpem@0 | 421 | ///////////////////////////////////////////////////// |
philpem@0 | 422 | // Sequential logic |
philpem@0 | 423 | ///////////////////////////////////////////////////// |
philpem@0 | 424 | |
philpem@0 | 425 | // Record way selected for replacement on a cache miss |
philpem@0 | 426 | generate |
philpem@0 | 427 | if (associativity >= 2) |
philpem@0 | 428 | begin : way_select |
philpem@0 | 429 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 430 | begin |
philpem@0 | 431 | if (rst_i == `TRUE) |
philpem@0 | 432 | refill_way_select <= {{associativity-1{1'b0}}, 1'b1}; |
philpem@0 | 433 | else |
philpem@0 | 434 | begin |
philpem@0 | 435 | if (refill_request == `TRUE) |
philpem@0 | 436 | refill_way_select <= {refill_way_select[0], refill_way_select[1]}; |
philpem@0 | 437 | end |
philpem@0 | 438 | end |
philpem@0 | 439 | end |
philpem@0 | 440 | endgenerate |
philpem@0 | 441 | |
philpem@0 | 442 | // Record whether we are currently refilling |
philpem@0 | 443 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 444 | begin |
philpem@0 | 445 | if (rst_i == `TRUE) |
philpem@0 | 446 | refilling <= `FALSE; |
philpem@0 | 447 | else |
philpem@0 | 448 | refilling <= refill; |
philpem@0 | 449 | end |
philpem@0 | 450 | |
philpem@0 | 451 | // Instruction cache control FSM |
philpem@0 | 452 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 453 | begin |
philpem@0 | 454 | if (rst_i == `TRUE) |
philpem@0 | 455 | begin |
philpem@0 | 456 | state <= `LM32_DC_STATE_FLUSH; |
philpem@0 | 457 | flush_set <= {`LM32_DC_TMEM_ADDR_WIDTH{1'b1}}; |
philpem@0 | 458 | refill_request <= `FALSE; |
philpem@0 | 459 | refill_address <= {`LM32_WORD_WIDTH{1'bx}}; |
philpem@0 | 460 | restart_request <= `FALSE; |
philpem@0 | 461 | end |
philpem@0 | 462 | else |
philpem@0 | 463 | begin |
philpem@0 | 464 | case (state) |
philpem@0 | 465 | |
philpem@0 | 466 | // Flush the cache |
philpem@0 | 467 | `LM32_DC_STATE_FLUSH: |
philpem@0 | 468 | begin |
philpem@0 | 469 | if (flush_set == {`LM32_DC_TMEM_ADDR_WIDTH{1'b0}}) |
philpem@0 | 470 | state <= `LM32_DC_STATE_CHECK; |
philpem@0 | 471 | flush_set <= flush_set - 1'b1; |
philpem@0 | 472 | end |
philpem@0 | 473 | |
philpem@0 | 474 | // Check for cache misses |
philpem@0 | 475 | `LM32_DC_STATE_CHECK: |
philpem@0 | 476 | begin |
philpem@0 | 477 | if (stall_a == `FALSE) |
philpem@0 | 478 | restart_request <= `FALSE; |
philpem@0 | 479 | if (miss == `TRUE) |
philpem@0 | 480 | begin |
philpem@0 | 481 | refill_request <= `TRUE; |
philpem@0 | 482 | refill_address <= address_m; |
philpem@0 | 483 | state <= `LM32_DC_STATE_REFILL; |
philpem@0 | 484 | end |
philpem@0 | 485 | else if (dflush == `TRUE) |
philpem@0 | 486 | state <= `LM32_DC_STATE_FLUSH; |
philpem@0 | 487 | end |
philpem@0 | 488 | |
philpem@0 | 489 | // Refill a cache line |
philpem@0 | 490 | `LM32_DC_STATE_REFILL: |
philpem@0 | 491 | begin |
philpem@0 | 492 | refill_request <= `FALSE; |
philpem@0 | 493 | if (refill_ready == `TRUE) |
philpem@0 | 494 | begin |
philpem@0 | 495 | if (last_refill == `TRUE) |
philpem@0 | 496 | begin |
philpem@0 | 497 | restart_request <= `TRUE; |
philpem@0 | 498 | state <= `LM32_DC_STATE_CHECK; |
philpem@0 | 499 | end |
philpem@0 | 500 | end |
philpem@0 | 501 | end |
philpem@0 | 502 | |
philpem@0 | 503 | endcase |
philpem@0 | 504 | end |
philpem@0 | 505 | end |
philpem@0 | 506 | |
philpem@0 | 507 | generate |
philpem@0 | 508 | if (bytes_per_line > 4) |
philpem@0 | 509 | begin |
philpem@0 | 510 | // Refill offset |
philpem@0 | 511 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 512 | begin |
philpem@0 | 513 | if (rst_i == `TRUE) |
philpem@0 | 514 | refill_offset <= {addr_offset_width{1'b0}}; |
philpem@0 | 515 | else |
philpem@0 | 516 | begin |
philpem@0 | 517 | case (state) |
philpem@0 | 518 | |
philpem@0 | 519 | // Check for cache misses |
philpem@0 | 520 | `LM32_DC_STATE_CHECK: |
philpem@0 | 521 | begin |
philpem@0 | 522 | if (miss == `TRUE) |
philpem@0 | 523 | refill_offset <= {addr_offset_width{1'b0}}; |
philpem@0 | 524 | end |
philpem@0 | 525 | |
philpem@0 | 526 | // Refill a cache line |
philpem@0 | 527 | `LM32_DC_STATE_REFILL: |
philpem@0 | 528 | begin |
philpem@0 | 529 | if (refill_ready == `TRUE) |
philpem@0 | 530 | refill_offset <= refill_offset + 1'b1; |
philpem@0 | 531 | end |
philpem@0 | 532 | |
philpem@0 | 533 | endcase |
philpem@0 | 534 | end |
philpem@0 | 535 | end |
philpem@0 | 536 | end |
philpem@0 | 537 | endgenerate |
philpem@0 | 538 | |
philpem@0 | 539 | endmodule |
philpem@0 | 540 | |
philpem@0 | 541 | `endif |
philpem@0 | 542 |