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_load_store_unit.v |
philpem@0 | 19 | // Title : Load and store unit |
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 | // : Instead of disallowing an instruction cache miss on a data cache |
philpem@0 | 27 | // : miss, both can now occur at the same time. If both occur at same |
philpem@0 | 28 | // : time, then restart address is the address of instruction that |
philpem@0 | 29 | // : caused data cache miss. |
philpem@0 | 30 | // Version : 3.2 |
philpem@0 | 31 | // : EBRs use SYNC resets instead of ASYNC resets. |
philpem@0 | 32 | // Version : 3.3 |
philpem@0 | 33 | // : Support for new non-cacheable Data Memory that is accessible by |
philpem@0 | 34 | // : the data port and has a one cycle access latency. |
philpem@0 | 35 | // Version : 3.4 |
philpem@0 | 36 | // : No change |
philpem@0 | 37 | // Version : 3.5 |
philpem@0 | 38 | // : Bug fix: Inline memory is correctly generated if it is not a |
philpem@0 | 39 | // : power-of-two |
philpem@0 | 40 | // ============================================================================= |
philpem@0 | 41 | |
philpem@0 | 42 | `include "lm32_include.v" |
philpem@0 | 43 | |
philpem@0 | 44 | ///////////////////////////////////////////////////// |
philpem@0 | 45 | // Module interface |
philpem@0 | 46 | ///////////////////////////////////////////////////// |
philpem@0 | 47 | |
philpem@0 | 48 | module lm32_load_store_unit ( |
philpem@0 | 49 | // ----- Inputs ------- |
philpem@0 | 50 | clk_i, |
philpem@0 | 51 | rst_i, |
philpem@0 | 52 | // From pipeline |
philpem@0 | 53 | stall_a, |
philpem@0 | 54 | stall_x, |
philpem@0 | 55 | stall_m, |
philpem@0 | 56 | kill_x, |
philpem@0 | 57 | kill_m, |
philpem@0 | 58 | exception_m, |
philpem@0 | 59 | store_operand_x, |
philpem@0 | 60 | load_store_address_x, |
philpem@0 | 61 | load_store_address_m, |
philpem@0 | 62 | load_store_address_w, |
philpem@0 | 63 | load_x, |
philpem@0 | 64 | store_x, |
philpem@0 | 65 | load_q_x, |
philpem@0 | 66 | store_q_x, |
philpem@0 | 67 | load_q_m, |
philpem@0 | 68 | store_q_m, |
philpem@0 | 69 | sign_extend_x, |
philpem@0 | 70 | size_x, |
philpem@0 | 71 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 72 | dflush, |
philpem@0 | 73 | `endif |
philpem@0 | 74 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 75 | irom_data_m, |
philpem@0 | 76 | `endif |
philpem@0 | 77 | // From Wishbone |
philpem@0 | 78 | d_dat_i, |
philpem@0 | 79 | d_ack_i, |
philpem@0 | 80 | d_err_i, |
philpem@0 | 81 | d_rty_i, |
philpem@0 | 82 | // ----- Outputs ------- |
philpem@0 | 83 | // To pipeline |
philpem@0 | 84 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 85 | dcache_refill_request, |
philpem@0 | 86 | dcache_restart_request, |
philpem@0 | 87 | dcache_stall_request, |
philpem@0 | 88 | dcache_refilling, |
philpem@0 | 89 | `endif |
philpem@0 | 90 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 91 | irom_store_data_m, |
philpem@0 | 92 | irom_address_xm, |
philpem@0 | 93 | irom_we_xm, |
philpem@0 | 94 | irom_stall_request_x, |
philpem@0 | 95 | `endif |
philpem@0 | 96 | load_data_w, |
philpem@0 | 97 | stall_wb_load, |
philpem@0 | 98 | // To Wishbone |
philpem@0 | 99 | d_dat_o, |
philpem@0 | 100 | d_adr_o, |
philpem@0 | 101 | d_cyc_o, |
philpem@0 | 102 | d_sel_o, |
philpem@0 | 103 | d_stb_o, |
philpem@0 | 104 | d_we_o, |
philpem@0 | 105 | d_cti_o, |
philpem@0 | 106 | d_lock_o, |
philpem@0 | 107 | d_bte_o |
philpem@0 | 108 | ); |
philpem@0 | 109 | |
philpem@0 | 110 | ///////////////////////////////////////////////////// |
philpem@0 | 111 | // Parameters |
philpem@0 | 112 | ///////////////////////////////////////////////////// |
philpem@0 | 113 | |
philpem@0 | 114 | parameter associativity = 1; // Associativity of the cache (Number of ways) |
philpem@0 | 115 | parameter sets = 512; // Number of sets |
philpem@0 | 116 | parameter bytes_per_line = 16; // Number of bytes per cache line |
philpem@0 | 117 | parameter base_address = 0; // Base address of cachable memory |
philpem@0 | 118 | parameter limit = 0; // Limit (highest address) of cachable memory |
philpem@0 | 119 | |
philpem@0 | 120 | // For bytes_per_line == 4, we set 1 so part-select range isn't reversed, even though not really used |
philpem@0 | 121 | localparam addr_offset_width = bytes_per_line == 4 ? 1 : clogb2(bytes_per_line)-1-2; |
philpem@0 | 122 | localparam addr_offset_lsb = 2; |
philpem@0 | 123 | localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1); |
philpem@0 | 124 | |
philpem@0 | 125 | ///////////////////////////////////////////////////// |
philpem@0 | 126 | // Inputs |
philpem@0 | 127 | ///////////////////////////////////////////////////// |
philpem@0 | 128 | |
philpem@0 | 129 | input clk_i; // Clock |
philpem@0 | 130 | input rst_i; // Reset |
philpem@0 | 131 | |
philpem@0 | 132 | input stall_a; // A stage stall |
philpem@0 | 133 | input stall_x; // X stage stall |
philpem@0 | 134 | input stall_m; // M stage stall |
philpem@0 | 135 | input kill_x; // Kill instruction in X stage |
philpem@0 | 136 | input kill_m; // Kill instruction in M stage |
philpem@0 | 137 | input exception_m; // An exception occured in the M stage |
philpem@0 | 138 | |
philpem@0 | 139 | input [`LM32_WORD_RNG] store_operand_x; // Data read from register to store |
philpem@0 | 140 | input [`LM32_WORD_RNG] load_store_address_x; // X stage load/store address |
philpem@0 | 141 | input [`LM32_WORD_RNG] load_store_address_m; // M stage load/store address |
philpem@0 | 142 | input [1:0] load_store_address_w; // W stage load/store address (only least two significant bits are needed) |
philpem@0 | 143 | input load_x; // Load instruction in X stage |
philpem@0 | 144 | input store_x; // Store instruction in X stage |
philpem@0 | 145 | input load_q_x; // Load instruction in X stage |
philpem@0 | 146 | input store_q_x; // Store instruction in X stage |
philpem@0 | 147 | input load_q_m; // Load instruction in M stage |
philpem@0 | 148 | input store_q_m; // Store instruction in M stage |
philpem@0 | 149 | input sign_extend_x; // Whether load instruction in X stage should sign extend or zero extend |
philpem@0 | 150 | input [`LM32_SIZE_RNG] size_x; // Size of load or store (byte, hword, word) |
philpem@0 | 151 | |
philpem@0 | 152 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 153 | input dflush; // Flush the data cache |
philpem@0 | 154 | `endif |
philpem@0 | 155 | |
philpem@0 | 156 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 157 | input [`LM32_WORD_RNG] irom_data_m; // Data from Instruction-ROM |
philpem@0 | 158 | `endif |
philpem@0 | 159 | |
philpem@0 | 160 | input [`LM32_WORD_RNG] d_dat_i; // Data Wishbone interface read data |
philpem@0 | 161 | input d_ack_i; // Data Wishbone interface acknowledgement |
philpem@0 | 162 | input d_err_i; // Data Wishbone interface error |
philpem@0 | 163 | input d_rty_i; // Data Wishbone interface retry |
philpem@0 | 164 | |
philpem@0 | 165 | ///////////////////////////////////////////////////// |
philpem@0 | 166 | // Outputs |
philpem@0 | 167 | ///////////////////////////////////////////////////// |
philpem@0 | 168 | |
philpem@0 | 169 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 170 | output dcache_refill_request; // Request to refill data cache |
philpem@0 | 171 | wire dcache_refill_request; |
philpem@0 | 172 | output dcache_restart_request; // Request to restart the instruction that caused a data cache miss |
philpem@0 | 173 | wire dcache_restart_request; |
philpem@0 | 174 | output dcache_stall_request; // Data cache stall request |
philpem@0 | 175 | wire dcache_stall_request; |
philpem@0 | 176 | output dcache_refilling; |
philpem@0 | 177 | wire dcache_refilling; |
philpem@0 | 178 | `endif |
philpem@0 | 179 | |
philpem@0 | 180 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 181 | output irom_store_data_m; // Store data to Instruction ROM |
philpem@0 | 182 | wire [`LM32_WORD_RNG] irom_store_data_m; |
philpem@0 | 183 | output [`LM32_WORD_RNG] irom_address_xm; // Load/store address to Instruction ROM |
philpem@0 | 184 | wire [`LM32_WORD_RNG] irom_address_xm; |
philpem@0 | 185 | output irom_we_xm; // Write-enable of 2nd port of Instruction ROM |
philpem@0 | 186 | wire irom_we_xm; |
philpem@0 | 187 | output irom_stall_request_x; // Stall instruction in D stage |
philpem@0 | 188 | wire irom_stall_request_x; |
philpem@0 | 189 | `endif |
philpem@0 | 190 | |
philpem@0 | 191 | output [`LM32_WORD_RNG] load_data_w; // Result of a load instruction |
philpem@0 | 192 | reg [`LM32_WORD_RNG] load_data_w; |
philpem@0 | 193 | output stall_wb_load; // Request to stall pipeline due to a load from the Wishbone interface |
philpem@0 | 194 | reg stall_wb_load; |
philpem@0 | 195 | |
philpem@0 | 196 | output [`LM32_WORD_RNG] d_dat_o; // Data Wishbone interface write data |
philpem@0 | 197 | reg [`LM32_WORD_RNG] d_dat_o; |
philpem@0 | 198 | output [`LM32_WORD_RNG] d_adr_o; // Data Wishbone interface address |
philpem@0 | 199 | reg [`LM32_WORD_RNG] d_adr_o; |
philpem@0 | 200 | output d_cyc_o; // Data Wishbone interface cycle |
philpem@0 | 201 | reg d_cyc_o; |
philpem@0 | 202 | output [`LM32_BYTE_SELECT_RNG] d_sel_o; // Data Wishbone interface byte select |
philpem@0 | 203 | reg [`LM32_BYTE_SELECT_RNG] d_sel_o; |
philpem@0 | 204 | output d_stb_o; // Data Wishbone interface strobe |
philpem@0 | 205 | reg d_stb_o; |
philpem@0 | 206 | output d_we_o; // Data Wishbone interface write enable |
philpem@0 | 207 | reg d_we_o; |
philpem@0 | 208 | output [`LM32_CTYPE_RNG] d_cti_o; // Data Wishbone interface cycle type |
philpem@0 | 209 | reg [`LM32_CTYPE_RNG] d_cti_o; |
philpem@0 | 210 | output d_lock_o; // Date Wishbone interface lock bus |
philpem@0 | 211 | reg d_lock_o; |
philpem@0 | 212 | output [`LM32_BTYPE_RNG] d_bte_o; // Data Wishbone interface burst type |
philpem@0 | 213 | wire [`LM32_BTYPE_RNG] d_bte_o; |
philpem@0 | 214 | |
philpem@0 | 215 | ///////////////////////////////////////////////////// |
philpem@0 | 216 | // Internal nets and registers |
philpem@0 | 217 | ///////////////////////////////////////////////////// |
philpem@0 | 218 | |
philpem@0 | 219 | // Microcode pipeline registers - See inputs for description |
philpem@0 | 220 | reg [`LM32_SIZE_RNG] size_m; |
philpem@0 | 221 | reg [`LM32_SIZE_RNG] size_w; |
philpem@0 | 222 | reg sign_extend_m; |
philpem@0 | 223 | reg sign_extend_w; |
philpem@0 | 224 | reg [`LM32_WORD_RNG] store_data_x; |
philpem@0 | 225 | reg [`LM32_WORD_RNG] store_data_m; |
philpem@0 | 226 | reg [`LM32_BYTE_SELECT_RNG] byte_enable_x; |
philpem@0 | 227 | reg [`LM32_BYTE_SELECT_RNG] byte_enable_m; |
philpem@0 | 228 | wire [`LM32_WORD_RNG] data_m; |
philpem@0 | 229 | reg [`LM32_WORD_RNG] data_w; |
philpem@0 | 230 | |
philpem@0 | 231 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 232 | wire dcache_select_x; // Select data cache to load from / store to |
philpem@0 | 233 | reg dcache_select_m; |
philpem@0 | 234 | wire [`LM32_WORD_RNG] dcache_data_m; // Data read from cache |
philpem@0 | 235 | wire [`LM32_WORD_RNG] dcache_refill_address; // Address to refill data cache from |
philpem@0 | 236 | reg dcache_refill_ready; // Indicates the next word of refill data is ready |
philpem@0 | 237 | wire [`LM32_CTYPE_RNG] first_cycle_type; // First Wishbone cycle type |
philpem@0 | 238 | wire [`LM32_CTYPE_RNG] next_cycle_type; // Next Wishbone cycle type |
philpem@0 | 239 | wire last_word; // Indicates if this is the last word in the cache line |
philpem@0 | 240 | wire [`LM32_WORD_RNG] first_address; // First cache refill address |
philpem@0 | 241 | `endif |
philpem@0 | 242 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 243 | wire dram_select_x; // Select data RAM to load from / store to |
philpem@0 | 244 | reg dram_select_m; |
philpem@0 | 245 | reg dram_bypass_en; // RAW in data RAM; read latched (bypass) value rather than value from memory |
philpem@0 | 246 | reg [`LM32_WORD_RNG] dram_bypass_data; // Latched value of store'd data to data RAM |
philpem@0 | 247 | wire [`LM32_WORD_RNG] dram_data_out; // Data read from data RAM |
philpem@0 | 248 | wire [`LM32_WORD_RNG] dram_data_m; // Data read from data RAM: bypass value or value from memory |
philpem@0 | 249 | wire [`LM32_WORD_RNG] dram_store_data_m; // Data to write to RAM |
philpem@0 | 250 | `endif |
philpem@0 | 251 | wire wb_select_x; // Select Wishbone to load from / store to |
philpem@0 | 252 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 253 | wire irom_select_x; // Select instruction ROM to load from / store to |
philpem@0 | 254 | reg irom_select_m; |
philpem@0 | 255 | `endif |
philpem@0 | 256 | reg wb_select_m; |
philpem@0 | 257 | reg [`LM32_WORD_RNG] wb_data_m; // Data read from Wishbone |
philpem@0 | 258 | reg wb_load_complete; // Indicates when a Wishbone load is complete |
philpem@0 | 259 | |
philpem@0 | 260 | ///////////////////////////////////////////////////// |
philpem@0 | 261 | // Functions |
philpem@0 | 262 | ///////////////////////////////////////////////////// |
philpem@0 | 263 | |
philpem@0 | 264 | `include "lm32_functions.v" |
philpem@0 | 265 | |
philpem@0 | 266 | ///////////////////////////////////////////////////// |
philpem@0 | 267 | // Instantiations |
philpem@0 | 268 | ///////////////////////////////////////////////////// |
philpem@0 | 269 | |
philpem@0 | 270 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 271 | // Data RAM |
philpem@0 | 272 | pmi_ram_dp_true |
philpem@0 | 273 | #( |
philpem@0 | 274 | // ----- Parameters ------- |
philpem@0 | 275 | .pmi_family (`LATTICE_FAMILY), |
philpem@0 | 276 | |
philpem@0 | 277 | //.pmi_addr_depth_a (1 << (clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)), |
philpem@0 | 278 | //.pmi_addr_width_a ((clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)), |
philpem@0 | 279 | //.pmi_data_width_a (`LM32_WORD_WIDTH), |
philpem@0 | 280 | //.pmi_addr_depth_b (1 << (clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)), |
philpem@0 | 281 | //.pmi_addr_width_b ((clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)), |
philpem@0 | 282 | //.pmi_data_width_b (`LM32_WORD_WIDTH), |
philpem@0 | 283 | |
philpem@0 | 284 | .pmi_addr_depth_a (`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1), |
philpem@0 | 285 | .pmi_addr_width_a (clogb2_v1(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)), |
philpem@0 | 286 | .pmi_data_width_a (`LM32_WORD_WIDTH), |
philpem@0 | 287 | .pmi_addr_depth_b (`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1), |
philpem@0 | 288 | .pmi_addr_width_b (clogb2_v1(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)), |
philpem@0 | 289 | .pmi_data_width_b (`LM32_WORD_WIDTH), |
philpem@0 | 290 | |
philpem@0 | 291 | .pmi_regmode_a ("noreg"), |
philpem@0 | 292 | .pmi_regmode_b ("noreg"), |
philpem@0 | 293 | .pmi_gsr ("enable"), |
philpem@0 | 294 | .pmi_resetmode ("sync"), |
philpem@0 | 295 | .pmi_init_file (`CFG_DRAM_INIT_FILE), |
philpem@0 | 296 | .pmi_init_file_format (`CFG_DRAM_INIT_FILE_FORMAT), |
philpem@0 | 297 | .module_type ("pmi_ram_dp_true") |
philpem@0 | 298 | ) |
philpem@0 | 299 | ram ( |
philpem@0 | 300 | // ----- Inputs ------- |
philpem@0 | 301 | .ClockA (clk_i), |
philpem@0 | 302 | .ClockB (clk_i), |
philpem@0 | 303 | .ResetA (rst_i), |
philpem@0 | 304 | .ResetB (rst_i), |
philpem@0 | 305 | .DataInA ({32{1'b0}}), |
philpem@0 | 306 | .DataInB (dram_store_data_m), |
philpem@0 | 307 | .AddressA (load_store_address_x[(clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)+2-1:2]), |
philpem@0 | 308 | .AddressB (load_store_address_m[(clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)+2-1:2]), |
philpem@0 | 309 | // .ClockEnA (!stall_x & (load_x | store_x)), |
philpem@0 | 310 | .ClockEnA (!stall_x), |
philpem@0 | 311 | .ClockEnB (!stall_m), |
philpem@0 | 312 | .WrA (`FALSE), |
philpem@0 | 313 | .WrB (store_q_m & dram_select_m), |
philpem@0 | 314 | // ----- Outputs ------- |
philpem@0 | 315 | .QA (dram_data_out), |
philpem@0 | 316 | .QB () |
philpem@0 | 317 | ); |
philpem@0 | 318 | |
philpem@0 | 319 | /*---------------------------------------------------------------------- |
philpem@0 | 320 | EBRs cannot perform reads from location 'written to' on the same clock |
philpem@0 | 321 | edge. Therefore bypass logic is required to latch the store'd value |
philpem@0 | 322 | and use it for the load (instead of value from memory). |
philpem@0 | 323 | ----------------------------------------------------------------------*/ |
philpem@0 | 324 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 325 | if (rst_i == `TRUE) |
philpem@0 | 326 | begin |
philpem@0 | 327 | dram_bypass_en <= `FALSE; |
philpem@0 | 328 | dram_bypass_data <= 0; |
philpem@0 | 329 | end |
philpem@0 | 330 | else |
philpem@0 | 331 | begin |
philpem@0 | 332 | if (stall_x == `FALSE) |
philpem@0 | 333 | dram_bypass_data <= dram_store_data_m; |
philpem@0 | 334 | |
philpem@0 | 335 | if ( (stall_m == `FALSE) |
philpem@0 | 336 | && (stall_x == `FALSE) |
philpem@0 | 337 | && (store_q_m == `TRUE) |
philpem@0 | 338 | && ( (load_x == `TRUE) |
philpem@0 | 339 | || (store_x == `TRUE) |
philpem@0 | 340 | ) |
philpem@0 | 341 | && (load_store_address_x[(`LM32_WORD_WIDTH-1):2] == load_store_address_m[(`LM32_WORD_WIDTH-1):2]) |
philpem@0 | 342 | ) |
philpem@0 | 343 | dram_bypass_en <= `TRUE; |
philpem@0 | 344 | else |
philpem@0 | 345 | if ( (dram_bypass_en == `TRUE) |
philpem@0 | 346 | && (stall_x == `FALSE) |
philpem@0 | 347 | ) |
philpem@0 | 348 | dram_bypass_en <= `FALSE; |
philpem@0 | 349 | end |
philpem@0 | 350 | |
philpem@0 | 351 | assign dram_data_m = dram_bypass_en ? dram_bypass_data : dram_data_out; |
philpem@0 | 352 | `endif |
philpem@0 | 353 | |
philpem@0 | 354 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 355 | // Data cache |
philpem@0 | 356 | lm32_dcache #( |
philpem@0 | 357 | .associativity (associativity), |
philpem@0 | 358 | .sets (sets), |
philpem@0 | 359 | .bytes_per_line (bytes_per_line), |
philpem@0 | 360 | .base_address (base_address), |
philpem@0 | 361 | .limit (limit) |
philpem@0 | 362 | ) dcache ( |
philpem@0 | 363 | // ----- Inputs ----- |
philpem@0 | 364 | .clk_i (clk_i), |
philpem@0 | 365 | .rst_i (rst_i), |
philpem@0 | 366 | .stall_a (stall_a), |
philpem@0 | 367 | .stall_x (stall_x), |
philpem@0 | 368 | .stall_m (stall_m), |
philpem@0 | 369 | .address_x (load_store_address_x), |
philpem@0 | 370 | .address_m (load_store_address_m), |
philpem@0 | 371 | .load_q_m (load_q_m & dcache_select_m), |
philpem@0 | 372 | .store_q_m (store_q_m & dcache_select_m), |
philpem@0 | 373 | .store_data (store_data_m), |
philpem@0 | 374 | .store_byte_select (byte_enable_m & {4{dcache_select_m}}), |
philpem@0 | 375 | .refill_ready (dcache_refill_ready), |
philpem@0 | 376 | .refill_data (wb_data_m), |
philpem@0 | 377 | .dflush (dflush), |
philpem@0 | 378 | // ----- Outputs ----- |
philpem@0 | 379 | .stall_request (dcache_stall_request), |
philpem@0 | 380 | .restart_request (dcache_restart_request), |
philpem@0 | 381 | .refill_request (dcache_refill_request), |
philpem@0 | 382 | .refill_address (dcache_refill_address), |
philpem@0 | 383 | .refilling (dcache_refilling), |
philpem@0 | 384 | .load_data (dcache_data_m) |
philpem@0 | 385 | ); |
philpem@0 | 386 | `endif |
philpem@0 | 387 | |
philpem@0 | 388 | ///////////////////////////////////////////////////// |
philpem@0 | 389 | // Combinational Logic |
philpem@0 | 390 | ///////////////////////////////////////////////////// |
philpem@0 | 391 | |
philpem@0 | 392 | // Select where data should be loaded from / stored to |
philpem@0 | 393 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 394 | assign dram_select_x = (load_store_address_x >= `CFG_DRAM_BASE_ADDRESS) |
philpem@0 | 395 | && (load_store_address_x <= `CFG_DRAM_LIMIT); |
philpem@0 | 396 | `endif |
philpem@0 | 397 | |
philpem@0 | 398 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 399 | assign irom_select_x = (load_store_address_x >= `CFG_IROM_BASE_ADDRESS) |
philpem@0 | 400 | && (load_store_address_x <= `CFG_IROM_LIMIT); |
philpem@0 | 401 | `endif |
philpem@0 | 402 | |
philpem@0 | 403 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 404 | assign dcache_select_x = (load_store_address_x >= `CFG_DCACHE_BASE_ADDRESS) |
philpem@0 | 405 | && (load_store_address_x <= `CFG_DCACHE_LIMIT) |
philpem@0 | 406 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 407 | && (dram_select_x == `FALSE) |
philpem@0 | 408 | `endif |
philpem@0 | 409 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 410 | && (irom_select_x == `FALSE) |
philpem@0 | 411 | `endif |
philpem@0 | 412 | ; |
philpem@0 | 413 | `endif |
philpem@0 | 414 | |
philpem@0 | 415 | assign wb_select_x = `TRUE |
philpem@0 | 416 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 417 | && !dcache_select_x |
philpem@0 | 418 | `endif |
philpem@0 | 419 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 420 | && !dram_select_x |
philpem@0 | 421 | `endif |
philpem@0 | 422 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 423 | && !irom_select_x |
philpem@0 | 424 | `endif |
philpem@0 | 425 | ; |
philpem@0 | 426 | |
philpem@0 | 427 | // Make sure data to store is in correct byte lane |
philpem@0 | 428 | always @(*) |
philpem@0 | 429 | begin |
philpem@0 | 430 | case (size_x) |
philpem@0 | 431 | `LM32_SIZE_BYTE: store_data_x = {4{store_operand_x[7:0]}}; |
philpem@0 | 432 | `LM32_SIZE_HWORD: store_data_x = {2{store_operand_x[15:0]}}; |
philpem@0 | 433 | `LM32_SIZE_WORD: store_data_x = store_operand_x; |
philpem@0 | 434 | default: store_data_x = {`LM32_WORD_WIDTH{1'bx}}; |
philpem@0 | 435 | endcase |
philpem@0 | 436 | end |
philpem@0 | 437 | |
philpem@0 | 438 | // Generate byte enable accoring to size of load or store and address being accessed |
philpem@0 | 439 | always @(*) |
philpem@0 | 440 | begin |
philpem@0 | 441 | casez ({size_x, load_store_address_x[1:0]}) |
philpem@0 | 442 | {`LM32_SIZE_BYTE, 2'b11}: byte_enable_x = 4'b0001; |
philpem@0 | 443 | {`LM32_SIZE_BYTE, 2'b10}: byte_enable_x = 4'b0010; |
philpem@0 | 444 | {`LM32_SIZE_BYTE, 2'b01}: byte_enable_x = 4'b0100; |
philpem@0 | 445 | {`LM32_SIZE_BYTE, 2'b00}: byte_enable_x = 4'b1000; |
philpem@0 | 446 | {`LM32_SIZE_HWORD, 2'b1?}: byte_enable_x = 4'b0011; |
philpem@0 | 447 | {`LM32_SIZE_HWORD, 2'b0?}: byte_enable_x = 4'b1100; |
philpem@0 | 448 | {`LM32_SIZE_WORD, 2'b??}: byte_enable_x = 4'b1111; |
philpem@0 | 449 | default: byte_enable_x = 4'bxxxx; |
philpem@0 | 450 | endcase |
philpem@0 | 451 | end |
philpem@0 | 452 | |
philpem@0 | 453 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 454 | // Only replace selected bytes |
philpem@0 | 455 | assign dram_store_data_m[`LM32_BYTE_0_RNG] = byte_enable_m[0] ? store_data_m[`LM32_BYTE_0_RNG] : dram_data_m[`LM32_BYTE_0_RNG]; |
philpem@0 | 456 | assign dram_store_data_m[`LM32_BYTE_1_RNG] = byte_enable_m[1] ? store_data_m[`LM32_BYTE_1_RNG] : dram_data_m[`LM32_BYTE_1_RNG]; |
philpem@0 | 457 | assign dram_store_data_m[`LM32_BYTE_2_RNG] = byte_enable_m[2] ? store_data_m[`LM32_BYTE_2_RNG] : dram_data_m[`LM32_BYTE_2_RNG]; |
philpem@0 | 458 | assign dram_store_data_m[`LM32_BYTE_3_RNG] = byte_enable_m[3] ? store_data_m[`LM32_BYTE_3_RNG] : dram_data_m[`LM32_BYTE_3_RNG]; |
philpem@0 | 459 | `endif |
philpem@0 | 460 | |
philpem@0 | 461 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 462 | // Only replace selected bytes |
philpem@0 | 463 | assign irom_store_data_m[`LM32_BYTE_0_RNG] = byte_enable_m[0] ? store_data_m[`LM32_BYTE_0_RNG] : irom_data_m[`LM32_BYTE_0_RNG]; |
philpem@0 | 464 | assign irom_store_data_m[`LM32_BYTE_1_RNG] = byte_enable_m[1] ? store_data_m[`LM32_BYTE_1_RNG] : irom_data_m[`LM32_BYTE_1_RNG]; |
philpem@0 | 465 | assign irom_store_data_m[`LM32_BYTE_2_RNG] = byte_enable_m[2] ? store_data_m[`LM32_BYTE_2_RNG] : irom_data_m[`LM32_BYTE_2_RNG]; |
philpem@0 | 466 | assign irom_store_data_m[`LM32_BYTE_3_RNG] = byte_enable_m[3] ? store_data_m[`LM32_BYTE_3_RNG] : irom_data_m[`LM32_BYTE_3_RNG]; |
philpem@0 | 467 | `endif |
philpem@0 | 468 | |
philpem@0 | 469 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 470 | // Instead of implementing a byte-addressable instruction ROM (for store byte instruction), |
philpem@0 | 471 | // a load-and-store architecture is used wherein a 32-bit value is loaded, the requisite |
philpem@0 | 472 | // byte is replaced, and the whole 32-bit value is written back |
philpem@0 | 473 | |
philpem@0 | 474 | assign irom_address_xm = ((irom_select_m == `TRUE) && (store_q_m == `TRUE)) |
philpem@0 | 475 | ? load_store_address_m |
philpem@0 | 476 | : load_store_address_x; |
philpem@0 | 477 | |
philpem@0 | 478 | // All store instructions perform a write operation in the M stage |
philpem@0 | 479 | assign irom_we_xm = (irom_select_m == `TRUE) |
philpem@0 | 480 | && (store_q_m == `TRUE); |
philpem@0 | 481 | |
philpem@0 | 482 | // A single port in instruction ROM is available to load-store unit for doing loads/stores. |
philpem@0 | 483 | // Since every store requires a load (in X stage) and then a store (in M stage), we cannot |
philpem@0 | 484 | // allow load (or store) instructions sequentially after the store instructions to proceed |
philpem@0 | 485 | // until the store instruction has vacated M stage (i.e., completed the store operation) |
philpem@0 | 486 | assign irom_stall_request_x = (irom_select_x == `TRUE) |
philpem@0 | 487 | && (store_q_x == `TRUE); |
philpem@0 | 488 | `endif |
philpem@0 | 489 | |
philpem@0 | 490 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 491 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 492 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 493 | // WB + DC + DRAM + IROM |
philpem@0 | 494 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 495 | ? wb_data_m |
philpem@0 | 496 | : dram_select_m == `TRUE |
philpem@0 | 497 | ? dram_data_m |
philpem@0 | 498 | : irom_select_m == `TRUE |
philpem@0 | 499 | ? irom_data_m |
philpem@0 | 500 | : dcache_data_m; |
philpem@0 | 501 | `else |
philpem@0 | 502 | // WB + DC + DRAM |
philpem@0 | 503 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 504 | ? wb_data_m |
philpem@0 | 505 | : dram_select_m == `TRUE |
philpem@0 | 506 | ? dram_data_m |
philpem@0 | 507 | : dcache_data_m; |
philpem@0 | 508 | `endif |
philpem@0 | 509 | `else |
philpem@0 | 510 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 511 | // WB + DC + IROM |
philpem@0 | 512 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 513 | ? wb_data_m |
philpem@0 | 514 | : irom_select_m == `TRUE |
philpem@0 | 515 | ? irom_data_m |
philpem@0 | 516 | : dcache_data_m; |
philpem@0 | 517 | `else |
philpem@0 | 518 | // WB + DC |
philpem@0 | 519 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 520 | ? wb_data_m |
philpem@0 | 521 | : dcache_data_m; |
philpem@0 | 522 | `endif |
philpem@0 | 523 | `endif |
philpem@0 | 524 | `else |
philpem@0 | 525 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 526 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 527 | // WB + DRAM + IROM |
philpem@0 | 528 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 529 | ? wb_data_m |
philpem@0 | 530 | : dram_select_m == `TRUE |
philpem@0 | 531 | ? dram_data_m |
philpem@0 | 532 | : irom_data_m; |
philpem@0 | 533 | `else |
philpem@0 | 534 | // WB + DRAM |
philpem@0 | 535 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 536 | ? wb_data_m |
philpem@0 | 537 | : dram_data_m; |
philpem@0 | 538 | `endif |
philpem@0 | 539 | `else |
philpem@0 | 540 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 541 | // WB + IROM |
philpem@0 | 542 | assign data_m = wb_select_m == `TRUE |
philpem@0 | 543 | ? wb_data_m |
philpem@0 | 544 | : irom_data_m; |
philpem@0 | 545 | `else |
philpem@0 | 546 | // WB |
philpem@0 | 547 | assign data_m = wb_data_m; |
philpem@0 | 548 | `endif |
philpem@0 | 549 | `endif |
philpem@0 | 550 | `endif |
philpem@0 | 551 | |
philpem@0 | 552 | // Sub-word selection and sign/zero-extension for loads |
philpem@0 | 553 | always @(*) |
philpem@0 | 554 | begin |
philpem@0 | 555 | casez ({size_w, load_store_address_w[1:0]}) |
philpem@0 | 556 | {`LM32_SIZE_BYTE, 2'b11}: load_data_w = {{24{sign_extend_w & data_w[7]}}, data_w[7:0]}; |
philpem@0 | 557 | {`LM32_SIZE_BYTE, 2'b10}: load_data_w = {{24{sign_extend_w & data_w[15]}}, data_w[15:8]}; |
philpem@0 | 558 | {`LM32_SIZE_BYTE, 2'b01}: load_data_w = {{24{sign_extend_w & data_w[23]}}, data_w[23:16]}; |
philpem@0 | 559 | {`LM32_SIZE_BYTE, 2'b00}: load_data_w = {{24{sign_extend_w & data_w[31]}}, data_w[31:24]}; |
philpem@0 | 560 | {`LM32_SIZE_HWORD, 2'b1?}: load_data_w = {{16{sign_extend_w & data_w[15]}}, data_w[15:0]}; |
philpem@0 | 561 | {`LM32_SIZE_HWORD, 2'b0?}: load_data_w = {{16{sign_extend_w & data_w[31]}}, data_w[31:16]}; |
philpem@0 | 562 | {`LM32_SIZE_WORD, 2'b??}: load_data_w = data_w; |
philpem@0 | 563 | default: load_data_w = {`LM32_WORD_WIDTH{1'bx}}; |
philpem@0 | 564 | endcase |
philpem@0 | 565 | end |
philpem@0 | 566 | |
philpem@0 | 567 | // Unused/constant Wishbone signals |
philpem@0 | 568 | assign d_bte_o = `LM32_BTYPE_LINEAR; |
philpem@0 | 569 | |
philpem@0 | 570 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 571 | // Generate signal to indicate last word in cache line |
philpem@0 | 572 | generate |
philpem@0 | 573 | case (bytes_per_line) |
philpem@0 | 574 | 4: |
philpem@0 | 575 | begin |
philpem@0 | 576 | assign first_cycle_type = `LM32_CTYPE_END; |
philpem@0 | 577 | assign next_cycle_type = `LM32_CTYPE_END; |
philpem@0 | 578 | assign last_word = `TRUE; |
philpem@0 | 579 | assign first_address = {dcache_refill_address[`LM32_WORD_WIDTH-1:2], 2'b00}; |
philpem@0 | 580 | end |
philpem@0 | 581 | 8: |
philpem@0 | 582 | begin |
philpem@0 | 583 | assign first_cycle_type = `LM32_CTYPE_INCREMENTING; |
philpem@0 | 584 | assign next_cycle_type = `LM32_CTYPE_END; |
philpem@0 | 585 | assign last_word = (&d_adr_o[addr_offset_msb:addr_offset_lsb]) == 1'b1; |
philpem@0 | 586 | assign first_address = {dcache_refill_address[`LM32_WORD_WIDTH-1:addr_offset_msb+1], {addr_offset_width{1'b0}}, 2'b00}; |
philpem@0 | 587 | end |
philpem@0 | 588 | 16: |
philpem@0 | 589 | begin |
philpem@0 | 590 | assign first_cycle_type = `LM32_CTYPE_INCREMENTING; |
philpem@0 | 591 | assign next_cycle_type = d_adr_o[addr_offset_msb] == 1'b1 ? `LM32_CTYPE_END : `LM32_CTYPE_INCREMENTING; |
philpem@0 | 592 | assign last_word = (&d_adr_o[addr_offset_msb:addr_offset_lsb]) == 1'b1; |
philpem@0 | 593 | assign first_address = {dcache_refill_address[`LM32_WORD_WIDTH-1:addr_offset_msb+1], {addr_offset_width{1'b0}}, 2'b00}; |
philpem@0 | 594 | end |
philpem@0 | 595 | endcase |
philpem@0 | 596 | endgenerate |
philpem@0 | 597 | `endif |
philpem@0 | 598 | |
philpem@0 | 599 | ///////////////////////////////////////////////////// |
philpem@0 | 600 | // Sequential Logic |
philpem@0 | 601 | ///////////////////////////////////////////////////// |
philpem@0 | 602 | |
philpem@0 | 603 | // Data Wishbone interface |
philpem@0 | 604 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 605 | begin |
philpem@0 | 606 | if (rst_i == `TRUE) |
philpem@0 | 607 | begin |
philpem@0 | 608 | d_cyc_o <= `FALSE; |
philpem@0 | 609 | d_stb_o <= `FALSE; |
philpem@0 | 610 | d_dat_o <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 611 | d_adr_o <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 612 | d_sel_o <= {`LM32_BYTE_SELECT_WIDTH{`FALSE}}; |
philpem@0 | 613 | d_we_o <= `FALSE; |
philpem@0 | 614 | d_cti_o <= `LM32_CTYPE_END; |
philpem@0 | 615 | d_lock_o <= `FALSE; |
philpem@0 | 616 | wb_data_m <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 617 | wb_load_complete <= `FALSE; |
philpem@0 | 618 | stall_wb_load <= `FALSE; |
philpem@0 | 619 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 620 | dcache_refill_ready <= `FALSE; |
philpem@0 | 621 | `endif |
philpem@0 | 622 | end |
philpem@0 | 623 | else |
philpem@0 | 624 | begin |
philpem@0 | 625 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 626 | // Refill ready should only be asserted for a single cycle |
philpem@0 | 627 | dcache_refill_ready <= `FALSE; |
philpem@0 | 628 | `endif |
philpem@0 | 629 | // Is a Wishbone cycle already in progress? |
philpem@0 | 630 | if (d_cyc_o == `TRUE) |
philpem@0 | 631 | begin |
philpem@0 | 632 | // Is the cycle complete? |
philpem@0 | 633 | if ((d_ack_i == `TRUE) || (d_err_i == `TRUE)) |
philpem@0 | 634 | begin |
philpem@0 | 635 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 636 | if ((dcache_refilling == `TRUE) && (!last_word)) |
philpem@0 | 637 | begin |
philpem@0 | 638 | // Fetch next word of cache line |
philpem@0 | 639 | d_adr_o[addr_offset_msb:addr_offset_lsb] <= d_adr_o[addr_offset_msb:addr_offset_lsb] + 1'b1; |
philpem@0 | 640 | end |
philpem@0 | 641 | else |
philpem@0 | 642 | `endif |
philpem@0 | 643 | begin |
philpem@0 | 644 | // Refill/access complete |
philpem@0 | 645 | d_cyc_o <= `FALSE; |
philpem@0 | 646 | d_stb_o <= `FALSE; |
philpem@0 | 647 | d_lock_o <= `FALSE; |
philpem@0 | 648 | end |
philpem@0 | 649 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 650 | d_cti_o <= next_cycle_type; |
philpem@0 | 651 | // If we are performing a refill, indicate to cache next word of data is ready |
philpem@0 | 652 | dcache_refill_ready <= dcache_refilling; |
philpem@0 | 653 | `endif |
philpem@0 | 654 | // Register data read from Wishbone interface |
philpem@0 | 655 | wb_data_m <= d_dat_i; |
philpem@0 | 656 | // Don't set when stores complete - otherwise we'll deadlock if load in m stage |
philpem@0 | 657 | wb_load_complete <= !d_we_o; |
philpem@0 | 658 | end |
philpem@0 | 659 | // synthesis translate_off |
philpem@0 | 660 | if (d_err_i == `TRUE) |
philpem@0 | 661 | $display ("Data bus error. Address: %x", d_adr_o); |
philpem@0 | 662 | // synthesis translate_on |
philpem@0 | 663 | end |
philpem@0 | 664 | else |
philpem@0 | 665 | begin |
philpem@0 | 666 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 667 | if (dcache_refill_request == `TRUE) |
philpem@0 | 668 | begin |
philpem@0 | 669 | // Start cache refill |
philpem@0 | 670 | d_adr_o <= first_address; |
philpem@0 | 671 | d_cyc_o <= `TRUE; |
philpem@0 | 672 | d_sel_o <= {`LM32_WORD_WIDTH/8{`TRUE}}; |
philpem@0 | 673 | d_stb_o <= `TRUE; |
philpem@0 | 674 | d_we_o <= `FALSE; |
philpem@0 | 675 | d_cti_o <= first_cycle_type; |
philpem@0 | 676 | //d_lock_o <= `TRUE; |
philpem@0 | 677 | end |
philpem@0 | 678 | else |
philpem@0 | 679 | `endif |
philpem@0 | 680 | if ( (store_q_m == `TRUE) |
philpem@0 | 681 | && (stall_m == `FALSE) |
philpem@0 | 682 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 683 | && (dram_select_m == `FALSE) |
philpem@0 | 684 | `endif |
philpem@0 | 685 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 686 | && (irom_select_m == `FALSE) |
philpem@0 | 687 | `endif |
philpem@0 | 688 | ) |
philpem@0 | 689 | begin |
philpem@0 | 690 | // Data cache is write through, so all stores go to memory |
philpem@0 | 691 | d_dat_o <= store_data_m; |
philpem@0 | 692 | d_adr_o <= load_store_address_m; |
philpem@0 | 693 | d_cyc_o <= `TRUE; |
philpem@0 | 694 | d_sel_o <= byte_enable_m; |
philpem@0 | 695 | d_stb_o <= `TRUE; |
philpem@0 | 696 | d_we_o <= `TRUE; |
philpem@0 | 697 | d_cti_o <= `LM32_CTYPE_END; |
philpem@0 | 698 | end |
philpem@0 | 699 | else if ( (load_q_m == `TRUE) |
philpem@0 | 700 | && (wb_select_m == `TRUE) |
philpem@0 | 701 | && (wb_load_complete == `FALSE) |
philpem@0 | 702 | // stall_m will be TRUE, because stall_wb_load will be TRUE |
philpem@0 | 703 | ) |
philpem@0 | 704 | begin |
philpem@0 | 705 | // Read requested address |
philpem@0 | 706 | stall_wb_load <= `FALSE; |
philpem@0 | 707 | d_adr_o <= load_store_address_m; |
philpem@0 | 708 | d_cyc_o <= `TRUE; |
philpem@0 | 709 | d_sel_o <= byte_enable_m; |
philpem@0 | 710 | d_stb_o <= `TRUE; |
philpem@0 | 711 | d_we_o <= `FALSE; |
philpem@0 | 712 | d_cti_o <= `LM32_CTYPE_END; |
philpem@0 | 713 | end |
philpem@0 | 714 | end |
philpem@0 | 715 | // Clear load/store complete flag when instruction leaves M stage |
philpem@0 | 716 | if (stall_m == `FALSE) |
philpem@0 | 717 | wb_load_complete <= `FALSE; |
philpem@0 | 718 | // When a Wishbone load first enters the M stage, we need to stall it |
philpem@0 | 719 | if ((load_q_x == `TRUE) && (wb_select_x == `TRUE) && (stall_x == `FALSE)) |
philpem@0 | 720 | stall_wb_load <= `TRUE; |
philpem@0 | 721 | // Clear stall request if load instruction is killed |
philpem@0 | 722 | if ((kill_m == `TRUE) || (exception_m == `TRUE)) |
philpem@0 | 723 | stall_wb_load <= `FALSE; |
philpem@0 | 724 | end |
philpem@0 | 725 | end |
philpem@0 | 726 | |
philpem@0 | 727 | // Pipeline registers |
philpem@0 | 728 | |
philpem@0 | 729 | // X/M stage pipeline registers |
philpem@0 | 730 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 731 | begin |
philpem@0 | 732 | if (rst_i == `TRUE) |
philpem@0 | 733 | begin |
philpem@0 | 734 | sign_extend_m <= `FALSE; |
philpem@0 | 735 | size_m <= 2'b00; |
philpem@0 | 736 | byte_enable_m <= `FALSE; |
philpem@0 | 737 | store_data_m <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 738 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 739 | dcache_select_m <= `FALSE; |
philpem@0 | 740 | `endif |
philpem@0 | 741 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 742 | dram_select_m <= `FALSE; |
philpem@0 | 743 | `endif |
philpem@0 | 744 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 745 | irom_select_m <= `FALSE; |
philpem@0 | 746 | `endif |
philpem@0 | 747 | wb_select_m <= `FALSE; |
philpem@0 | 748 | end |
philpem@0 | 749 | else |
philpem@0 | 750 | begin |
philpem@0 | 751 | if (stall_m == `FALSE) |
philpem@0 | 752 | begin |
philpem@0 | 753 | sign_extend_m <= sign_extend_x; |
philpem@0 | 754 | size_m <= size_x; |
philpem@0 | 755 | byte_enable_m <= byte_enable_x; |
philpem@0 | 756 | store_data_m <= store_data_x; |
philpem@0 | 757 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 758 | dcache_select_m <= dcache_select_x; |
philpem@0 | 759 | `endif |
philpem@0 | 760 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 761 | dram_select_m <= dram_select_x; |
philpem@0 | 762 | `endif |
philpem@0 | 763 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 764 | irom_select_m <= irom_select_x; |
philpem@0 | 765 | `endif |
philpem@0 | 766 | wb_select_m <= wb_select_x; |
philpem@0 | 767 | end |
philpem@0 | 768 | end |
philpem@0 | 769 | end |
philpem@0 | 770 | |
philpem@0 | 771 | // M/W stage pipeline registers |
philpem@0 | 772 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 773 | begin |
philpem@0 | 774 | if (rst_i == `TRUE) |
philpem@0 | 775 | begin |
philpem@0 | 776 | size_w <= 2'b00; |
philpem@0 | 777 | data_w <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 778 | sign_extend_w <= `FALSE; |
philpem@0 | 779 | end |
philpem@0 | 780 | else |
philpem@0 | 781 | begin |
philpem@0 | 782 | size_w <= size_m; |
philpem@0 | 783 | data_w <= data_m; |
philpem@0 | 784 | sign_extend_w <= sign_extend_m; |
philpem@0 | 785 | end |
philpem@0 | 786 | end |
philpem@0 | 787 | |
philpem@0 | 788 | ///////////////////////////////////////////////////// |
philpem@0 | 789 | // Behavioural Logic |
philpem@0 | 790 | ///////////////////////////////////////////////////// |
philpem@0 | 791 | |
philpem@0 | 792 | // synthesis translate_off |
philpem@0 | 793 | |
philpem@0 | 794 | // Check for non-aligned loads or stores |
philpem@0 | 795 | always @(posedge clk_i) |
philpem@0 | 796 | begin |
philpem@0 | 797 | if (((load_q_m == `TRUE) || (store_q_m == `TRUE)) && (stall_m == `FALSE)) |
philpem@0 | 798 | begin |
philpem@0 | 799 | if ((size_m === `LM32_SIZE_HWORD) && (load_store_address_m[0] !== 1'b0)) |
philpem@0 | 800 | $display ("Warning: Non-aligned halfword access. Address: 0x%0x Time: %0t.", load_store_address_m, $time); |
philpem@0 | 801 | if ((size_m === `LM32_SIZE_WORD) && (load_store_address_m[1:0] !== 2'b00)) |
philpem@0 | 802 | $display ("Warning: Non-aligned word access. Address: 0x%0x Time: %0t.", load_store_address_m, $time); |
philpem@0 | 803 | end |
philpem@0 | 804 | end |
philpem@0 | 805 | |
philpem@0 | 806 | // synthesis translate_on |
philpem@0 | 807 | |
philpem@0 | 808 | endmodule |