lm32_load_store_unit.v

Sun, 06 Mar 2011 19:48:34 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 06 Mar 2011 19:48:34 +0000
changeset 16
5fb37de64edc
parent 8
07be9df9fee8
child 26
73de224304c1
permissions
-rwxr-xr-x

Add JTAG interface for Xilinx Spartan 6 (Michael Walle)

Original-Source: Milkymist mailing list posting, 2010-09-23
Original-Message-Id: <201009232334.04219.michael@walle.cc>
Original-Author: Michael Walle <michael walle.cc>

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