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_icache.v |
philpem@0 | 19 | // Title : Instruction cache |
philpem@0 | 20 | // Dependencies : lm32_include.v |
philpem@0 | 21 | // |
philpem@0 | 22 | // Version 3.5 |
philpem@0 | 23 | // 1. Bug Fix: Instruction cache flushes issued from Instruction Inline Memory |
philpem@0 | 24 | // cause segmentation fault due to incorrect fetches. |
philpem@0 | 25 | // |
philpem@0 | 26 | // Version 3.1 |
philpem@0 | 27 | // 1. Feature: Support for user-selected resource usage when implementing |
philpem@0 | 28 | // cache memory. Additional parameters must be defined when invoking module |
philpem@0 | 29 | // lm32_ram. Instruction cache miss mechanism is dependent on branch |
philpem@0 | 30 | // prediction being performed in D stage of pipeline. |
philpem@0 | 31 | // |
philpem@0 | 32 | // Version 7.0SP2, 3.0 |
philpem@0 | 33 | // No change |
philpem@0 | 34 | // ============================================================================= |
philpem@0 | 35 | |
philpem@0 | 36 | `include "lm32_include.v" |
philpem@0 | 37 | |
philpem@0 | 38 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 39 | |
philpem@0 | 40 | `define LM32_IC_ADDR_OFFSET_RNG addr_offset_msb:addr_offset_lsb |
philpem@0 | 41 | `define LM32_IC_ADDR_SET_RNG addr_set_msb:addr_set_lsb |
philpem@0 | 42 | `define LM32_IC_ADDR_TAG_RNG addr_tag_msb:addr_tag_lsb |
philpem@0 | 43 | `define LM32_IC_ADDR_IDX_RNG addr_set_msb:addr_offset_lsb |
philpem@0 | 44 | |
philpem@0 | 45 | `define LM32_IC_TMEM_ADDR_WIDTH addr_set_width |
philpem@0 | 46 | `define LM32_IC_TMEM_ADDR_RNG (`LM32_IC_TMEM_ADDR_WIDTH-1):0 |
philpem@0 | 47 | `define LM32_IC_DMEM_ADDR_WIDTH (addr_offset_width+addr_set_width) |
philpem@0 | 48 | `define LM32_IC_DMEM_ADDR_RNG (`LM32_IC_DMEM_ADDR_WIDTH-1):0 |
philpem@0 | 49 | |
philpem@0 | 50 | `define LM32_IC_TAGS_WIDTH (addr_tag_width+1) |
philpem@0 | 51 | `define LM32_IC_TAGS_RNG (`LM32_IC_TAGS_WIDTH-1):0 |
philpem@0 | 52 | `define LM32_IC_TAGS_TAG_RNG (`LM32_IC_TAGS_WIDTH-1):1 |
philpem@0 | 53 | `define LM32_IC_TAGS_VALID_RNG 0 |
philpem@0 | 54 | |
philpem@0 | 55 | `define LM32_IC_STATE_RNG 3:0 |
philpem@0 | 56 | `define LM32_IC_STATE_FLUSH_INIT 4'b0001 |
philpem@0 | 57 | `define LM32_IC_STATE_FLUSH 4'b0010 |
philpem@0 | 58 | `define LM32_IC_STATE_CHECK 4'b0100 |
philpem@0 | 59 | `define LM32_IC_STATE_REFILL 4'b1000 |
philpem@0 | 60 | |
philpem@0 | 61 | ///////////////////////////////////////////////////// |
philpem@0 | 62 | // Module interface |
philpem@0 | 63 | ///////////////////////////////////////////////////// |
philpem@0 | 64 | |
philpem@0 | 65 | module lm32_icache ( |
philpem@0 | 66 | // ----- Inputs ----- |
philpem@0 | 67 | clk_i, |
philpem@0 | 68 | rst_i, |
philpem@0 | 69 | stall_a, |
philpem@0 | 70 | stall_f, |
philpem@0 | 71 | address_a, |
philpem@0 | 72 | address_f, |
philpem@0 | 73 | read_enable_f, |
philpem@0 | 74 | refill_ready, |
philpem@0 | 75 | refill_data, |
philpem@0 | 76 | iflush, |
philpem@0 | 77 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 78 | select_f, |
philpem@0 | 79 | `endif |
philpem@0 | 80 | valid_d, |
philpem@0 | 81 | branch_predict_taken_d, |
philpem@0 | 82 | // ----- Outputs ----- |
philpem@0 | 83 | stall_request, |
philpem@0 | 84 | restart_request, |
philpem@0 | 85 | refill_request, |
philpem@0 | 86 | refill_address, |
philpem@0 | 87 | refilling, |
philpem@0 | 88 | inst |
philpem@0 | 89 | ); |
philpem@0 | 90 | |
philpem@0 | 91 | ///////////////////////////////////////////////////// |
philpem@0 | 92 | // Parameters |
philpem@0 | 93 | ///////////////////////////////////////////////////// |
philpem@0 | 94 | |
philpem@0 | 95 | parameter associativity = 1; // Associativity of the cache (Number of ways) |
philpem@0 | 96 | parameter sets = 512; // Number of sets |
philpem@0 | 97 | parameter bytes_per_line = 16; // Number of bytes per cache line |
philpem@0 | 98 | parameter base_address = 0; // Base address of cachable memory |
philpem@0 | 99 | parameter limit = 0; // Limit (highest address) of cachable memory |
philpem@0 | 100 | |
philpem@0 | 101 | localparam addr_offset_width = clogb2(bytes_per_line)-1-2; |
philpem@0 | 102 | localparam addr_set_width = clogb2(sets)-1; |
philpem@0 | 103 | localparam addr_offset_lsb = 2; |
philpem@0 | 104 | localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1); |
philpem@0 | 105 | localparam addr_set_lsb = (addr_offset_msb+1); |
philpem@0 | 106 | localparam addr_set_msb = (addr_set_lsb+addr_set_width-1); |
philpem@0 | 107 | localparam addr_tag_lsb = (addr_set_msb+1); |
philpem@0 | 108 | localparam addr_tag_msb = clogb2(`CFG_ICACHE_LIMIT-`CFG_ICACHE_BASE_ADDRESS)-1; |
philpem@0 | 109 | localparam addr_tag_width = (addr_tag_msb-addr_tag_lsb+1); |
philpem@0 | 110 | |
philpem@0 | 111 | ///////////////////////////////////////////////////// |
philpem@0 | 112 | // Inputs |
philpem@0 | 113 | ///////////////////////////////////////////////////// |
philpem@0 | 114 | |
philpem@0 | 115 | input clk_i; // Clock |
philpem@0 | 116 | input rst_i; // Reset |
philpem@0 | 117 | |
philpem@0 | 118 | input stall_a; // Stall instruction in A stage |
philpem@0 | 119 | input stall_f; // Stall instruction in F stage |
philpem@0 | 120 | |
philpem@0 | 121 | input valid_d; // Valid instruction in D stage |
philpem@0 | 122 | input branch_predict_taken_d; // Instruction in D stage is a branch and is predicted taken |
philpem@0 | 123 | |
philpem@0 | 124 | input [`LM32_PC_RNG] address_a; // Address of instruction in A stage |
philpem@0 | 125 | input [`LM32_PC_RNG] address_f; // Address of instruction in F stage |
philpem@0 | 126 | input read_enable_f; // Indicates if cache access is valid |
philpem@0 | 127 | |
philpem@0 | 128 | input refill_ready; // Next word of refill data is ready |
philpem@0 | 129 | input [`LM32_INSTRUCTION_RNG] refill_data; // Data to refill the cache with |
philpem@0 | 130 | |
philpem@0 | 131 | input iflush; // Flush the cache |
philpem@0 | 132 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 133 | input select_f; // Instruction in F stage is mapped through instruction cache |
philpem@0 | 134 | `endif |
philpem@0 | 135 | |
philpem@0 | 136 | ///////////////////////////////////////////////////// |
philpem@0 | 137 | // Outputs |
philpem@0 | 138 | ///////////////////////////////////////////////////// |
philpem@0 | 139 | |
philpem@0 | 140 | output stall_request; // Request to stall the pipeline |
philpem@0 | 141 | wire stall_request; |
philpem@0 | 142 | output restart_request; // Request to restart instruction that caused the cache miss |
philpem@0 | 143 | reg restart_request; |
philpem@0 | 144 | output refill_request; // Request to refill a cache line |
philpem@0 | 145 | wire refill_request; |
philpem@0 | 146 | output [`LM32_PC_RNG] refill_address; // Base address of cache refill |
philpem@0 | 147 | reg [`LM32_PC_RNG] refill_address; |
philpem@0 | 148 | output refilling; // Indicates the instruction cache is currently refilling |
philpem@0 | 149 | reg refilling; |
philpem@0 | 150 | output [`LM32_INSTRUCTION_RNG] inst; // Instruction read from cache |
philpem@0 | 151 | wire [`LM32_INSTRUCTION_RNG] inst; |
philpem@0 | 152 | |
philpem@0 | 153 | ///////////////////////////////////////////////////// |
philpem@0 | 154 | // Internal nets and registers |
philpem@0 | 155 | ///////////////////////////////////////////////////// |
philpem@0 | 156 | |
philpem@0 | 157 | wire enable; |
philpem@0 | 158 | wire [0:associativity-1] way_mem_we; |
philpem@0 | 159 | wire [`LM32_INSTRUCTION_RNG] way_data[0:associativity-1]; |
philpem@0 | 160 | wire [`LM32_IC_TAGS_TAG_RNG] way_tag[0:associativity-1]; |
philpem@0 | 161 | wire [0:associativity-1] way_valid; |
philpem@0 | 162 | wire [0:associativity-1] way_match; |
philpem@0 | 163 | wire miss; |
philpem@0 | 164 | |
philpem@0 | 165 | wire [`LM32_IC_TMEM_ADDR_RNG] tmem_read_address; |
philpem@0 | 166 | wire [`LM32_IC_TMEM_ADDR_RNG] tmem_write_address; |
philpem@0 | 167 | wire [`LM32_IC_DMEM_ADDR_RNG] dmem_read_address; |
philpem@0 | 168 | wire [`LM32_IC_DMEM_ADDR_RNG] dmem_write_address; |
philpem@0 | 169 | wire [`LM32_IC_TAGS_RNG] tmem_write_data; |
philpem@0 | 170 | |
philpem@0 | 171 | reg [`LM32_IC_STATE_RNG] state; |
philpem@0 | 172 | wire flushing; |
philpem@0 | 173 | wire check; |
philpem@0 | 174 | wire refill; |
philpem@0 | 175 | |
philpem@0 | 176 | reg [associativity-1:0] refill_way_select; |
philpem@0 | 177 | reg [`LM32_IC_ADDR_OFFSET_RNG] refill_offset; |
philpem@0 | 178 | wire last_refill; |
philpem@0 | 179 | reg [`LM32_IC_TMEM_ADDR_RNG] flush_set; |
philpem@0 | 180 | |
philpem@0 | 181 | genvar i; |
philpem@0 | 182 | |
philpem@0 | 183 | ///////////////////////////////////////////////////// |
philpem@0 | 184 | // Functions |
philpem@0 | 185 | ///////////////////////////////////////////////////// |
philpem@0 | 186 | |
philpem@0 | 187 | `include "lm32_functions.v" |
philpem@0 | 188 | |
philpem@0 | 189 | ///////////////////////////////////////////////////// |
philpem@0 | 190 | // Instantiations |
philpem@0 | 191 | ///////////////////////////////////////////////////// |
philpem@0 | 192 | |
philpem@0 | 193 | generate |
philpem@0 | 194 | for (i = 0; i < associativity; i = i + 1) |
philpem@0 | 195 | begin : memories |
philpem@0 | 196 | |
philpem@0 | 197 | lm32_ram |
philpem@0 | 198 | #( |
philpem@0 | 199 | // ----- Parameters ------- |
philpem@0 | 200 | .data_width (32), |
philpem@3 | 201 | .address_width (`LM32_IC_DMEM_ADDR_WIDTH) |
philpem@2 | 202 | `ifdef PLATFORM_LATTICE |
philpem@3 | 203 | , |
philpem@2 | 204 | `ifdef CFG_ICACHE_DAT_USE_DP_TRUE |
philpem@0 | 205 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 206 | .RAM_TYPE ("RAM_DP_TRUE") |
philpem@2 | 207 | `else |
philpem@2 | 208 | `ifdef CFG_ICACHE_DAT_USE_DP |
philpem@0 | 209 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 210 | .RAM_TYPE ("RAM_DP") |
philpem@2 | 211 | `else |
philpem@2 | 212 | `ifdef CFG_ICACHE_DAT_USE_SLICE |
philpem@0 | 213 | .RAM_IMPLEMENTATION ("SLICE") |
philpem@2 | 214 | `else |
philpem@0 | 215 | .RAM_IMPLEMENTATION ("AUTO") |
philpem@2 | 216 | `endif |
philpem@0 | 217 | `endif |
philpem@0 | 218 | `endif |
philpem@0 | 219 | `endif |
philpem@0 | 220 | ) |
philpem@0 | 221 | way_0_data_ram |
philpem@0 | 222 | ( |
philpem@0 | 223 | // ----- Inputs ------- |
philpem@0 | 224 | .read_clk (clk_i), |
philpem@0 | 225 | .write_clk (clk_i), |
philpem@0 | 226 | .reset (rst_i), |
philpem@0 | 227 | .read_address (dmem_read_address), |
philpem@0 | 228 | .enable_read (enable), |
philpem@0 | 229 | .write_address (dmem_write_address), |
philpem@0 | 230 | .enable_write (`TRUE), |
philpem@0 | 231 | .write_enable (way_mem_we[i]), |
philpem@0 | 232 | .write_data (refill_data), |
philpem@0 | 233 | // ----- Outputs ------- |
philpem@0 | 234 | .read_data (way_data[i]) |
philpem@0 | 235 | ); |
philpem@0 | 236 | |
philpem@0 | 237 | lm32_ram |
philpem@0 | 238 | #( |
philpem@0 | 239 | // ----- Parameters ------- |
philpem@0 | 240 | .data_width (`LM32_IC_TAGS_WIDTH), |
philpem@3 | 241 | .address_width (`LM32_IC_TMEM_ADDR_WIDTH) |
philpem@3 | 242 | `ifdef PLATFORM_LATTICE |
philpem@3 | 243 | , |
philpem@3 | 244 | `ifdef CFG_ICACHE_DAT_USE_DP_TRUE |
philpem@0 | 245 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 246 | .RAM_TYPE ("RAM_DP_TRUE") |
philpem@3 | 247 | `else |
philpem@3 | 248 | `ifdef CFG_ICACHE_DAT_USE_DP |
philpem@0 | 249 | .RAM_IMPLEMENTATION ("EBR"), |
philpem@0 | 250 | .RAM_TYPE ("RAM_DP") |
philpem@3 | 251 | `else |
philpem@3 | 252 | `ifdef CFG_ICACHE_DAT_USE_SLICE |
philpem@0 | 253 | .RAM_IMPLEMENTATION ("SLICE") |
philpem@3 | 254 | `else |
philpem@0 | 255 | .RAM_IMPLEMENTATION ("AUTO") |
philpem@3 | 256 | `endif |
philpem@0 | 257 | `endif |
philpem@0 | 258 | `endif |
philpem@0 | 259 | `endif |
philpem@0 | 260 | ) |
philpem@0 | 261 | way_0_tag_ram |
philpem@0 | 262 | ( |
philpem@0 | 263 | // ----- Inputs ------- |
philpem@0 | 264 | .read_clk (clk_i), |
philpem@0 | 265 | .write_clk (clk_i), |
philpem@0 | 266 | .reset (rst_i), |
philpem@0 | 267 | .read_address (tmem_read_address), |
philpem@0 | 268 | .enable_read (enable), |
philpem@0 | 269 | .write_address (tmem_write_address), |
philpem@0 | 270 | .enable_write (`TRUE), |
philpem@0 | 271 | .write_enable (way_mem_we[i] | flushing), |
philpem@0 | 272 | .write_data (tmem_write_data), |
philpem@0 | 273 | // ----- Outputs ------- |
philpem@0 | 274 | .read_data ({way_tag[i], way_valid[i]}) |
philpem@0 | 275 | ); |
philpem@0 | 276 | |
philpem@0 | 277 | end |
philpem@0 | 278 | endgenerate |
philpem@0 | 279 | |
philpem@0 | 280 | ///////////////////////////////////////////////////// |
philpem@0 | 281 | // Combinational logic |
philpem@0 | 282 | ///////////////////////////////////////////////////// |
philpem@0 | 283 | |
philpem@0 | 284 | // Compute which ways in the cache match the address address being read |
philpem@0 | 285 | generate |
philpem@0 | 286 | for (i = 0; i < associativity; i = i + 1) |
philpem@0 | 287 | begin : match |
philpem@0 | 288 | assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_f[`LM32_IC_ADDR_TAG_RNG], `TRUE}); |
philpem@0 | 289 | end |
philpem@0 | 290 | endgenerate |
philpem@0 | 291 | |
philpem@0 | 292 | // Select data from way that matched the address being read |
philpem@0 | 293 | generate |
philpem@0 | 294 | if (associativity == 1) |
philpem@0 | 295 | begin : inst_1 |
philpem@0 | 296 | assign inst = way_match[0] ? way_data[0] : 32'b0; |
philpem@0 | 297 | end |
philpem@0 | 298 | else if (associativity == 2) |
philpem@0 | 299 | begin : inst_2 |
philpem@0 | 300 | assign inst = way_match[0] ? way_data[0] : (way_match[1] ? way_data[1] : 32'b0); |
philpem@0 | 301 | end |
philpem@0 | 302 | endgenerate |
philpem@0 | 303 | |
philpem@0 | 304 | // Compute address to use to index into the data memories |
philpem@0 | 305 | generate |
philpem@0 | 306 | if (bytes_per_line > 4) |
philpem@0 | 307 | assign dmem_write_address = {refill_address[`LM32_IC_ADDR_SET_RNG], refill_offset}; |
philpem@0 | 308 | else |
philpem@0 | 309 | assign dmem_write_address = refill_address[`LM32_IC_ADDR_SET_RNG]; |
philpem@0 | 310 | endgenerate |
philpem@0 | 311 | |
philpem@0 | 312 | assign dmem_read_address = address_a[`LM32_IC_ADDR_IDX_RNG]; |
philpem@0 | 313 | |
philpem@0 | 314 | // Compute address to use to index into the tag memories |
philpem@0 | 315 | assign tmem_read_address = address_a[`LM32_IC_ADDR_SET_RNG]; |
philpem@0 | 316 | assign tmem_write_address = flushing |
philpem@0 | 317 | ? flush_set |
philpem@0 | 318 | : refill_address[`LM32_IC_ADDR_SET_RNG]; |
philpem@0 | 319 | |
philpem@0 | 320 | // Compute signal to indicate when we are on the last refill accesses |
philpem@0 | 321 | generate |
philpem@0 | 322 | if (bytes_per_line > 4) |
philpem@0 | 323 | assign last_refill = refill_offset == {addr_offset_width{1'b1}}; |
philpem@0 | 324 | else |
philpem@0 | 325 | assign last_refill = `TRUE; |
philpem@0 | 326 | endgenerate |
philpem@0 | 327 | |
philpem@0 | 328 | // Compute data and tag memory access enable |
philpem@0 | 329 | assign enable = (stall_a == `FALSE); |
philpem@0 | 330 | |
philpem@0 | 331 | // Compute data and tag memory write enables |
philpem@0 | 332 | generate |
philpem@0 | 333 | if (associativity == 1) |
philpem@0 | 334 | begin : we_1 |
philpem@0 | 335 | assign way_mem_we[0] = (refill_ready == `TRUE); |
philpem@0 | 336 | end |
philpem@0 | 337 | else |
philpem@0 | 338 | begin : we_2 |
philpem@0 | 339 | assign way_mem_we[0] = (refill_ready == `TRUE) && (refill_way_select[0] == `TRUE); |
philpem@0 | 340 | assign way_mem_we[1] = (refill_ready == `TRUE) && (refill_way_select[1] == `TRUE); |
philpem@0 | 341 | end |
philpem@0 | 342 | endgenerate |
philpem@0 | 343 | |
philpem@0 | 344 | // On the last refill cycle set the valid bit, for all other writes it should be cleared |
philpem@0 | 345 | assign tmem_write_data[`LM32_IC_TAGS_VALID_RNG] = last_refill & !flushing; |
philpem@0 | 346 | assign tmem_write_data[`LM32_IC_TAGS_TAG_RNG] = refill_address[`LM32_IC_ADDR_TAG_RNG]; |
philpem@0 | 347 | |
philpem@0 | 348 | // Signals that indicate which state we are in |
philpem@0 | 349 | assign flushing = |state[1:0]; |
philpem@0 | 350 | assign check = state[2]; |
philpem@0 | 351 | assign refill = state[3]; |
philpem@0 | 352 | |
philpem@0 | 353 | assign miss = (~(|way_match)) && (read_enable_f == `TRUE) && (stall_f == `FALSE) && !(valid_d && branch_predict_taken_d); |
philpem@0 | 354 | assign stall_request = (check == `FALSE); |
philpem@0 | 355 | assign refill_request = (refill == `TRUE); |
philpem@0 | 356 | |
philpem@0 | 357 | ///////////////////////////////////////////////////// |
philpem@0 | 358 | // Sequential logic |
philpem@0 | 359 | ///////////////////////////////////////////////////// |
philpem@0 | 360 | |
philpem@0 | 361 | // Record way selected for replacement on a cache miss |
philpem@0 | 362 | generate |
philpem@0 | 363 | if (associativity >= 2) |
philpem@0 | 364 | begin : way_select |
philpem@0 | 365 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 366 | begin |
philpem@0 | 367 | if (rst_i == `TRUE) |
philpem@0 | 368 | refill_way_select <= {{associativity-1{1'b0}}, 1'b1}; |
philpem@0 | 369 | else |
philpem@0 | 370 | begin |
philpem@0 | 371 | if (miss == `TRUE) |
philpem@0 | 372 | refill_way_select <= {refill_way_select[0], refill_way_select[1]}; |
philpem@0 | 373 | end |
philpem@0 | 374 | end |
philpem@0 | 375 | end |
philpem@0 | 376 | endgenerate |
philpem@0 | 377 | |
philpem@0 | 378 | // Record whether we are refilling |
philpem@0 | 379 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 380 | begin |
philpem@0 | 381 | if (rst_i == `TRUE) |
philpem@0 | 382 | refilling <= `FALSE; |
philpem@0 | 383 | else |
philpem@0 | 384 | refilling <= refill; |
philpem@0 | 385 | end |
philpem@0 | 386 | |
philpem@0 | 387 | // Instruction cache control FSM |
philpem@0 | 388 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 389 | begin |
philpem@0 | 390 | if (rst_i == `TRUE) |
philpem@0 | 391 | begin |
philpem@0 | 392 | state <= `LM32_IC_STATE_FLUSH_INIT; |
philpem@0 | 393 | flush_set <= {`LM32_IC_TMEM_ADDR_WIDTH{1'b1}}; |
philpem@0 | 394 | refill_address <= {`LM32_PC_WIDTH{1'bx}}; |
philpem@0 | 395 | restart_request <= `FALSE; |
philpem@0 | 396 | end |
philpem@0 | 397 | else |
philpem@0 | 398 | begin |
philpem@0 | 399 | case (state) |
philpem@0 | 400 | |
philpem@0 | 401 | // Flush the cache for the first time after reset |
philpem@0 | 402 | `LM32_IC_STATE_FLUSH_INIT: |
philpem@0 | 403 | begin |
philpem@0 | 404 | if (flush_set == {`LM32_IC_TMEM_ADDR_WIDTH{1'b0}}) |
philpem@0 | 405 | state <= `LM32_IC_STATE_CHECK; |
philpem@0 | 406 | flush_set <= flush_set - 1'b1; |
philpem@0 | 407 | end |
philpem@0 | 408 | |
philpem@0 | 409 | // Flush the cache in response to an write to the ICC CSR |
philpem@0 | 410 | `LM32_IC_STATE_FLUSH: |
philpem@0 | 411 | begin |
philpem@0 | 412 | if (flush_set == {`LM32_IC_TMEM_ADDR_WIDTH{1'b0}}) |
philpem@0 | 413 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 414 | if (select_f) |
philpem@0 | 415 | state <= `LM32_IC_STATE_REFILL; |
philpem@0 | 416 | else |
philpem@0 | 417 | `endif |
philpem@0 | 418 | state <= `LM32_IC_STATE_CHECK; |
philpem@0 | 419 | |
philpem@0 | 420 | flush_set <= flush_set - 1'b1; |
philpem@0 | 421 | end |
philpem@0 | 422 | |
philpem@0 | 423 | // Check for cache misses |
philpem@0 | 424 | `LM32_IC_STATE_CHECK: |
philpem@0 | 425 | begin |
philpem@0 | 426 | if (stall_a == `FALSE) |
philpem@0 | 427 | restart_request <= `FALSE; |
philpem@0 | 428 | if (iflush == `TRUE) |
philpem@0 | 429 | begin |
philpem@0 | 430 | refill_address <= address_f; |
philpem@0 | 431 | state <= `LM32_IC_STATE_FLUSH; |
philpem@0 | 432 | end |
philpem@0 | 433 | else if (miss == `TRUE) |
philpem@0 | 434 | begin |
philpem@0 | 435 | refill_address <= address_f; |
philpem@0 | 436 | state <= `LM32_IC_STATE_REFILL; |
philpem@0 | 437 | end |
philpem@0 | 438 | end |
philpem@0 | 439 | |
philpem@0 | 440 | // Refill a cache line |
philpem@0 | 441 | `LM32_IC_STATE_REFILL: |
philpem@0 | 442 | begin |
philpem@0 | 443 | if (refill_ready == `TRUE) |
philpem@0 | 444 | begin |
philpem@0 | 445 | if (last_refill == `TRUE) |
philpem@0 | 446 | begin |
philpem@0 | 447 | restart_request <= `TRUE; |
philpem@0 | 448 | state <= `LM32_IC_STATE_CHECK; |
philpem@0 | 449 | end |
philpem@0 | 450 | end |
philpem@0 | 451 | end |
philpem@0 | 452 | |
philpem@0 | 453 | endcase |
philpem@0 | 454 | end |
philpem@0 | 455 | end |
philpem@0 | 456 | |
philpem@0 | 457 | generate |
philpem@0 | 458 | if (bytes_per_line > 4) |
philpem@0 | 459 | begin |
philpem@0 | 460 | // Refill offset |
philpem@0 | 461 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 462 | begin |
philpem@0 | 463 | if (rst_i == `TRUE) |
philpem@0 | 464 | refill_offset <= {addr_offset_width{1'b0}}; |
philpem@0 | 465 | else |
philpem@0 | 466 | begin |
philpem@0 | 467 | case (state) |
philpem@0 | 468 | |
philpem@0 | 469 | // Check for cache misses |
philpem@0 | 470 | `LM32_IC_STATE_CHECK: |
philpem@0 | 471 | begin |
philpem@0 | 472 | if (iflush == `TRUE) |
philpem@0 | 473 | refill_offset <= {addr_offset_width{1'b0}}; |
philpem@0 | 474 | else if (miss == `TRUE) |
philpem@0 | 475 | refill_offset <= {addr_offset_width{1'b0}}; |
philpem@0 | 476 | end |
philpem@0 | 477 | |
philpem@0 | 478 | // Refill a cache line |
philpem@0 | 479 | `LM32_IC_STATE_REFILL: |
philpem@0 | 480 | begin |
philpem@0 | 481 | if (refill_ready == `TRUE) |
philpem@0 | 482 | refill_offset <= refill_offset + 1'b1; |
philpem@0 | 483 | end |
philpem@0 | 484 | |
philpem@0 | 485 | endcase |
philpem@0 | 486 | end |
philpem@0 | 487 | end |
philpem@0 | 488 | end |
philpem@0 | 489 | endgenerate |
philpem@0 | 490 | |
philpem@0 | 491 | endmodule |
philpem@0 | 492 | |
philpem@0 | 493 | `endif |
philpem@0 | 494 |