lm32_load_store_unit.v

Sun, 04 Apr 2010 20:52:32 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 04 Apr 2010 20:52:32 +0100
changeset 2
a61bb364ae1f
parent 0
cd0b58aa6f83
child 8
07be9df9fee8
permissions
-rw-r--r--

Disable Lattice-specific stuff by default

To build on Lattice platforms, `define PLATFORM_LATTICE in lm32_include.v.
Otherwise, non-optimal "platform independent" HDL will be used.
This means LM32 can now be built for non-Lattice FPGAs.

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