lm32_load_store_unit.v

Mon, 05 Apr 2010 21:00:31 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 05 Apr 2010 21:00:31 +0100
changeset 6
a8e459b24c31
parent 0
cd0b58aa6f83
child 8
07be9df9fee8
permissions
-rw-r--r--

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