Tue, 06 Apr 2010 18:27:55 +0100
Make cache 2-way associative
Switched from Direct Mapped to 2-Way Set Associative caches. Should boost speed
a bit.
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_cpu.v |
philpem@0 | 19 | // Title : Top-level of CPU. |
philpem@0 | 20 | // Dependencies : lm32_include.v |
philpem@0 | 21 | // |
philpem@0 | 22 | // Version 3.4 |
philpem@0 | 23 | // 1. Bug Fix: In a tight infinite loop (add, sw, bi) incoming interrupts were |
philpem@0 | 24 | // never serviced. |
philpem@0 | 25 | // |
philpem@0 | 26 | // Version 3.3 |
philpem@0 | 27 | // 1. Feature: Support for memory that is tightly coupled to processor core, and |
philpem@0 | 28 | // has a single-cycle access latency (same as caches). Instruction port has |
philpem@0 | 29 | // access to a dedicated physically-mapped memory. Data port has access to |
philpem@0 | 30 | // a dedicated physically-mapped memory. In order to be able to manipulate |
philpem@0 | 31 | // values in both these memories via the debugger, these memories also |
philpem@0 | 32 | // interface with the data port of LM32. |
philpem@0 | 33 | // 2. Feature: Extended Configuration Register |
philpem@0 | 34 | // 3. Bug Fix: Removed port names that conflict with keywords reserved in System- |
philpem@0 | 35 | // Verilog. |
philpem@0 | 36 | // |
philpem@0 | 37 | // Version 3.2 |
philpem@0 | 38 | // 1. Bug Fix: Single-stepping a load/store to invalid address causes debugger to |
philpem@0 | 39 | // hang. At the same time CPU fails to register data bus error exception. Bug |
philpem@0 | 40 | // is caused because (a) data bus error exception occurs after load/store has |
philpem@0 | 41 | // passed X stage and next sequential instruction (e.g., brk) is already in X |
philpem@0 | 42 | // stage, and (b) data bus error exception had lower priority than, say, brk |
philpem@0 | 43 | // exception. |
philpem@0 | 44 | // 2. Bug Fix: If a brk (or scall/eret/bret) sequentially follows a load/store to |
philpem@0 | 45 | // invalid location, CPU will fail to register data bus error exception. The |
philpem@0 | 46 | // solution is to stall scall/eret/bret/brk instructions in D pipeline stage |
philpem@0 | 47 | // until load/store has completed. |
philpem@0 | 48 | // 3. Feature: Enable precise identification of load/store that causes seg fault. |
philpem@0 | 49 | // 4. SYNC resets used for register file when implemented in EBRs. |
philpem@0 | 50 | // |
philpem@0 | 51 | // Version 3.1 |
philpem@0 | 52 | // 1. Feature: LM32 Register File can now be mapped in to on-chip block RAM (EBR) |
philpem@0 | 53 | // instead of distributed memory by enabling the option in LM32 GUI. |
philpem@0 | 54 | // 2. Feature: LM32 also adds a static branch predictor to improve branch |
philpem@0 | 55 | // performance. All immediate-based forward-pointing branches are predicted |
philpem@0 | 56 | // not-taken. All immediate-based backward-pointing branches are predicted taken. |
philpem@0 | 57 | // |
philpem@0 | 58 | // Version 7.0SP2, 3.0 |
philpem@0 | 59 | // No Change |
philpem@0 | 60 | // |
philpem@0 | 61 | // Version 6.1.17 |
philpem@0 | 62 | // Initial Release |
philpem@0 | 63 | // ============================================================================= |
philpem@0 | 64 | |
philpem@0 | 65 | `include "lm32_include.v" |
philpem@0 | 66 | |
philpem@0 | 67 | ///////////////////////////////////////////////////// |
philpem@0 | 68 | // Module interface |
philpem@0 | 69 | ///////////////////////////////////////////////////// |
philpem@0 | 70 | |
philpem@0 | 71 | module lm32_cpu ( |
philpem@0 | 72 | // ----- Inputs ------- |
philpem@0 | 73 | clk_i, |
philpem@0 | 74 | `ifdef CFG_EBR_NEGEDGE_REGISTER_FILE |
philpem@0 | 75 | clk_n_i, |
philpem@0 | 76 | `endif |
philpem@0 | 77 | rst_i, |
philpem@0 | 78 | // From external devices |
philpem@0 | 79 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 80 | interrupt_n, |
philpem@0 | 81 | `endif |
philpem@0 | 82 | // From user logic |
philpem@0 | 83 | `ifdef CFG_USER_ENABLED |
philpem@0 | 84 | user_result, |
philpem@0 | 85 | user_complete, |
philpem@0 | 86 | `endif |
philpem@0 | 87 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 88 | // From JTAG |
philpem@0 | 89 | jtag_clk, |
philpem@0 | 90 | jtag_update, |
philpem@0 | 91 | jtag_reg_q, |
philpem@0 | 92 | jtag_reg_addr_q, |
philpem@0 | 93 | `endif |
philpem@0 | 94 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 95 | // Instruction Wishbone master |
philpem@0 | 96 | I_DAT_I, |
philpem@0 | 97 | I_ACK_I, |
philpem@0 | 98 | I_ERR_I, |
philpem@0 | 99 | I_RTY_I, |
philpem@0 | 100 | `endif |
philpem@0 | 101 | // Data Wishbone master |
philpem@0 | 102 | D_DAT_I, |
philpem@0 | 103 | D_ACK_I, |
philpem@0 | 104 | D_ERR_I, |
philpem@0 | 105 | D_RTY_I, |
philpem@0 | 106 | // ----- Outputs ------- |
philpem@0 | 107 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 108 | trace_pc, |
philpem@0 | 109 | trace_pc_valid, |
philpem@0 | 110 | trace_exception, |
philpem@0 | 111 | trace_eid, |
philpem@0 | 112 | trace_eret, |
philpem@0 | 113 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 114 | trace_bret, |
philpem@0 | 115 | `endif |
philpem@0 | 116 | `endif |
philpem@0 | 117 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 118 | jtag_reg_d, |
philpem@0 | 119 | jtag_reg_addr_d, |
philpem@0 | 120 | `endif |
philpem@0 | 121 | `ifdef CFG_USER_ENABLED |
philpem@0 | 122 | user_valid, |
philpem@0 | 123 | user_opcode, |
philpem@0 | 124 | user_operand_0, |
philpem@0 | 125 | user_operand_1, |
philpem@0 | 126 | `endif |
philpem@0 | 127 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 128 | // Instruction Wishbone master |
philpem@0 | 129 | I_DAT_O, |
philpem@0 | 130 | I_ADR_O, |
philpem@0 | 131 | I_CYC_O, |
philpem@0 | 132 | I_SEL_O, |
philpem@0 | 133 | I_STB_O, |
philpem@0 | 134 | I_WE_O, |
philpem@0 | 135 | I_CTI_O, |
philpem@0 | 136 | I_LOCK_O, |
philpem@0 | 137 | I_BTE_O, |
philpem@0 | 138 | `endif |
philpem@0 | 139 | // Data Wishbone master |
philpem@0 | 140 | D_DAT_O, |
philpem@0 | 141 | D_ADR_O, |
philpem@0 | 142 | D_CYC_O, |
philpem@0 | 143 | D_SEL_O, |
philpem@0 | 144 | D_STB_O, |
philpem@0 | 145 | D_WE_O, |
philpem@0 | 146 | D_CTI_O, |
philpem@0 | 147 | D_LOCK_O, |
philpem@0 | 148 | D_BTE_O |
philpem@0 | 149 | ); |
philpem@0 | 150 | |
philpem@0 | 151 | ///////////////////////////////////////////////////// |
philpem@0 | 152 | // Parameters |
philpem@0 | 153 | ///////////////////////////////////////////////////// |
philpem@0 | 154 | |
philpem@0 | 155 | parameter eba_reset = `CFG_EBA_RESET; // Reset value for EBA CSR |
philpem@0 | 156 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 157 | parameter deba_reset = `CFG_DEBA_RESET; // Reset value for DEBA CSR |
philpem@0 | 158 | `endif |
philpem@0 | 159 | |
philpem@0 | 160 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 161 | parameter icache_associativity = `CFG_ICACHE_ASSOCIATIVITY; // Associativity of the cache (Number of ways) |
philpem@0 | 162 | parameter icache_sets = `CFG_ICACHE_SETS; // Number of sets |
philpem@0 | 163 | parameter icache_bytes_per_line = `CFG_ICACHE_BYTES_PER_LINE; // Number of bytes per cache line |
philpem@0 | 164 | parameter icache_base_address = `CFG_ICACHE_BASE_ADDRESS; // Base address of cachable memory |
philpem@0 | 165 | parameter icache_limit = `CFG_ICACHE_LIMIT; // Limit (highest address) of cachable memory |
philpem@0 | 166 | `else |
philpem@0 | 167 | parameter icache_associativity = 1; |
philpem@0 | 168 | parameter icache_sets = 512; |
philpem@0 | 169 | parameter icache_bytes_per_line = 16; |
philpem@0 | 170 | parameter icache_base_address = 0; |
philpem@0 | 171 | parameter icache_limit = 0; |
philpem@0 | 172 | `endif |
philpem@0 | 173 | |
philpem@0 | 174 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 175 | parameter dcache_associativity = `CFG_DCACHE_ASSOCIATIVITY; // Associativity of the cache (Number of ways) |
philpem@0 | 176 | parameter dcache_sets = `CFG_DCACHE_SETS; // Number of sets |
philpem@0 | 177 | parameter dcache_bytes_per_line = `CFG_DCACHE_BYTES_PER_LINE; // Number of bytes per cache line |
philpem@0 | 178 | parameter dcache_base_address = `CFG_DCACHE_BASE_ADDRESS; // Base address of cachable memory |
philpem@0 | 179 | parameter dcache_limit = `CFG_DCACHE_LIMIT; // Limit (highest address) of cachable memory |
philpem@0 | 180 | `else |
philpem@0 | 181 | parameter dcache_associativity = 1; |
philpem@0 | 182 | parameter dcache_sets = 512; |
philpem@0 | 183 | parameter dcache_bytes_per_line = 16; |
philpem@0 | 184 | parameter dcache_base_address = 0; |
philpem@0 | 185 | parameter dcache_limit = 0; |
philpem@0 | 186 | `endif |
philpem@0 | 187 | |
philpem@0 | 188 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 189 | parameter watchpoints = `CFG_WATCHPOINTS; // Number of h/w watchpoint CSRs |
philpem@0 | 190 | `else |
philpem@0 | 191 | parameter watchpoints = 0; |
philpem@0 | 192 | `endif |
philpem@0 | 193 | `ifdef CFG_ROM_DEBUG_ENABLED |
philpem@0 | 194 | parameter breakpoints = `CFG_BREAKPOINTS; // Number of h/w breakpoint CSRs |
philpem@0 | 195 | `else |
philpem@0 | 196 | parameter breakpoints = 0; |
philpem@0 | 197 | `endif |
philpem@0 | 198 | |
philpem@0 | 199 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 200 | parameter interrupts = `CFG_INTERRUPTS; // Number of interrupts |
philpem@0 | 201 | `else |
philpem@0 | 202 | parameter interrupts = 0; |
philpem@0 | 203 | `endif |
philpem@0 | 204 | |
philpem@0 | 205 | ///////////////////////////////////////////////////// |
philpem@0 | 206 | // Inputs |
philpem@0 | 207 | ///////////////////////////////////////////////////// |
philpem@0 | 208 | |
philpem@0 | 209 | input clk_i; // Clock |
philpem@0 | 210 | `ifdef CFG_EBR_NEGEDGE_REGISTER_FILE |
philpem@0 | 211 | input clk_n_i; // Inverted clock |
philpem@0 | 212 | `endif |
philpem@0 | 213 | input rst_i; // Reset |
philpem@0 | 214 | |
philpem@0 | 215 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 216 | input [`LM32_INTERRUPT_RNG] interrupt_n; // Interrupt pins, active-low |
philpem@0 | 217 | `endif |
philpem@0 | 218 | |
philpem@0 | 219 | `ifdef CFG_USER_ENABLED |
philpem@0 | 220 | input [`LM32_WORD_RNG] user_result; // User-defined instruction result |
philpem@0 | 221 | input user_complete; // User-defined instruction execution is complete |
philpem@0 | 222 | `endif |
philpem@0 | 223 | |
philpem@0 | 224 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 225 | input jtag_clk; // JTAG clock |
philpem@0 | 226 | input jtag_update; // JTAG state machine is in data register update state |
philpem@0 | 227 | input [`LM32_BYTE_RNG] jtag_reg_q; |
philpem@0 | 228 | input [2:0] jtag_reg_addr_q; |
philpem@0 | 229 | `endif |
philpem@0 | 230 | |
philpem@0 | 231 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 232 | input [`LM32_WORD_RNG] I_DAT_I; // Instruction Wishbone interface read data |
philpem@0 | 233 | input I_ACK_I; // Instruction Wishbone interface acknowledgement |
philpem@0 | 234 | input I_ERR_I; // Instruction Wishbone interface error |
philpem@0 | 235 | input I_RTY_I; // Instruction Wishbone interface retry |
philpem@0 | 236 | `endif |
philpem@0 | 237 | |
philpem@0 | 238 | input [`LM32_WORD_RNG] D_DAT_I; // Data Wishbone interface read data |
philpem@0 | 239 | input D_ACK_I; // Data Wishbone interface acknowledgement |
philpem@0 | 240 | input D_ERR_I; // Data Wishbone interface error |
philpem@0 | 241 | input D_RTY_I; // Data Wishbone interface retry |
philpem@0 | 242 | |
philpem@0 | 243 | ///////////////////////////////////////////////////// |
philpem@0 | 244 | // Outputs |
philpem@0 | 245 | ///////////////////////////////////////////////////// |
philpem@0 | 246 | |
philpem@0 | 247 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 248 | output [`LM32_PC_RNG] trace_pc; // PC to trace |
philpem@0 | 249 | reg [`LM32_PC_RNG] trace_pc; |
philpem@0 | 250 | output trace_pc_valid; // Indicates that a new trace PC is valid |
philpem@0 | 251 | reg trace_pc_valid; |
philpem@0 | 252 | output trace_exception; // Indicates an exception has occured |
philpem@0 | 253 | reg trace_exception; |
philpem@0 | 254 | output [`LM32_EID_RNG] trace_eid; // Indicates what type of exception has occured |
philpem@0 | 255 | reg [`LM32_EID_RNG] trace_eid; |
philpem@0 | 256 | output trace_eret; // Indicates an eret instruction has been executed |
philpem@0 | 257 | reg trace_eret; |
philpem@0 | 258 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 259 | output trace_bret; // Indicates a bret instruction has been executed |
philpem@0 | 260 | reg trace_bret; |
philpem@0 | 261 | `endif |
philpem@0 | 262 | `endif |
philpem@0 | 263 | |
philpem@0 | 264 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 265 | output [`LM32_BYTE_RNG] jtag_reg_d; |
philpem@0 | 266 | wire [`LM32_BYTE_RNG] jtag_reg_d; |
philpem@0 | 267 | output [2:0] jtag_reg_addr_d; |
philpem@0 | 268 | wire [2:0] jtag_reg_addr_d; |
philpem@0 | 269 | `endif |
philpem@0 | 270 | |
philpem@0 | 271 | `ifdef CFG_USER_ENABLED |
philpem@0 | 272 | output user_valid; // Indicates if user_opcode is valid |
philpem@0 | 273 | wire user_valid; |
philpem@0 | 274 | output [`LM32_USER_OPCODE_RNG] user_opcode; // User-defined instruction opcode |
philpem@0 | 275 | reg [`LM32_USER_OPCODE_RNG] user_opcode; |
philpem@0 | 276 | output [`LM32_WORD_RNG] user_operand_0; // First operand for user-defined instruction |
philpem@0 | 277 | wire [`LM32_WORD_RNG] user_operand_0; |
philpem@0 | 278 | output [`LM32_WORD_RNG] user_operand_1; // Second operand for user-defined instruction |
philpem@0 | 279 | wire [`LM32_WORD_RNG] user_operand_1; |
philpem@0 | 280 | `endif |
philpem@0 | 281 | |
philpem@0 | 282 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 283 | output [`LM32_WORD_RNG] I_DAT_O; // Instruction Wishbone interface write data |
philpem@0 | 284 | wire [`LM32_WORD_RNG] I_DAT_O; |
philpem@0 | 285 | output [`LM32_WORD_RNG] I_ADR_O; // Instruction Wishbone interface address |
philpem@0 | 286 | wire [`LM32_WORD_RNG] I_ADR_O; |
philpem@0 | 287 | output I_CYC_O; // Instruction Wishbone interface cycle |
philpem@0 | 288 | wire I_CYC_O; |
philpem@0 | 289 | output [`LM32_BYTE_SELECT_RNG] I_SEL_O; // Instruction Wishbone interface byte select |
philpem@0 | 290 | wire [`LM32_BYTE_SELECT_RNG] I_SEL_O; |
philpem@0 | 291 | output I_STB_O; // Instruction Wishbone interface strobe |
philpem@0 | 292 | wire I_STB_O; |
philpem@0 | 293 | output I_WE_O; // Instruction Wishbone interface write enable |
philpem@0 | 294 | wire I_WE_O; |
philpem@0 | 295 | output [`LM32_CTYPE_RNG] I_CTI_O; // Instruction Wishbone interface cycle type |
philpem@0 | 296 | wire [`LM32_CTYPE_RNG] I_CTI_O; |
philpem@0 | 297 | output I_LOCK_O; // Instruction Wishbone interface lock bus |
philpem@0 | 298 | wire I_LOCK_O; |
philpem@0 | 299 | output [`LM32_BTYPE_RNG] I_BTE_O; // Instruction Wishbone interface burst type |
philpem@0 | 300 | wire [`LM32_BTYPE_RNG] I_BTE_O; |
philpem@0 | 301 | `endif |
philpem@0 | 302 | |
philpem@0 | 303 | output [`LM32_WORD_RNG] D_DAT_O; // Data Wishbone interface write data |
philpem@0 | 304 | wire [`LM32_WORD_RNG] D_DAT_O; |
philpem@0 | 305 | output [`LM32_WORD_RNG] D_ADR_O; // Data Wishbone interface address |
philpem@0 | 306 | wire [`LM32_WORD_RNG] D_ADR_O; |
philpem@0 | 307 | output D_CYC_O; // Data Wishbone interface cycle |
philpem@0 | 308 | wire D_CYC_O; |
philpem@0 | 309 | output [`LM32_BYTE_SELECT_RNG] D_SEL_O; // Data Wishbone interface byte select |
philpem@0 | 310 | wire [`LM32_BYTE_SELECT_RNG] D_SEL_O; |
philpem@0 | 311 | output D_STB_O; // Data Wishbone interface strobe |
philpem@0 | 312 | wire D_STB_O; |
philpem@0 | 313 | output D_WE_O; // Data Wishbone interface write enable |
philpem@0 | 314 | wire D_WE_O; |
philpem@0 | 315 | output [`LM32_CTYPE_RNG] D_CTI_O; // Data Wishbone interface cycle type |
philpem@0 | 316 | wire [`LM32_CTYPE_RNG] D_CTI_O; |
philpem@0 | 317 | output D_LOCK_O; // Date Wishbone interface lock bus |
philpem@0 | 318 | wire D_LOCK_O; |
philpem@0 | 319 | output [`LM32_BTYPE_RNG] D_BTE_O; // Data Wishbone interface burst type |
philpem@0 | 320 | wire [`LM32_BTYPE_RNG] D_BTE_O; |
philpem@0 | 321 | |
philpem@0 | 322 | ///////////////////////////////////////////////////// |
philpem@0 | 323 | // Internal nets and registers |
philpem@0 | 324 | ///////////////////////////////////////////////////// |
philpem@0 | 325 | |
philpem@0 | 326 | // Pipeline registers |
philpem@0 | 327 | |
philpem@0 | 328 | `ifdef LM32_CACHE_ENABLED |
philpem@0 | 329 | reg valid_a; // Instruction in A stage is valid |
philpem@0 | 330 | `endif |
philpem@0 | 331 | reg valid_f; // Instruction in F stage is valid |
philpem@0 | 332 | reg valid_d; // Instruction in D stage is valid |
philpem@0 | 333 | reg valid_x; // Instruction in X stage is valid |
philpem@0 | 334 | reg valid_m; // Instruction in M stage is valid |
philpem@0 | 335 | reg valid_w; // Instruction in W stage is valid |
philpem@0 | 336 | |
philpem@0 | 337 | wire q_x; |
philpem@0 | 338 | wire [`LM32_WORD_RNG] immediate_d; // Immediate operand |
philpem@0 | 339 | wire load_d; // Indicates a load instruction |
philpem@0 | 340 | reg load_x; |
philpem@0 | 341 | reg load_m; |
philpem@0 | 342 | wire load_q_x; |
philpem@0 | 343 | wire store_q_x; |
philpem@0 | 344 | wire store_d; // Indicates a store instruction |
philpem@0 | 345 | reg store_x; |
philpem@0 | 346 | reg store_m; |
philpem@0 | 347 | wire [`LM32_SIZE_RNG] size_d; // Size of load/store (byte, hword, word) |
philpem@0 | 348 | reg [`LM32_SIZE_RNG] size_x; |
philpem@0 | 349 | wire branch_d; // Indicates a branch instruction |
philpem@0 | 350 | wire branch_predict_d; // Indicates a branch is predicted |
philpem@0 | 351 | wire branch_predict_taken_d; // Indicates a branch is predicted taken |
philpem@0 | 352 | wire [`LM32_PC_RNG] branch_predict_address_d; // Address to which predicted branch jumps |
philpem@0 | 353 | wire [`LM32_PC_RNG] branch_target_d; |
philpem@0 | 354 | wire bi_unconditional; |
philpem@0 | 355 | wire bi_conditional; |
philpem@0 | 356 | reg branch_x; |
philpem@0 | 357 | reg branch_predict_x; |
philpem@0 | 358 | reg branch_predict_taken_x; |
philpem@0 | 359 | reg branch_m; |
philpem@0 | 360 | reg branch_predict_m; |
philpem@0 | 361 | reg branch_predict_taken_m; |
philpem@0 | 362 | wire branch_mispredict_taken_m; // Indicates a branch was mispredicted as taken |
philpem@0 | 363 | wire branch_flushX_m; // Indicates that instruction in X stage must be squashed |
philpem@0 | 364 | wire branch_reg_d; // Branch to register or immediate |
philpem@0 | 365 | wire [`LM32_PC_RNG] branch_offset_d; // Branch offset for immediate branches |
philpem@0 | 366 | reg [`LM32_PC_RNG] branch_target_x; // Address to branch to |
philpem@0 | 367 | reg [`LM32_PC_RNG] branch_target_m; |
philpem@0 | 368 | wire [`LM32_D_RESULT_SEL_0_RNG] d_result_sel_0_d; // Which result should be selected in D stage for operand 0 |
philpem@0 | 369 | wire [`LM32_D_RESULT_SEL_1_RNG] d_result_sel_1_d; // Which result should be selected in D stage for operand 1 |
philpem@0 | 370 | |
philpem@0 | 371 | wire x_result_sel_csr_d; // Select X stage result from CSRs |
philpem@0 | 372 | reg x_result_sel_csr_x; |
philpem@0 | 373 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 374 | wire x_result_sel_mc_arith_d; // Select X stage result from multi-cycle arithmetic unit |
philpem@0 | 375 | reg x_result_sel_mc_arith_x; |
philpem@0 | 376 | `endif |
philpem@0 | 377 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 378 | wire x_result_sel_shift_d; // Select X stage result from shifter |
philpem@0 | 379 | reg x_result_sel_shift_x; |
philpem@0 | 380 | `endif |
philpem@0 | 381 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 382 | wire x_result_sel_sext_d; // Select X stage result from sign-extend logic |
philpem@0 | 383 | reg x_result_sel_sext_x; |
philpem@0 | 384 | `endif |
philpem@0 | 385 | wire x_result_sel_logic_d; // Select X stage result from logic op unit |
philpem@0 | 386 | reg x_result_sel_logic_x; |
philpem@0 | 387 | `ifdef CFG_USER_ENABLED |
philpem@0 | 388 | wire x_result_sel_user_d; // Select X stage result from user-defined logic |
philpem@0 | 389 | reg x_result_sel_user_x; |
philpem@0 | 390 | `endif |
philpem@0 | 391 | wire x_result_sel_add_d; // Select X stage result from adder |
philpem@0 | 392 | reg x_result_sel_add_x; |
philpem@0 | 393 | wire m_result_sel_compare_d; // Select M stage result from comparison logic |
philpem@0 | 394 | reg m_result_sel_compare_x; |
philpem@0 | 395 | reg m_result_sel_compare_m; |
philpem@0 | 396 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 397 | wire m_result_sel_shift_d; // Select M stage result from shifter |
philpem@0 | 398 | reg m_result_sel_shift_x; |
philpem@0 | 399 | reg m_result_sel_shift_m; |
philpem@0 | 400 | `endif |
philpem@0 | 401 | wire w_result_sel_load_d; // Select W stage result from load/store unit |
philpem@0 | 402 | reg w_result_sel_load_x; |
philpem@0 | 403 | reg w_result_sel_load_m; |
philpem@0 | 404 | reg w_result_sel_load_w; |
philpem@0 | 405 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 406 | wire w_result_sel_mul_d; // Select W stage result from multiplier |
philpem@0 | 407 | reg w_result_sel_mul_x; |
philpem@0 | 408 | reg w_result_sel_mul_m; |
philpem@0 | 409 | reg w_result_sel_mul_w; |
philpem@0 | 410 | `endif |
philpem@0 | 411 | wire x_bypass_enable_d; // Whether result is bypassable in X stage |
philpem@0 | 412 | reg x_bypass_enable_x; |
philpem@0 | 413 | wire m_bypass_enable_d; // Whether result is bypassable in M stage |
philpem@0 | 414 | reg m_bypass_enable_x; |
philpem@0 | 415 | reg m_bypass_enable_m; |
philpem@0 | 416 | wire sign_extend_d; // Whether to sign-extend or zero-extend |
philpem@0 | 417 | reg sign_extend_x; |
philpem@0 | 418 | wire write_enable_d; // Register file write enable |
philpem@0 | 419 | reg write_enable_x; |
philpem@0 | 420 | wire write_enable_q_x; |
philpem@0 | 421 | reg write_enable_m; |
philpem@0 | 422 | wire write_enable_q_m; |
philpem@0 | 423 | reg write_enable_w; |
philpem@0 | 424 | wire write_enable_q_w; |
philpem@0 | 425 | wire read_enable_0_d; // Register file read enable 0 |
philpem@0 | 426 | wire [`LM32_REG_IDX_RNG] read_idx_0_d; // Register file read index 0 |
philpem@0 | 427 | wire read_enable_1_d; // Register file read enable 1 |
philpem@0 | 428 | wire [`LM32_REG_IDX_RNG] read_idx_1_d; // Register file read index 1 |
philpem@0 | 429 | wire [`LM32_REG_IDX_RNG] write_idx_d; // Register file write index |
philpem@0 | 430 | reg [`LM32_REG_IDX_RNG] write_idx_x; |
philpem@0 | 431 | reg [`LM32_REG_IDX_RNG] write_idx_m; |
philpem@0 | 432 | reg [`LM32_REG_IDX_RNG] write_idx_w; |
philpem@0 | 433 | wire [`LM32_CSR_RNG] csr_d; // CSR read/write index |
philpem@0 | 434 | reg [`LM32_CSR_RNG] csr_x; |
philpem@0 | 435 | wire [`LM32_CONDITION_RNG] condition_d; // Branch condition |
philpem@0 | 436 | reg [`LM32_CONDITION_RNG] condition_x; |
philpem@0 | 437 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 438 | wire break_d; // Indicates a break instruction |
philpem@0 | 439 | reg break_x; |
philpem@0 | 440 | `endif |
philpem@0 | 441 | wire scall_d; // Indicates a scall instruction |
philpem@0 | 442 | reg scall_x; |
philpem@0 | 443 | wire eret_d; // Indicates an eret instruction |
philpem@0 | 444 | reg eret_x; |
philpem@0 | 445 | wire eret_q_x; |
philpem@0 | 446 | reg eret_m; |
philpem@0 | 447 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 448 | reg eret_w; |
philpem@0 | 449 | `endif |
philpem@0 | 450 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 451 | wire bret_d; // Indicates a bret instruction |
philpem@0 | 452 | reg bret_x; |
philpem@0 | 453 | wire bret_q_x; |
philpem@0 | 454 | reg bret_m; |
philpem@0 | 455 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 456 | reg bret_w; |
philpem@0 | 457 | `endif |
philpem@0 | 458 | `endif |
philpem@0 | 459 | wire csr_write_enable_d; // CSR write enable |
philpem@0 | 460 | reg csr_write_enable_x; |
philpem@0 | 461 | wire csr_write_enable_q_x; |
philpem@0 | 462 | `ifdef CFG_USER_ENABLED |
philpem@0 | 463 | wire [`LM32_USER_OPCODE_RNG] user_opcode_d; // User-defined instruction opcode |
philpem@0 | 464 | `endif |
philpem@0 | 465 | |
philpem@0 | 466 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 467 | wire bus_error_d; // Indicates an bus error occured while fetching the instruction in this pipeline stage |
philpem@0 | 468 | reg bus_error_x; |
philpem@0 | 469 | reg data_bus_error_exception_m; |
philpem@0 | 470 | reg [`LM32_PC_RNG] memop_pc_w; |
philpem@0 | 471 | `endif |
philpem@0 | 472 | |
philpem@0 | 473 | reg [`LM32_WORD_RNG] d_result_0; // Result of instruction in D stage (operand 0) |
philpem@0 | 474 | reg [`LM32_WORD_RNG] d_result_1; // Result of instruction in D stage (operand 1) |
philpem@0 | 475 | reg [`LM32_WORD_RNG] x_result; // Result of instruction in X stage |
philpem@0 | 476 | reg [`LM32_WORD_RNG] m_result; // Result of instruction in M stage |
philpem@0 | 477 | reg [`LM32_WORD_RNG] w_result; // Result of instruction in W stage |
philpem@0 | 478 | |
philpem@0 | 479 | reg [`LM32_WORD_RNG] operand_0_x; // Operand 0 for X stage instruction |
philpem@0 | 480 | reg [`LM32_WORD_RNG] operand_1_x; // Operand 1 for X stage instruction |
philpem@0 | 481 | reg [`LM32_WORD_RNG] store_operand_x; // Data read from register to store |
philpem@0 | 482 | reg [`LM32_WORD_RNG] operand_m; // Operand for M stage instruction |
philpem@0 | 483 | reg [`LM32_WORD_RNG] operand_w; // Operand for W stage instruction |
philpem@0 | 484 | |
philpem@0 | 485 | // To/from register file |
philpem@0 | 486 | `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
philpem@0 | 487 | reg [`LM32_WORD_RNG] reg_data_live_0; |
philpem@0 | 488 | reg [`LM32_WORD_RNG] reg_data_live_1; |
philpem@0 | 489 | reg use_buf; // Whether to use reg_data_live or reg_data_buf |
philpem@0 | 490 | reg [`LM32_WORD_RNG] reg_data_buf_0; |
philpem@0 | 491 | reg [`LM32_WORD_RNG] reg_data_buf_1; |
philpem@0 | 492 | `endif |
philpem@0 | 493 | `ifdef LM32_EBR_REGISTER_FILE |
philpem@0 | 494 | `else |
philpem@0 | 495 | reg [`LM32_WORD_RNG] registers[0:(1<<`LM32_REG_IDX_WIDTH)-1]; // Register file |
philpem@0 | 496 | `endif |
philpem@0 | 497 | wire [`LM32_WORD_RNG] reg_data_0; // Register file read port 0 data |
philpem@0 | 498 | wire [`LM32_WORD_RNG] reg_data_1; // Register file read port 1 data |
philpem@0 | 499 | reg [`LM32_WORD_RNG] bypass_data_0; // Register value 0 after bypassing |
philpem@0 | 500 | reg [`LM32_WORD_RNG] bypass_data_1; // Register value 1 after bypassing |
philpem@0 | 501 | wire reg_write_enable_q_w; |
philpem@0 | 502 | |
philpem@0 | 503 | reg interlock; // Indicates pipeline should be stalled because of a read-after-write hazzard |
philpem@0 | 504 | |
philpem@0 | 505 | wire stall_a; // Stall instruction in A pipeline stage |
philpem@0 | 506 | wire stall_f; // Stall instruction in F pipeline stage |
philpem@0 | 507 | wire stall_d; // Stall instruction in D pipeline stage |
philpem@0 | 508 | wire stall_x; // Stall instruction in X pipeline stage |
philpem@0 | 509 | wire stall_m; // Stall instruction in M pipeline stage |
philpem@0 | 510 | |
philpem@0 | 511 | // To/from adder |
philpem@0 | 512 | wire adder_op_d; // Whether to add or subtract |
philpem@0 | 513 | reg adder_op_x; |
philpem@0 | 514 | reg adder_op_x_n; // Inverted version of adder_op_x |
philpem@0 | 515 | wire [`LM32_WORD_RNG] adder_result_x; // Result from adder |
philpem@0 | 516 | wire adder_overflow_x; // Whether a signed overflow occured |
philpem@0 | 517 | wire adder_carry_n_x; // Whether a carry was generated |
philpem@0 | 518 | |
philpem@0 | 519 | // To/from logical operations unit |
philpem@0 | 520 | wire [`LM32_LOGIC_OP_RNG] logic_op_d; // Which operation to perform |
philpem@0 | 521 | reg [`LM32_LOGIC_OP_RNG] logic_op_x; |
philpem@0 | 522 | wire [`LM32_WORD_RNG] logic_result_x; // Result of logical operation |
philpem@0 | 523 | |
philpem@0 | 524 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 525 | // From sign-extension unit |
philpem@0 | 526 | wire [`LM32_WORD_RNG] sextb_result_x; // Result of byte sign-extension |
philpem@0 | 527 | wire [`LM32_WORD_RNG] sexth_result_x; // Result of half-word sign-extenstion |
philpem@0 | 528 | wire [`LM32_WORD_RNG] sext_result_x; // Result of sign-extension specified by instruction |
philpem@0 | 529 | `endif |
philpem@0 | 530 | |
philpem@0 | 531 | // To/from shifter |
philpem@0 | 532 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 533 | `ifdef CFG_ROTATE_ENABLED |
philpem@0 | 534 | wire rotate_d; // Whether we should rotate or shift |
philpem@0 | 535 | reg rotate_x; |
philpem@0 | 536 | `endif |
philpem@0 | 537 | wire direction_d; // Which direction to shift in |
philpem@0 | 538 | reg direction_x; |
philpem@0 | 539 | reg direction_m; |
philpem@0 | 540 | wire [`LM32_WORD_RNG] shifter_result_m; // Result of shifter |
philpem@0 | 541 | `endif |
philpem@0 | 542 | `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
philpem@0 | 543 | wire shift_left_d; // Indicates whether to perform a left shift or not |
philpem@0 | 544 | wire shift_left_q_d; |
philpem@0 | 545 | wire shift_right_d; // Indicates whether to perform a right shift or not |
philpem@0 | 546 | wire shift_right_q_d; |
philpem@0 | 547 | `endif |
philpem@0 | 548 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 549 | wire [`LM32_WORD_RNG] shifter_result_x; // Result of single-bit right shifter |
philpem@0 | 550 | `endif |
philpem@0 | 551 | |
philpem@0 | 552 | // To/from multiplier |
philpem@0 | 553 | `ifdef LM32_MULTIPLY_ENABLED |
philpem@0 | 554 | wire [`LM32_WORD_RNG] multiplier_result_w; // Result from multiplier |
philpem@0 | 555 | `endif |
philpem@0 | 556 | `ifdef CFG_MC_MULTIPLY_ENABLED |
philpem@0 | 557 | wire multiply_d; // Indicates whether to perform a multiply or not |
philpem@0 | 558 | wire multiply_q_d; |
philpem@0 | 559 | `endif |
philpem@0 | 560 | |
philpem@0 | 561 | // To/from divider |
philpem@0 | 562 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 563 | wire divide_d; // Indicates whether to perform a divider or not |
philpem@0 | 564 | wire divide_q_d; |
philpem@0 | 565 | wire modulus_d; |
philpem@0 | 566 | wire modulus_q_d; |
philpem@0 | 567 | wire divide_by_zero_x; // Indicates an attempt was made to divide by zero |
philpem@0 | 568 | `endif |
philpem@0 | 569 | |
philpem@0 | 570 | // To from multi-cycle arithmetic unit |
philpem@0 | 571 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 572 | wire mc_stall_request_x; // Multi-cycle arithmetic unit stall request |
philpem@0 | 573 | wire [`LM32_WORD_RNG] mc_result_x; |
philpem@0 | 574 | `endif |
philpem@0 | 575 | |
philpem@0 | 576 | // From CSRs |
philpem@0 | 577 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 578 | wire [`LM32_WORD_RNG] interrupt_csr_read_data_x;// Data read from interrupt CSRs |
philpem@0 | 579 | `endif |
philpem@0 | 580 | wire [`LM32_WORD_RNG] cfg; // Configuration CSR |
philpem@0 | 581 | wire [`LM32_WORD_RNG] cfg2; // Extended Configuration CSR |
philpem@0 | 582 | `ifdef CFG_CYCLE_COUNTER_ENABLED |
philpem@0 | 583 | reg [`LM32_WORD_RNG] cc; // Cycle counter CSR |
philpem@0 | 584 | `endif |
philpem@0 | 585 | reg [`LM32_WORD_RNG] csr_read_data_x; // Data read from CSRs |
philpem@0 | 586 | |
philpem@0 | 587 | // To/from instruction unit |
philpem@0 | 588 | wire [`LM32_PC_RNG] pc_f; // PC of instruction in F stage |
philpem@0 | 589 | wire [`LM32_PC_RNG] pc_d; // PC of instruction in D stage |
philpem@0 | 590 | wire [`LM32_PC_RNG] pc_x; // PC of instruction in X stage |
philpem@0 | 591 | wire [`LM32_PC_RNG] pc_m; // PC of instruction in M stage |
philpem@0 | 592 | wire [`LM32_PC_RNG] pc_w; // PC of instruction in W stage |
philpem@0 | 593 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 594 | reg [`LM32_PC_RNG] pc_c; // PC of last commited instruction |
philpem@0 | 595 | `endif |
philpem@0 | 596 | `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
philpem@0 | 597 | wire [`LM32_INSTRUCTION_RNG] instruction_f; // Instruction in F stage |
philpem@0 | 598 | `endif |
philpem@0 | 599 | //pragma attribute instruction_d preserve_signal true |
philpem@0 | 600 | //pragma attribute instruction_d preserve_driver true |
philpem@0 | 601 | wire [`LM32_INSTRUCTION_RNG] instruction_d; // Instruction in D stage |
philpem@0 | 602 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 603 | wire iflush; // Flush instruction cache |
philpem@0 | 604 | wire icache_stall_request; // Stall pipeline because instruction cache is busy |
philpem@0 | 605 | wire icache_restart_request; // Restart instruction that caused an instruction cache miss |
philpem@0 | 606 | wire icache_refill_request; // Request to refill instruction cache |
philpem@0 | 607 | wire icache_refilling; // Indicates the instruction cache is being refilled |
philpem@0 | 608 | `endif |
philpem@0 | 609 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 610 | wire [`LM32_WORD_RNG] irom_store_data_m; // Store data to instruction ROM |
philpem@0 | 611 | wire [`LM32_WORD_RNG] irom_address_xm; // Address to instruction ROM from load-store unit |
philpem@0 | 612 | wire [`LM32_WORD_RNG] irom_data_m; // Load data from instruction ROM |
philpem@0 | 613 | wire irom_we_xm; // Indicates data needs to be written to instruction ROM |
philpem@0 | 614 | wire irom_stall_request_x; // Indicates D stage needs to be stalled on a store to instruction ROM |
philpem@0 | 615 | `endif |
philpem@0 | 616 | |
philpem@0 | 617 | // To/from load/store unit |
philpem@0 | 618 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 619 | wire dflush_x; // Flush data cache |
philpem@0 | 620 | reg dflush_m; |
philpem@0 | 621 | wire dcache_stall_request; // Stall pipeline because data cache is busy |
philpem@0 | 622 | wire dcache_restart_request; // Restart instruction that caused a data cache miss |
philpem@0 | 623 | wire dcache_refill_request; // Request to refill data cache |
philpem@0 | 624 | wire dcache_refilling; // Indicates the data cache is being refilled |
philpem@0 | 625 | `endif |
philpem@0 | 626 | wire [`LM32_WORD_RNG] load_data_w; // Result of a load instruction |
philpem@0 | 627 | wire stall_wb_load; // Stall pipeline because of a load via the data Wishbone interface |
philpem@0 | 628 | |
philpem@0 | 629 | // To/from JTAG interface |
philpem@0 | 630 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 631 | `ifdef CFG_JTAG_UART_ENABLED |
philpem@0 | 632 | wire [`LM32_WORD_RNG] jtx_csr_read_data; // Read data for JTX CSR |
philpem@0 | 633 | wire [`LM32_WORD_RNG] jrx_csr_read_data; // Read data for JRX CSR |
philpem@0 | 634 | `endif |
philpem@0 | 635 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 636 | wire jtag_csr_write_enable; // Debugger CSR write enable |
philpem@0 | 637 | wire [`LM32_WORD_RNG] jtag_csr_write_data; // Data to write to specified CSR |
philpem@0 | 638 | wire [`LM32_CSR_RNG] jtag_csr; // Which CSR to write |
philpem@0 | 639 | wire jtag_read_enable; |
philpem@0 | 640 | wire [`LM32_BYTE_RNG] jtag_read_data; |
philpem@0 | 641 | wire jtag_write_enable; |
philpem@0 | 642 | wire [`LM32_BYTE_RNG] jtag_write_data; |
philpem@0 | 643 | wire [`LM32_WORD_RNG] jtag_address; |
philpem@0 | 644 | wire jtag_access_complete; |
philpem@0 | 645 | `endif |
philpem@0 | 646 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 647 | wire jtag_break; // Request from debugger to raise a breakpoint |
philpem@0 | 648 | `endif |
philpem@0 | 649 | `endif |
philpem@0 | 650 | |
philpem@0 | 651 | // Hazzard detection |
philpem@0 | 652 | wire raw_x_0; // RAW hazzard between instruction in X stage and read port 0 |
philpem@0 | 653 | wire raw_x_1; // RAW hazzard between instruction in X stage and read port 1 |
philpem@0 | 654 | wire raw_m_0; // RAW hazzard between instruction in M stage and read port 0 |
philpem@0 | 655 | wire raw_m_1; // RAW hazzard between instruction in M stage and read port 1 |
philpem@0 | 656 | wire raw_w_0; // RAW hazzard between instruction in W stage and read port 0 |
philpem@0 | 657 | wire raw_w_1; // RAW hazzard between instruction in W stage and read port 1 |
philpem@0 | 658 | |
philpem@0 | 659 | // Control flow |
philpem@0 | 660 | wire cmp_zero; // Result of comparison is zero |
philpem@0 | 661 | wire cmp_negative; // Result of comparison is negative |
philpem@0 | 662 | wire cmp_overflow; // Comparison produced an overflow |
philpem@0 | 663 | wire cmp_carry_n; // Comparison produced a carry, inverted |
philpem@0 | 664 | reg condition_met_x; // Condition of branch instruction is met |
philpem@0 | 665 | reg condition_met_m; |
philpem@0 | 666 | `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
philpem@0 | 667 | wire branch_taken_x; // Branch is taken in X stage |
philpem@0 | 668 | `endif |
philpem@0 | 669 | wire branch_taken_m; // Branch is taken in M stage |
philpem@0 | 670 | |
philpem@0 | 671 | wire kill_f; // Kill instruction in F stage |
philpem@0 | 672 | wire kill_d; // Kill instruction in D stage |
philpem@0 | 673 | wire kill_x; // Kill instruction in X stage |
philpem@0 | 674 | wire kill_m; // Kill instruction in M stage |
philpem@0 | 675 | wire kill_w; // Kill instruction in W stage |
philpem@0 | 676 | |
philpem@0 | 677 | reg [`LM32_PC_WIDTH+2-1:8] eba; // Exception Base Address (EBA) CSR |
philpem@0 | 678 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 679 | reg [`LM32_PC_WIDTH+2-1:8] deba; // Debug Exception Base Address (DEBA) CSR |
philpem@0 | 680 | `endif |
philpem@0 | 681 | reg [`LM32_EID_RNG] eid_x; // Exception ID in X stage |
philpem@0 | 682 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 683 | reg [`LM32_EID_RNG] eid_m; // Exception ID in M stage |
philpem@0 | 684 | reg [`LM32_EID_RNG] eid_w; // Exception ID in W stage |
philpem@0 | 685 | `endif |
philpem@0 | 686 | |
philpem@0 | 687 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 688 | `ifdef LM32_SINGLE_STEP_ENABLED |
philpem@0 | 689 | wire dc_ss; // Is single-step enabled |
philpem@0 | 690 | `endif |
philpem@0 | 691 | wire dc_re; // Remap all exceptions |
philpem@0 | 692 | wire exception_x; // An exception occured in the X stage |
philpem@0 | 693 | reg exception_m; // An instruction that caused an exception is in the M stage |
philpem@0 | 694 | wire debug_exception_x; // Indicates if a debug exception has occured |
philpem@0 | 695 | reg debug_exception_m; |
philpem@0 | 696 | reg debug_exception_w; |
philpem@0 | 697 | wire debug_exception_q_w; |
philpem@0 | 698 | wire non_debug_exception_x; // Indicates if a non debug exception has occured |
philpem@0 | 699 | reg non_debug_exception_m; |
philpem@0 | 700 | reg non_debug_exception_w; |
philpem@0 | 701 | wire non_debug_exception_q_w; |
philpem@0 | 702 | `else |
philpem@0 | 703 | wire exception_x; // Indicates if a debug exception has occured |
philpem@0 | 704 | reg exception_m; |
philpem@0 | 705 | reg exception_w; |
philpem@0 | 706 | wire exception_q_w; |
philpem@0 | 707 | `endif |
philpem@0 | 708 | |
philpem@0 | 709 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 710 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 711 | wire reset_exception; // Indicates if a reset exception has occured |
philpem@0 | 712 | `endif |
philpem@0 | 713 | `endif |
philpem@0 | 714 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 715 | wire interrupt_exception; // Indicates if an interrupt exception has occured |
philpem@0 | 716 | `endif |
philpem@0 | 717 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 718 | wire breakpoint_exception; // Indicates if a breakpoint exception has occured |
philpem@0 | 719 | wire watchpoint_exception; // Indicates if a watchpoint exception has occured |
philpem@0 | 720 | `endif |
philpem@0 | 721 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 722 | wire instruction_bus_error_exception; // Indicates if an instruction bus error exception has occured |
philpem@0 | 723 | wire data_bus_error_exception; // Indicates if a data bus error exception has occured |
philpem@0 | 724 | `endif |
philpem@0 | 725 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 726 | wire divide_by_zero_exception; // Indicates if a divide by zero exception has occured |
philpem@0 | 727 | `endif |
philpem@0 | 728 | wire system_call_exception; // Indicates if a system call exception has occured |
philpem@0 | 729 | |
philpem@0 | 730 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 731 | reg data_bus_error_seen; // Indicates if a data bus error was seen |
philpem@0 | 732 | `endif |
philpem@0 | 733 | |
philpem@0 | 734 | ///////////////////////////////////////////////////// |
philpem@0 | 735 | // Functions |
philpem@0 | 736 | ///////////////////////////////////////////////////// |
philpem@0 | 737 | |
philpem@0 | 738 | `include "lm32_functions.v" |
philpem@0 | 739 | |
philpem@0 | 740 | ///////////////////////////////////////////////////// |
philpem@0 | 741 | // Instantiations |
philpem@0 | 742 | ///////////////////////////////////////////////////// |
philpem@0 | 743 | |
philpem@0 | 744 | // Instruction unit |
philpem@0 | 745 | lm32_instruction_unit #( |
philpem@0 | 746 | .associativity (icache_associativity), |
philpem@0 | 747 | .sets (icache_sets), |
philpem@0 | 748 | .bytes_per_line (icache_bytes_per_line), |
philpem@0 | 749 | .base_address (icache_base_address), |
philpem@0 | 750 | .limit (icache_limit) |
philpem@0 | 751 | ) instruction_unit ( |
philpem@0 | 752 | // ----- Inputs ------- |
philpem@0 | 753 | .clk_i (clk_i), |
philpem@0 | 754 | .rst_i (rst_i), |
philpem@0 | 755 | // From pipeline |
philpem@0 | 756 | .stall_a (stall_a), |
philpem@0 | 757 | .stall_f (stall_f), |
philpem@0 | 758 | .stall_d (stall_d), |
philpem@0 | 759 | .stall_x (stall_x), |
philpem@0 | 760 | .stall_m (stall_m), |
philpem@0 | 761 | .valid_f (valid_f), |
philpem@0 | 762 | .valid_d (valid_d), |
philpem@0 | 763 | .kill_f (kill_f), |
philpem@0 | 764 | .branch_predict_taken_d (branch_predict_taken_d), |
philpem@0 | 765 | .branch_predict_address_d (branch_predict_address_d), |
philpem@0 | 766 | `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
philpem@0 | 767 | .branch_taken_x (branch_taken_x), |
philpem@0 | 768 | .branch_target_x (branch_target_x), |
philpem@0 | 769 | `endif |
philpem@0 | 770 | .exception_m (exception_m), |
philpem@0 | 771 | .branch_taken_m (branch_taken_m), |
philpem@0 | 772 | .branch_mispredict_taken_m (branch_mispredict_taken_m), |
philpem@0 | 773 | .branch_target_m (branch_target_m), |
philpem@0 | 774 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 775 | .iflush (iflush), |
philpem@0 | 776 | `endif |
philpem@0 | 777 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 778 | .irom_store_data_m (irom_store_data_m), |
philpem@0 | 779 | .irom_address_xm (irom_address_xm), |
philpem@0 | 780 | .irom_we_xm (irom_we_xm), |
philpem@0 | 781 | `endif |
philpem@0 | 782 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 783 | .dcache_restart_request (dcache_restart_request), |
philpem@0 | 784 | .dcache_refill_request (dcache_refill_request), |
philpem@0 | 785 | .dcache_refilling (dcache_refilling), |
philpem@0 | 786 | `endif |
philpem@0 | 787 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 788 | // From Wishbone |
philpem@0 | 789 | .i_dat_i (I_DAT_I), |
philpem@0 | 790 | .i_ack_i (I_ACK_I), |
philpem@0 | 791 | .i_err_i (I_ERR_I), |
philpem@0 | 792 | .i_rty_i (I_RTY_I), |
philpem@0 | 793 | `endif |
philpem@0 | 794 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 795 | .jtag_read_enable (jtag_read_enable), |
philpem@0 | 796 | .jtag_write_enable (jtag_write_enable), |
philpem@0 | 797 | .jtag_write_data (jtag_write_data), |
philpem@0 | 798 | .jtag_address (jtag_address), |
philpem@0 | 799 | `endif |
philpem@0 | 800 | // ----- Outputs ------- |
philpem@0 | 801 | // To pipeline |
philpem@0 | 802 | .pc_f (pc_f), |
philpem@0 | 803 | .pc_d (pc_d), |
philpem@0 | 804 | .pc_x (pc_x), |
philpem@0 | 805 | .pc_m (pc_m), |
philpem@0 | 806 | .pc_w (pc_w), |
philpem@0 | 807 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 808 | .icache_stall_request (icache_stall_request), |
philpem@0 | 809 | .icache_restart_request (icache_restart_request), |
philpem@0 | 810 | .icache_refill_request (icache_refill_request), |
philpem@0 | 811 | .icache_refilling (icache_refilling), |
philpem@0 | 812 | `endif |
philpem@0 | 813 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 814 | .irom_data_m (irom_data_m), |
philpem@0 | 815 | `endif |
philpem@0 | 816 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 817 | // To Wishbone |
philpem@0 | 818 | .i_dat_o (I_DAT_O), |
philpem@0 | 819 | .i_adr_o (I_ADR_O), |
philpem@0 | 820 | .i_cyc_o (I_CYC_O), |
philpem@0 | 821 | .i_sel_o (I_SEL_O), |
philpem@0 | 822 | .i_stb_o (I_STB_O), |
philpem@0 | 823 | .i_we_o (I_WE_O), |
philpem@0 | 824 | .i_cti_o (I_CTI_O), |
philpem@0 | 825 | .i_lock_o (I_LOCK_O), |
philpem@0 | 826 | .i_bte_o (I_BTE_O), |
philpem@0 | 827 | `endif |
philpem@0 | 828 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 829 | .jtag_read_data (jtag_read_data), |
philpem@0 | 830 | .jtag_access_complete (jtag_access_complete), |
philpem@0 | 831 | `endif |
philpem@0 | 832 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 833 | .bus_error_d (bus_error_d), |
philpem@0 | 834 | `endif |
philpem@0 | 835 | `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
philpem@0 | 836 | .instruction_f (instruction_f), |
philpem@0 | 837 | `endif |
philpem@0 | 838 | .instruction_d (instruction_d) |
philpem@0 | 839 | ); |
philpem@0 | 840 | |
philpem@0 | 841 | // Instruction decoder |
philpem@0 | 842 | lm32_decoder decoder ( |
philpem@0 | 843 | // ----- Inputs ------- |
philpem@0 | 844 | .instruction (instruction_d), |
philpem@0 | 845 | // ----- Outputs ------- |
philpem@0 | 846 | .d_result_sel_0 (d_result_sel_0_d), |
philpem@0 | 847 | .d_result_sel_1 (d_result_sel_1_d), |
philpem@0 | 848 | .x_result_sel_csr (x_result_sel_csr_d), |
philpem@0 | 849 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 850 | .x_result_sel_mc_arith (x_result_sel_mc_arith_d), |
philpem@0 | 851 | `endif |
philpem@0 | 852 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 853 | .x_result_sel_shift (x_result_sel_shift_d), |
philpem@0 | 854 | `endif |
philpem@0 | 855 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 856 | .x_result_sel_sext (x_result_sel_sext_d), |
philpem@0 | 857 | `endif |
philpem@0 | 858 | .x_result_sel_logic (x_result_sel_logic_d), |
philpem@0 | 859 | `ifdef CFG_USER_ENABLED |
philpem@0 | 860 | .x_result_sel_user (x_result_sel_user_d), |
philpem@0 | 861 | `endif |
philpem@0 | 862 | .x_result_sel_add (x_result_sel_add_d), |
philpem@0 | 863 | .m_result_sel_compare (m_result_sel_compare_d), |
philpem@0 | 864 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 865 | .m_result_sel_shift (m_result_sel_shift_d), |
philpem@0 | 866 | `endif |
philpem@0 | 867 | .w_result_sel_load (w_result_sel_load_d), |
philpem@0 | 868 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 869 | .w_result_sel_mul (w_result_sel_mul_d), |
philpem@0 | 870 | `endif |
philpem@0 | 871 | .x_bypass_enable (x_bypass_enable_d), |
philpem@0 | 872 | .m_bypass_enable (m_bypass_enable_d), |
philpem@0 | 873 | .read_enable_0 (read_enable_0_d), |
philpem@0 | 874 | .read_idx_0 (read_idx_0_d), |
philpem@0 | 875 | .read_enable_1 (read_enable_1_d), |
philpem@0 | 876 | .read_idx_1 (read_idx_1_d), |
philpem@0 | 877 | .write_enable (write_enable_d), |
philpem@0 | 878 | .write_idx (write_idx_d), |
philpem@0 | 879 | .immediate (immediate_d), |
philpem@0 | 880 | .branch_offset (branch_offset_d), |
philpem@0 | 881 | .load (load_d), |
philpem@0 | 882 | .store (store_d), |
philpem@0 | 883 | .size (size_d), |
philpem@0 | 884 | .sign_extend (sign_extend_d), |
philpem@0 | 885 | .adder_op (adder_op_d), |
philpem@0 | 886 | .logic_op (logic_op_d), |
philpem@0 | 887 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 888 | .direction (direction_d), |
philpem@0 | 889 | `endif |
philpem@0 | 890 | `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
philpem@0 | 891 | .shift_left (shift_left_d), |
philpem@0 | 892 | .shift_right (shift_right_d), |
philpem@0 | 893 | `endif |
philpem@0 | 894 | `ifdef CFG_MC_MULTIPLY_ENABLED |
philpem@0 | 895 | .multiply (multiply_d), |
philpem@0 | 896 | `endif |
philpem@0 | 897 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 898 | .divide (divide_d), |
philpem@0 | 899 | .modulus (modulus_d), |
philpem@0 | 900 | `endif |
philpem@0 | 901 | .branch (branch_d), |
philpem@0 | 902 | .bi_unconditional (bi_unconditional), |
philpem@0 | 903 | .bi_conditional (bi_conditional), |
philpem@0 | 904 | .branch_reg (branch_reg_d), |
philpem@0 | 905 | .condition (condition_d), |
philpem@0 | 906 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 907 | .break_opcode (break_d), |
philpem@0 | 908 | `endif |
philpem@0 | 909 | .scall (scall_d), |
philpem@0 | 910 | .eret (eret_d), |
philpem@0 | 911 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 912 | .bret (bret_d), |
philpem@0 | 913 | `endif |
philpem@0 | 914 | `ifdef CFG_USER_ENABLED |
philpem@0 | 915 | .user_opcode (user_opcode_d), |
philpem@0 | 916 | `endif |
philpem@0 | 917 | .csr_write_enable (csr_write_enable_d) |
philpem@0 | 918 | ); |
philpem@0 | 919 | |
philpem@0 | 920 | // Load/store unit |
philpem@0 | 921 | lm32_load_store_unit #( |
philpem@0 | 922 | .associativity (dcache_associativity), |
philpem@0 | 923 | .sets (dcache_sets), |
philpem@0 | 924 | .bytes_per_line (dcache_bytes_per_line), |
philpem@0 | 925 | .base_address (dcache_base_address), |
philpem@0 | 926 | .limit (dcache_limit) |
philpem@0 | 927 | ) load_store_unit ( |
philpem@0 | 928 | // ----- Inputs ------- |
philpem@0 | 929 | .clk_i (clk_i), |
philpem@0 | 930 | .rst_i (rst_i), |
philpem@0 | 931 | // From pipeline |
philpem@0 | 932 | .stall_a (stall_a), |
philpem@0 | 933 | .stall_x (stall_x), |
philpem@0 | 934 | .stall_m (stall_m), |
philpem@0 | 935 | .kill_x (kill_x), |
philpem@0 | 936 | .kill_m (kill_m), |
philpem@0 | 937 | .exception_m (exception_m), |
philpem@0 | 938 | .store_operand_x (store_operand_x), |
philpem@0 | 939 | .load_store_address_x (adder_result_x), |
philpem@0 | 940 | .load_store_address_m (operand_m), |
philpem@0 | 941 | .load_store_address_w (operand_w[1:0]), |
philpem@0 | 942 | .load_x (load_x), |
philpem@0 | 943 | .store_x (store_x), |
philpem@0 | 944 | .load_q_x (load_q_x), |
philpem@0 | 945 | .store_q_x (store_q_x), |
philpem@0 | 946 | .load_q_m (load_q_m), |
philpem@0 | 947 | .store_q_m (store_q_m), |
philpem@0 | 948 | .sign_extend_x (sign_extend_x), |
philpem@0 | 949 | .size_x (size_x), |
philpem@0 | 950 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 951 | .dflush (dflush_m), |
philpem@0 | 952 | `endif |
philpem@0 | 953 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 954 | .irom_data_m (irom_data_m), |
philpem@0 | 955 | `endif |
philpem@0 | 956 | // From Wishbone |
philpem@0 | 957 | .d_dat_i (D_DAT_I), |
philpem@0 | 958 | .d_ack_i (D_ACK_I), |
philpem@0 | 959 | .d_err_i (D_ERR_I), |
philpem@0 | 960 | .d_rty_i (D_RTY_I), |
philpem@0 | 961 | // ----- Outputs ------- |
philpem@0 | 962 | // To pipeline |
philpem@0 | 963 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 964 | .dcache_refill_request (dcache_refill_request), |
philpem@0 | 965 | .dcache_restart_request (dcache_restart_request), |
philpem@0 | 966 | .dcache_stall_request (dcache_stall_request), |
philpem@0 | 967 | .dcache_refilling (dcache_refilling), |
philpem@0 | 968 | `endif |
philpem@0 | 969 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 970 | .irom_store_data_m (irom_store_data_m), |
philpem@0 | 971 | .irom_address_xm (irom_address_xm), |
philpem@0 | 972 | .irom_we_xm (irom_we_xm), |
philpem@0 | 973 | .irom_stall_request_x (irom_stall_request_x), |
philpem@0 | 974 | `endif |
philpem@0 | 975 | .load_data_w (load_data_w), |
philpem@0 | 976 | .stall_wb_load (stall_wb_load), |
philpem@0 | 977 | // To Wishbone |
philpem@0 | 978 | .d_dat_o (D_DAT_O), |
philpem@0 | 979 | .d_adr_o (D_ADR_O), |
philpem@0 | 980 | .d_cyc_o (D_CYC_O), |
philpem@0 | 981 | .d_sel_o (D_SEL_O), |
philpem@0 | 982 | .d_stb_o (D_STB_O), |
philpem@0 | 983 | .d_we_o (D_WE_O), |
philpem@0 | 984 | .d_cti_o (D_CTI_O), |
philpem@0 | 985 | .d_lock_o (D_LOCK_O), |
philpem@0 | 986 | .d_bte_o (D_BTE_O) |
philpem@0 | 987 | ); |
philpem@0 | 988 | |
philpem@0 | 989 | // Adder |
philpem@0 | 990 | lm32_adder adder ( |
philpem@0 | 991 | // ----- Inputs ------- |
philpem@0 | 992 | .adder_op_x (adder_op_x), |
philpem@0 | 993 | .adder_op_x_n (adder_op_x_n), |
philpem@0 | 994 | .operand_0_x (operand_0_x), |
philpem@0 | 995 | .operand_1_x (operand_1_x), |
philpem@0 | 996 | // ----- Outputs ------- |
philpem@0 | 997 | .adder_result_x (adder_result_x), |
philpem@0 | 998 | .adder_carry_n_x (adder_carry_n_x), |
philpem@0 | 999 | .adder_overflow_x (adder_overflow_x) |
philpem@0 | 1000 | ); |
philpem@0 | 1001 | |
philpem@0 | 1002 | // Logic operations |
philpem@0 | 1003 | lm32_logic_op logic_op ( |
philpem@0 | 1004 | // ----- Inputs ------- |
philpem@0 | 1005 | .logic_op_x (logic_op_x), |
philpem@0 | 1006 | .operand_0_x (operand_0_x), |
philpem@0 | 1007 | |
philpem@0 | 1008 | .operand_1_x (operand_1_x), |
philpem@0 | 1009 | // ----- Outputs ------- |
philpem@0 | 1010 | .logic_result_x (logic_result_x) |
philpem@0 | 1011 | ); |
philpem@0 | 1012 | |
philpem@0 | 1013 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 1014 | // Pipelined barrel-shifter |
philpem@0 | 1015 | lm32_shifter shifter ( |
philpem@0 | 1016 | // ----- Inputs ------- |
philpem@0 | 1017 | .clk_i (clk_i), |
philpem@0 | 1018 | .rst_i (rst_i), |
philpem@0 | 1019 | .stall_x (stall_x), |
philpem@0 | 1020 | .direction_x (direction_x), |
philpem@0 | 1021 | .sign_extend_x (sign_extend_x), |
philpem@0 | 1022 | .operand_0_x (operand_0_x), |
philpem@0 | 1023 | .operand_1_x (operand_1_x), |
philpem@0 | 1024 | // ----- Outputs ------- |
philpem@0 | 1025 | .shifter_result_m (shifter_result_m) |
philpem@0 | 1026 | ); |
philpem@0 | 1027 | `endif |
philpem@0 | 1028 | |
philpem@0 | 1029 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 1030 | // Pipeline fixed-point multiplier |
philpem@0 | 1031 | lm32_multiplier multiplier ( |
philpem@0 | 1032 | // ----- Inputs ------- |
philpem@0 | 1033 | .clk_i (clk_i), |
philpem@0 | 1034 | .rst_i (rst_i), |
philpem@0 | 1035 | .stall_x (stall_x), |
philpem@0 | 1036 | .stall_m (stall_m), |
philpem@0 | 1037 | .operand_0 (d_result_0), |
philpem@0 | 1038 | .operand_1 (d_result_1), |
philpem@0 | 1039 | // ----- Outputs ------- |
philpem@0 | 1040 | .result (multiplier_result_w) |
philpem@0 | 1041 | ); |
philpem@0 | 1042 | `endif |
philpem@0 | 1043 | |
philpem@0 | 1044 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 1045 | // Multi-cycle arithmetic |
philpem@0 | 1046 | lm32_mc_arithmetic mc_arithmetic ( |
philpem@0 | 1047 | // ----- Inputs ------- |
philpem@0 | 1048 | .clk_i (clk_i), |
philpem@0 | 1049 | .rst_i (rst_i), |
philpem@0 | 1050 | .stall_d (stall_d), |
philpem@0 | 1051 | .kill_x (kill_x), |
philpem@0 | 1052 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1053 | .divide_d (divide_q_d), |
philpem@0 | 1054 | .modulus_d (modulus_q_d), |
philpem@0 | 1055 | `endif |
philpem@0 | 1056 | `ifdef CFG_MC_MULTIPLY_ENABLED |
philpem@0 | 1057 | .multiply_d (multiply_q_d), |
philpem@0 | 1058 | `endif |
philpem@0 | 1059 | `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
philpem@0 | 1060 | .shift_left_d (shift_left_q_d), |
philpem@0 | 1061 | .shift_right_d (shift_right_q_d), |
philpem@0 | 1062 | .sign_extend_d (sign_extend_d), |
philpem@0 | 1063 | `endif |
philpem@0 | 1064 | .operand_0_d (d_result_0), |
philpem@0 | 1065 | .operand_1_d (d_result_1), |
philpem@0 | 1066 | // ----- Outputs ------- |
philpem@0 | 1067 | .result_x (mc_result_x), |
philpem@0 | 1068 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1069 | .divide_by_zero_x (divide_by_zero_x), |
philpem@0 | 1070 | `endif |
philpem@0 | 1071 | .stall_request_x (mc_stall_request_x) |
philpem@0 | 1072 | ); |
philpem@0 | 1073 | `endif |
philpem@0 | 1074 | |
philpem@0 | 1075 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 1076 | // Interrupt unit |
philpem@0 | 1077 | lm32_interrupt interrupt ( |
philpem@0 | 1078 | // ----- Inputs ------- |
philpem@0 | 1079 | .clk_i (clk_i), |
philpem@0 | 1080 | .rst_i (rst_i), |
philpem@0 | 1081 | // From external devices |
philpem@0 | 1082 | .interrupt_n (interrupt_n), |
philpem@0 | 1083 | // From pipeline |
philpem@0 | 1084 | .stall_x (stall_x), |
philpem@0 | 1085 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1086 | .non_debug_exception (non_debug_exception_q_w), |
philpem@0 | 1087 | .debug_exception (debug_exception_q_w), |
philpem@0 | 1088 | `else |
philpem@0 | 1089 | .exception (exception_q_w), |
philpem@0 | 1090 | `endif |
philpem@0 | 1091 | .eret_q_x (eret_q_x), |
philpem@0 | 1092 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1093 | .bret_q_x (bret_q_x), |
philpem@0 | 1094 | `endif |
philpem@0 | 1095 | .csr (csr_x), |
philpem@0 | 1096 | .csr_write_data (operand_1_x), |
philpem@0 | 1097 | .csr_write_enable (csr_write_enable_q_x), |
philpem@0 | 1098 | // ----- Outputs ------- |
philpem@0 | 1099 | .interrupt_exception (interrupt_exception), |
philpem@0 | 1100 | // To pipeline |
philpem@0 | 1101 | .csr_read_data (interrupt_csr_read_data_x) |
philpem@0 | 1102 | ); |
philpem@0 | 1103 | `endif |
philpem@0 | 1104 | |
philpem@0 | 1105 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 1106 | // JTAG interface |
philpem@0 | 1107 | lm32_jtag jtag ( |
philpem@0 | 1108 | // ----- Inputs ------- |
philpem@0 | 1109 | .clk_i (clk_i), |
philpem@0 | 1110 | .rst_i (rst_i), |
philpem@0 | 1111 | // From JTAG |
philpem@0 | 1112 | .jtag_clk (jtag_clk), |
philpem@0 | 1113 | .jtag_update (jtag_update), |
philpem@0 | 1114 | .jtag_reg_q (jtag_reg_q), |
philpem@0 | 1115 | .jtag_reg_addr_q (jtag_reg_addr_q), |
philpem@0 | 1116 | // From pipeline |
philpem@0 | 1117 | `ifdef CFG_JTAG_UART_ENABLED |
philpem@0 | 1118 | .csr (csr_x), |
philpem@0 | 1119 | .csr_write_data (operand_1_x), |
philpem@0 | 1120 | .csr_write_enable (csr_write_enable_q_x), |
philpem@0 | 1121 | .stall_x (stall_x), |
philpem@0 | 1122 | `endif |
philpem@0 | 1123 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 1124 | .jtag_read_data (jtag_read_data), |
philpem@0 | 1125 | .jtag_access_complete (jtag_access_complete), |
philpem@0 | 1126 | `endif |
philpem@0 | 1127 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1128 | .exception_q_w (debug_exception_q_w || non_debug_exception_q_w), |
philpem@0 | 1129 | `endif |
philpem@0 | 1130 | // ----- Outputs ------- |
philpem@0 | 1131 | // To pipeline |
philpem@0 | 1132 | `ifdef CFG_JTAG_UART_ENABLED |
philpem@0 | 1133 | .jtx_csr_read_data (jtx_csr_read_data), |
philpem@0 | 1134 | .jrx_csr_read_data (jrx_csr_read_data), |
philpem@0 | 1135 | `endif |
philpem@0 | 1136 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 1137 | .jtag_csr_write_enable (jtag_csr_write_enable), |
philpem@0 | 1138 | .jtag_csr_write_data (jtag_csr_write_data), |
philpem@0 | 1139 | .jtag_csr (jtag_csr), |
philpem@0 | 1140 | .jtag_read_enable (jtag_read_enable), |
philpem@0 | 1141 | .jtag_write_enable (jtag_write_enable), |
philpem@0 | 1142 | .jtag_write_data (jtag_write_data), |
philpem@0 | 1143 | .jtag_address (jtag_address), |
philpem@0 | 1144 | `endif |
philpem@0 | 1145 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1146 | .jtag_break (jtag_break), |
philpem@0 | 1147 | .jtag_reset (reset_exception), |
philpem@0 | 1148 | `endif |
philpem@0 | 1149 | // To JTAG |
philpem@0 | 1150 | .jtag_reg_d (jtag_reg_d), |
philpem@0 | 1151 | .jtag_reg_addr_d (jtag_reg_addr_d) |
philpem@0 | 1152 | ); |
philpem@0 | 1153 | `endif |
philpem@0 | 1154 | |
philpem@0 | 1155 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1156 | // Debug unit |
philpem@0 | 1157 | lm32_debug #( |
philpem@0 | 1158 | .breakpoints (breakpoints), |
philpem@0 | 1159 | .watchpoints (watchpoints) |
philpem@0 | 1160 | ) hw_debug ( |
philpem@0 | 1161 | // ----- Inputs ------- |
philpem@0 | 1162 | .clk_i (clk_i), |
philpem@0 | 1163 | .rst_i (rst_i), |
philpem@0 | 1164 | .pc_x (pc_x), |
philpem@0 | 1165 | .load_x (load_x), |
philpem@0 | 1166 | .store_x (store_x), |
philpem@0 | 1167 | .load_store_address_x (adder_result_x), |
philpem@0 | 1168 | .csr_write_enable_x (csr_write_enable_q_x), |
philpem@0 | 1169 | .csr_write_data (operand_1_x), |
philpem@0 | 1170 | .csr_x (csr_x), |
philpem@0 | 1171 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 1172 | .jtag_csr_write_enable (jtag_csr_write_enable), |
philpem@0 | 1173 | .jtag_csr_write_data (jtag_csr_write_data), |
philpem@0 | 1174 | .jtag_csr (jtag_csr), |
philpem@0 | 1175 | `endif |
philpem@0 | 1176 | `ifdef LM32_SINGLE_STEP_ENABLED |
philpem@0 | 1177 | .eret_q_x (eret_q_x), |
philpem@0 | 1178 | .bret_q_x (bret_q_x), |
philpem@0 | 1179 | .stall_x (stall_x), |
philpem@0 | 1180 | .exception_x (exception_x), |
philpem@0 | 1181 | .q_x (q_x), |
philpem@0 | 1182 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1183 | .dcache_refill_request (dcache_refill_request), |
philpem@0 | 1184 | `endif |
philpem@0 | 1185 | `endif |
philpem@0 | 1186 | // ----- Outputs ------- |
philpem@0 | 1187 | `ifdef LM32_SINGLE_STEP_ENABLED |
philpem@0 | 1188 | .dc_ss (dc_ss), |
philpem@0 | 1189 | `endif |
philpem@0 | 1190 | .dc_re (dc_re), |
philpem@0 | 1191 | .bp_match (bp_match), |
philpem@0 | 1192 | .wp_match (wp_match) |
philpem@0 | 1193 | ); |
philpem@0 | 1194 | `endif |
philpem@0 | 1195 | |
philpem@0 | 1196 | // Register file |
philpem@0 | 1197 | |
philpem@0 | 1198 | `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
philpem@0 | 1199 | /*---------------------------------------------------------------------- |
philpem@0 | 1200 | Register File is implemented using EBRs. There can be three accesses to |
philpem@0 | 1201 | the register file in each cycle: two reads and one write. On-chip block |
philpem@0 | 1202 | RAM has two read/write ports. To accomodate three accesses, two on-chip |
philpem@0 | 1203 | block RAMs are used (each register file "write" is made to both block |
philpem@0 | 1204 | RAMs). |
philpem@0 | 1205 | |
philpem@0 | 1206 | One limitation of the on-chip block RAMs is that one cannot perform a |
philpem@0 | 1207 | read and write to same location in a cycle (if this is done, then the |
philpem@0 | 1208 | data read out is indeterminate). |
philpem@0 | 1209 | ----------------------------------------------------------------------*/ |
philpem@0 | 1210 | wire [31:0] regfile_data_0, regfile_data_1; |
philpem@0 | 1211 | reg [31:0] w_result_d; |
philpem@0 | 1212 | reg regfile_raw_0, regfile_raw_0_nxt; |
philpem@0 | 1213 | reg regfile_raw_1, regfile_raw_1_nxt; |
philpem@0 | 1214 | |
philpem@0 | 1215 | /*---------------------------------------------------------------------- |
philpem@0 | 1216 | Check if read and write is being performed to same register in current |
philpem@0 | 1217 | cycle? This is done by comparing the read and write IDXs. |
philpem@0 | 1218 | ----------------------------------------------------------------------*/ |
philpem@0 | 1219 | always @(reg_write_enable_q_w or write_idx_w or instruction_f) |
philpem@0 | 1220 | begin |
philpem@0 | 1221 | if (reg_write_enable_q_w |
philpem@0 | 1222 | && (write_idx_w == instruction_f[25:21])) |
philpem@0 | 1223 | regfile_raw_0_nxt = 1'b1; |
philpem@0 | 1224 | else |
philpem@0 | 1225 | regfile_raw_0_nxt = 1'b0; |
philpem@0 | 1226 | |
philpem@0 | 1227 | if (reg_write_enable_q_w |
philpem@0 | 1228 | && (write_idx_w == instruction_f[20:16])) |
philpem@0 | 1229 | regfile_raw_1_nxt = 1'b1; |
philpem@0 | 1230 | else |
philpem@0 | 1231 | regfile_raw_1_nxt = 1'b0; |
philpem@0 | 1232 | end |
philpem@0 | 1233 | |
philpem@0 | 1234 | /*---------------------------------------------------------------------- |
philpem@0 | 1235 | Select latched (delayed) write value or data from register file. If |
philpem@0 | 1236 | read in previous cycle was performed to register written to in same |
philpem@0 | 1237 | cycle, then latched (delayed) write value is selected. |
philpem@0 | 1238 | ----------------------------------------------------------------------*/ |
philpem@0 | 1239 | always @(regfile_raw_0 or w_result_d or regfile_data_0) |
philpem@0 | 1240 | if (regfile_raw_0) |
philpem@0 | 1241 | reg_data_live_0 = w_result_d; |
philpem@0 | 1242 | else |
philpem@0 | 1243 | reg_data_live_0 = regfile_data_0; |
philpem@0 | 1244 | |
philpem@0 | 1245 | /*---------------------------------------------------------------------- |
philpem@0 | 1246 | Select latched (delayed) write value or data from register file. If |
philpem@0 | 1247 | read in previous cycle was performed to register written to in same |
philpem@0 | 1248 | cycle, then latched (delayed) write value is selected. |
philpem@0 | 1249 | ----------------------------------------------------------------------*/ |
philpem@0 | 1250 | always @(regfile_raw_1 or w_result_d or regfile_data_1) |
philpem@0 | 1251 | if (regfile_raw_1) |
philpem@0 | 1252 | reg_data_live_1 = w_result_d; |
philpem@0 | 1253 | else |
philpem@0 | 1254 | reg_data_live_1 = regfile_data_1; |
philpem@0 | 1255 | |
philpem@0 | 1256 | /*---------------------------------------------------------------------- |
philpem@0 | 1257 | Latch value written to register file |
philpem@0 | 1258 | ----------------------------------------------------------------------*/ |
philpem@0 | 1259 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 1260 | if (rst_i == `TRUE) |
philpem@0 | 1261 | begin |
philpem@0 | 1262 | regfile_raw_0 <= 1'b0; |
philpem@0 | 1263 | regfile_raw_1 <= 1'b0; |
philpem@0 | 1264 | w_result_d <= 32'b0; |
philpem@0 | 1265 | end |
philpem@0 | 1266 | else |
philpem@0 | 1267 | begin |
philpem@0 | 1268 | regfile_raw_0 <= regfile_raw_0_nxt; |
philpem@0 | 1269 | regfile_raw_1 <= regfile_raw_1_nxt; |
philpem@0 | 1270 | w_result_d <= w_result; |
philpem@0 | 1271 | end |
philpem@0 | 1272 | |
philpem@0 | 1273 | /*---------------------------------------------------------------------- |
philpem@0 | 1274 | Register file instantiation as Pseudo-Dual Port EBRs. |
philpem@0 | 1275 | ----------------------------------------------------------------------*/ |
philpem@0 | 1276 | pmi_ram_dp |
philpem@0 | 1277 | #( |
philpem@0 | 1278 | // ----- Parameters ----- |
philpem@0 | 1279 | .pmi_wr_addr_depth(1<<5), |
philpem@0 | 1280 | .pmi_wr_addr_width(5), |
philpem@0 | 1281 | .pmi_wr_data_width(32), |
philpem@0 | 1282 | .pmi_rd_addr_depth(1<<5), |
philpem@0 | 1283 | .pmi_rd_addr_width(5), |
philpem@0 | 1284 | .pmi_rd_data_width(32), |
philpem@0 | 1285 | .pmi_regmode("noreg"), |
philpem@0 | 1286 | .pmi_gsr("enable"), |
philpem@0 | 1287 | .pmi_resetmode("sync"), |
philpem@0 | 1288 | .pmi_init_file("none"), |
philpem@0 | 1289 | .pmi_init_file_format("binary"), |
philpem@0 | 1290 | .pmi_family(`LATTICE_FAMILY), |
philpem@0 | 1291 | .module_type("pmi_ram_dp") |
philpem@0 | 1292 | ) |
philpem@0 | 1293 | reg_0 |
philpem@0 | 1294 | ( |
philpem@0 | 1295 | // ----- Inputs ----- |
philpem@0 | 1296 | .Data(w_result), |
philpem@0 | 1297 | .WrAddress(write_idx_w), |
philpem@0 | 1298 | .RdAddress(instruction_f[25:21]), |
philpem@0 | 1299 | .WrClock(clk_i), |
philpem@0 | 1300 | .RdClock(clk_i), |
philpem@0 | 1301 | .WrClockEn(`TRUE), |
philpem@0 | 1302 | .RdClockEn(`TRUE), |
philpem@0 | 1303 | .WE(reg_write_enable_q_w), |
philpem@0 | 1304 | .Reset(rst_i), |
philpem@0 | 1305 | // ----- Outputs ----- |
philpem@0 | 1306 | .Q(regfile_data_0) |
philpem@0 | 1307 | ); |
philpem@0 | 1308 | |
philpem@0 | 1309 | pmi_ram_dp |
philpem@0 | 1310 | #( |
philpem@0 | 1311 | // ----- Parameters ----- |
philpem@0 | 1312 | .pmi_wr_addr_depth(1<<5), |
philpem@0 | 1313 | .pmi_wr_addr_width(5), |
philpem@0 | 1314 | .pmi_wr_data_width(32), |
philpem@0 | 1315 | .pmi_rd_addr_depth(1<<5), |
philpem@0 | 1316 | .pmi_rd_addr_width(5), |
philpem@0 | 1317 | .pmi_rd_data_width(32), |
philpem@0 | 1318 | .pmi_regmode("noreg"), |
philpem@0 | 1319 | .pmi_gsr("enable"), |
philpem@0 | 1320 | .pmi_resetmode("sync"), |
philpem@0 | 1321 | .pmi_init_file("none"), |
philpem@0 | 1322 | .pmi_init_file_format("binary"), |
philpem@0 | 1323 | .pmi_family(`LATTICE_FAMILY), |
philpem@0 | 1324 | .module_type("pmi_ram_dp") |
philpem@0 | 1325 | ) |
philpem@0 | 1326 | reg_1 |
philpem@0 | 1327 | ( |
philpem@0 | 1328 | // ----- Inputs ----- |
philpem@0 | 1329 | .Data(w_result), |
philpem@0 | 1330 | .WrAddress(write_idx_w), |
philpem@0 | 1331 | .RdAddress(instruction_f[20:16]), |
philpem@0 | 1332 | .WrClock(clk_i), |
philpem@0 | 1333 | .RdClock(clk_i), |
philpem@0 | 1334 | .WrClockEn(`TRUE), |
philpem@0 | 1335 | .RdClockEn(`TRUE), |
philpem@0 | 1336 | .WE(reg_write_enable_q_w), |
philpem@0 | 1337 | .Reset(rst_i), |
philpem@0 | 1338 | // ----- Outputs ----- |
philpem@0 | 1339 | .Q(regfile_data_1) |
philpem@0 | 1340 | ); |
philpem@0 | 1341 | `endif |
philpem@0 | 1342 | |
philpem@0 | 1343 | `ifdef CFG_EBR_NEGEDGE_REGISTER_FILE |
philpem@0 | 1344 | pmi_ram_dp |
philpem@0 | 1345 | #( |
philpem@0 | 1346 | // ----- Parameters ----- |
philpem@0 | 1347 | .pmi_wr_addr_depth(1<<5), |
philpem@0 | 1348 | .pmi_wr_addr_width(5), |
philpem@0 | 1349 | .pmi_wr_data_width(32), |
philpem@0 | 1350 | .pmi_rd_addr_depth(1<<5), |
philpem@0 | 1351 | .pmi_rd_addr_width(5), |
philpem@0 | 1352 | .pmi_rd_data_width(32), |
philpem@0 | 1353 | .pmi_regmode("noreg"), |
philpem@0 | 1354 | .pmi_gsr("enable"), |
philpem@0 | 1355 | .pmi_resetmode("sync"), |
philpem@0 | 1356 | .pmi_init_file("none"), |
philpem@0 | 1357 | .pmi_init_file_format("binary"), |
philpem@0 | 1358 | .pmi_family(`LATTICE_FAMILY), |
philpem@0 | 1359 | .module_type("pmi_ram_dp") |
philpem@0 | 1360 | ) |
philpem@0 | 1361 | reg_0 |
philpem@0 | 1362 | ( |
philpem@0 | 1363 | // ----- Inputs ----- |
philpem@0 | 1364 | .Data(w_result), |
philpem@0 | 1365 | .WrAddress(write_idx_w), |
philpem@0 | 1366 | .RdAddress(read_idx_0_d), |
philpem@0 | 1367 | .WrClock(clk_i), |
philpem@0 | 1368 | .RdClock(clk_n_i), |
philpem@0 | 1369 | .WrClockEn(`TRUE), |
philpem@0 | 1370 | .RdClockEn(stall_f == `FALSE), |
philpem@0 | 1371 | .WE(reg_write_enable_q_w), |
philpem@0 | 1372 | .Reset(rst_i), |
philpem@0 | 1373 | // ----- Outputs ----- |
philpem@0 | 1374 | .Q(reg_data_0) |
philpem@0 | 1375 | ); |
philpem@0 | 1376 | |
philpem@0 | 1377 | pmi_ram_dp |
philpem@0 | 1378 | #( |
philpem@0 | 1379 | // ----- Parameters ----- |
philpem@0 | 1380 | .pmi_wr_addr_depth(1<<5), |
philpem@0 | 1381 | .pmi_wr_addr_width(5), |
philpem@0 | 1382 | .pmi_wr_data_width(32), |
philpem@0 | 1383 | .pmi_rd_addr_depth(1<<5), |
philpem@0 | 1384 | .pmi_rd_addr_width(5), |
philpem@0 | 1385 | .pmi_rd_data_width(32), |
philpem@0 | 1386 | .pmi_regmode("noreg"), |
philpem@0 | 1387 | .pmi_gsr("enable"), |
philpem@0 | 1388 | .pmi_resetmode("sync"), |
philpem@0 | 1389 | .pmi_init_file("none"), |
philpem@0 | 1390 | .pmi_init_file_format("binary"), |
philpem@0 | 1391 | .pmi_family(`LATTICE_FAMILY), |
philpem@0 | 1392 | .module_type("pmi_ram_dp") |
philpem@0 | 1393 | ) |
philpem@0 | 1394 | reg_1 |
philpem@0 | 1395 | ( |
philpem@0 | 1396 | // ----- Inputs ----- |
philpem@0 | 1397 | .Data(w_result), |
philpem@0 | 1398 | .WrAddress(write_idx_w), |
philpem@0 | 1399 | .RdAddress(read_idx_1_d), |
philpem@0 | 1400 | .WrClock(clk_i), |
philpem@0 | 1401 | .RdClock(clk_n_i), |
philpem@0 | 1402 | .WrClockEn(`TRUE), |
philpem@0 | 1403 | .RdClockEn(stall_f == `FALSE), |
philpem@0 | 1404 | .WE(reg_write_enable_q_w), |
philpem@0 | 1405 | .Reset(rst_i), |
philpem@0 | 1406 | // ----- Outputs ----- |
philpem@0 | 1407 | .Q(reg_data_1) |
philpem@0 | 1408 | ); |
philpem@0 | 1409 | `endif |
philpem@0 | 1410 | |
philpem@0 | 1411 | |
philpem@0 | 1412 | ///////////////////////////////////////////////////// |
philpem@0 | 1413 | // Combinational Logic |
philpem@0 | 1414 | ///////////////////////////////////////////////////// |
philpem@0 | 1415 | |
philpem@0 | 1416 | `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
philpem@0 | 1417 | // Select between buffered and live data from register file |
philpem@0 | 1418 | assign reg_data_0 = use_buf ? reg_data_buf_0 : reg_data_live_0; |
philpem@0 | 1419 | assign reg_data_1 = use_buf ? reg_data_buf_1 : reg_data_live_1; |
philpem@0 | 1420 | `endif |
philpem@0 | 1421 | `ifdef LM32_EBR_REGISTER_FILE |
philpem@0 | 1422 | `else |
philpem@0 | 1423 | // Register file read ports |
philpem@0 | 1424 | assign reg_data_0 = registers[read_idx_0_d]; |
philpem@0 | 1425 | assign reg_data_1 = registers[read_idx_1_d]; |
philpem@0 | 1426 | `endif |
philpem@0 | 1427 | |
philpem@0 | 1428 | // Detect read-after-write hazzards |
philpem@0 | 1429 | assign raw_x_0 = (write_idx_x == read_idx_0_d) && (write_enable_q_x == `TRUE); |
philpem@0 | 1430 | assign raw_m_0 = (write_idx_m == read_idx_0_d) && (write_enable_q_m == `TRUE); |
philpem@0 | 1431 | assign raw_w_0 = (write_idx_w == read_idx_0_d) && (write_enable_q_w == `TRUE); |
philpem@0 | 1432 | assign raw_x_1 = (write_idx_x == read_idx_1_d) && (write_enable_q_x == `TRUE); |
philpem@0 | 1433 | assign raw_m_1 = (write_idx_m == read_idx_1_d) && (write_enable_q_m == `TRUE); |
philpem@0 | 1434 | assign raw_w_1 = (write_idx_w == read_idx_1_d) && (write_enable_q_w == `TRUE); |
philpem@0 | 1435 | |
philpem@0 | 1436 | // Interlock detection - Raise an interlock for RAW hazzards |
philpem@0 | 1437 | always @(*) |
philpem@0 | 1438 | begin |
philpem@0 | 1439 | if ( ( (x_bypass_enable_x == `FALSE) |
philpem@0 | 1440 | && ( ((read_enable_0_d == `TRUE) && (raw_x_0 == `TRUE)) |
philpem@0 | 1441 | || ((read_enable_1_d == `TRUE) && (raw_x_1 == `TRUE)) |
philpem@0 | 1442 | ) |
philpem@0 | 1443 | ) |
philpem@0 | 1444 | || ( (m_bypass_enable_m == `FALSE) |
philpem@0 | 1445 | && ( ((read_enable_0_d == `TRUE) && (raw_m_0 == `TRUE)) |
philpem@0 | 1446 | || ((read_enable_1_d == `TRUE) && (raw_m_1 == `TRUE)) |
philpem@0 | 1447 | ) |
philpem@0 | 1448 | ) |
philpem@0 | 1449 | ) |
philpem@0 | 1450 | interlock = `TRUE; |
philpem@0 | 1451 | else |
philpem@0 | 1452 | interlock = `FALSE; |
philpem@0 | 1453 | end |
philpem@0 | 1454 | |
philpem@0 | 1455 | // Bypass for reg port 0 |
philpem@0 | 1456 | always @(*) |
philpem@0 | 1457 | begin |
philpem@0 | 1458 | if (raw_x_0 == `TRUE) |
philpem@0 | 1459 | bypass_data_0 = x_result; |
philpem@0 | 1460 | else if (raw_m_0 == `TRUE) |
philpem@0 | 1461 | bypass_data_0 = m_result; |
philpem@0 | 1462 | else if (raw_w_0 == `TRUE) |
philpem@0 | 1463 | bypass_data_0 = w_result; |
philpem@0 | 1464 | else |
philpem@0 | 1465 | bypass_data_0 = reg_data_0; |
philpem@0 | 1466 | end |
philpem@0 | 1467 | |
philpem@0 | 1468 | // Bypass for reg port 1 |
philpem@0 | 1469 | always @(*) |
philpem@0 | 1470 | begin |
philpem@0 | 1471 | if (raw_x_1 == `TRUE) |
philpem@0 | 1472 | bypass_data_1 = x_result; |
philpem@0 | 1473 | else if (raw_m_1 == `TRUE) |
philpem@0 | 1474 | bypass_data_1 = m_result; |
philpem@0 | 1475 | else if (raw_w_1 == `TRUE) |
philpem@0 | 1476 | bypass_data_1 = w_result; |
philpem@0 | 1477 | else |
philpem@0 | 1478 | bypass_data_1 = reg_data_1; |
philpem@0 | 1479 | end |
philpem@0 | 1480 | |
philpem@0 | 1481 | /*---------------------------------------------------------------------- |
philpem@0 | 1482 | Branch prediction is performed in D stage of pipeline. Only PC-relative |
philpem@0 | 1483 | branches are predicted: forward-pointing conditional branches are not- |
philpem@0 | 1484 | taken, while backward-pointing conditional branches are taken. |
philpem@0 | 1485 | Unconditional branches are always predicted taken! |
philpem@0 | 1486 | ----------------------------------------------------------------------*/ |
philpem@0 | 1487 | assign branch_predict_d = bi_unconditional | bi_conditional; |
philpem@0 | 1488 | assign branch_predict_taken_d = bi_unconditional ? 1'b1 : (bi_conditional ? instruction_d[15] : 1'b0); |
philpem@0 | 1489 | |
philpem@0 | 1490 | // Compute branch target address: Branch PC PLUS Offset |
philpem@0 | 1491 | assign branch_target_d = pc_d + branch_offset_d; |
philpem@0 | 1492 | |
philpem@0 | 1493 | // Compute fetch address. Address of instruction sequentially after the |
philpem@0 | 1494 | // branch if branch is not taken. Target address of branch is branch is |
philpem@0 | 1495 | // taken |
philpem@0 | 1496 | assign branch_predict_address_d = branch_predict_taken_d ? branch_target_d : pc_f; |
philpem@0 | 1497 | |
philpem@0 | 1498 | // D stage result selection |
philpem@0 | 1499 | always @(*) |
philpem@0 | 1500 | begin |
philpem@0 | 1501 | d_result_0 = d_result_sel_0_d[0] ? {pc_f, 2'b00} : bypass_data_0; |
philpem@0 | 1502 | case (d_result_sel_1_d) |
philpem@0 | 1503 | `LM32_D_RESULT_SEL_1_ZERO: d_result_1 = {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 1504 | `LM32_D_RESULT_SEL_1_REG_1: d_result_1 = bypass_data_1; |
philpem@0 | 1505 | `LM32_D_RESULT_SEL_1_IMMEDIATE: d_result_1 = immediate_d; |
philpem@0 | 1506 | default: d_result_1 = {`LM32_WORD_WIDTH{1'bx}}; |
philpem@0 | 1507 | endcase |
philpem@0 | 1508 | end |
philpem@0 | 1509 | |
philpem@0 | 1510 | `ifdef CFG_USER_ENABLED |
philpem@0 | 1511 | // Operands for user-defined instructions |
philpem@0 | 1512 | assign user_operand_0 = operand_0_x; |
philpem@0 | 1513 | assign user_operand_1 = operand_1_x; |
philpem@0 | 1514 | `endif |
philpem@0 | 1515 | |
philpem@0 | 1516 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 1517 | // Sign-extension |
philpem@0 | 1518 | assign sextb_result_x = {{24{operand_0_x[7]}}, operand_0_x[7:0]}; |
philpem@0 | 1519 | assign sexth_result_x = {{16{operand_0_x[15]}}, operand_0_x[15:0]}; |
philpem@0 | 1520 | assign sext_result_x = size_x == `LM32_SIZE_BYTE ? sextb_result_x : sexth_result_x; |
philpem@0 | 1521 | `endif |
philpem@0 | 1522 | |
philpem@0 | 1523 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 1524 | // Only single bit shift operations are supported when barrel-shifter isn't implemented |
philpem@0 | 1525 | assign shifter_result_x = {operand_0_x[`LM32_WORD_WIDTH-1] & sign_extend_x, operand_0_x[`LM32_WORD_WIDTH-1:1]}; |
philpem@0 | 1526 | `endif |
philpem@0 | 1527 | |
philpem@0 | 1528 | // Condition evaluation |
philpem@0 | 1529 | assign cmp_zero = operand_0_x == operand_1_x; |
philpem@0 | 1530 | assign cmp_negative = adder_result_x[`LM32_WORD_WIDTH-1]; |
philpem@0 | 1531 | assign cmp_overflow = adder_overflow_x; |
philpem@0 | 1532 | assign cmp_carry_n = adder_carry_n_x; |
philpem@0 | 1533 | always @(*) |
philpem@0 | 1534 | begin |
philpem@0 | 1535 | case (condition_x) |
philpem@0 | 1536 | `LM32_CONDITION_U1: condition_met_x = `TRUE; |
philpem@0 | 1537 | `LM32_CONDITION_U2: condition_met_x = `TRUE; |
philpem@0 | 1538 | `LM32_CONDITION_E: condition_met_x = cmp_zero; |
philpem@0 | 1539 | `LM32_CONDITION_NE: condition_met_x = !cmp_zero; |
philpem@0 | 1540 | `LM32_CONDITION_G: condition_met_x = !cmp_zero && (cmp_negative == cmp_overflow); |
philpem@0 | 1541 | `LM32_CONDITION_GU: condition_met_x = cmp_carry_n && !cmp_zero; |
philpem@0 | 1542 | `LM32_CONDITION_GE: condition_met_x = cmp_negative == cmp_overflow; |
philpem@0 | 1543 | `LM32_CONDITION_GEU: condition_met_x = cmp_carry_n; |
philpem@0 | 1544 | default: condition_met_x = 1'bx; |
philpem@0 | 1545 | endcase |
philpem@0 | 1546 | end |
philpem@0 | 1547 | |
philpem@0 | 1548 | // X stage result selection |
philpem@0 | 1549 | always @(*) |
philpem@0 | 1550 | begin |
philpem@0 | 1551 | x_result = x_result_sel_add_x ? adder_result_x |
philpem@0 | 1552 | : x_result_sel_csr_x ? csr_read_data_x |
philpem@0 | 1553 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 1554 | : x_result_sel_sext_x ? sext_result_x |
philpem@0 | 1555 | `endif |
philpem@0 | 1556 | `ifdef CFG_USER_ENABLED |
philpem@0 | 1557 | : x_result_sel_user_x ? user_result |
philpem@0 | 1558 | `endif |
philpem@0 | 1559 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 1560 | : x_result_sel_shift_x ? shifter_result_x |
philpem@0 | 1561 | `endif |
philpem@0 | 1562 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 1563 | : x_result_sel_mc_arith_x ? mc_result_x |
philpem@0 | 1564 | `endif |
philpem@0 | 1565 | : logic_result_x; |
philpem@0 | 1566 | end |
philpem@0 | 1567 | |
philpem@0 | 1568 | // M stage result selection |
philpem@0 | 1569 | always @(*) |
philpem@0 | 1570 | begin |
philpem@0 | 1571 | m_result = m_result_sel_compare_m ? {{`LM32_WORD_WIDTH-1{1'b0}}, condition_met_m} |
philpem@0 | 1572 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 1573 | : m_result_sel_shift_m ? shifter_result_m |
philpem@0 | 1574 | `endif |
philpem@0 | 1575 | : operand_m; |
philpem@0 | 1576 | end |
philpem@0 | 1577 | |
philpem@0 | 1578 | // W stage result selection |
philpem@0 | 1579 | always @(*) |
philpem@0 | 1580 | begin |
philpem@0 | 1581 | w_result = w_result_sel_load_w ? load_data_w |
philpem@0 | 1582 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 1583 | : w_result_sel_mul_w ? multiplier_result_w |
philpem@0 | 1584 | `endif |
philpem@0 | 1585 | : operand_w; |
philpem@0 | 1586 | end |
philpem@0 | 1587 | |
philpem@0 | 1588 | `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
philpem@0 | 1589 | // Indicate when a branch should be taken in X stage |
philpem@0 | 1590 | assign branch_taken_x = (stall_x == `FALSE) |
philpem@0 | 1591 | && ( (branch_x == `TRUE) |
philpem@0 | 1592 | && ((condition_x == `LM32_CONDITION_U1) || (condition_x == `LM32_CONDITION_U2)) |
philpem@0 | 1593 | && (valid_x == `TRUE) |
philpem@0 | 1594 | && (branch_predict_x == `FALSE) |
philpem@0 | 1595 | ); |
philpem@0 | 1596 | `endif |
philpem@0 | 1597 | |
philpem@0 | 1598 | // Indicate when a branch should be taken in M stage (exceptions are a type of branch) |
philpem@0 | 1599 | assign branch_taken_m = (stall_m == `FALSE) |
philpem@0 | 1600 | && ( ( (branch_m == `TRUE) |
philpem@0 | 1601 | && (valid_m == `TRUE) |
philpem@0 | 1602 | && ( ( (condition_met_m == `TRUE) |
philpem@0 | 1603 | && (branch_predict_taken_m == `FALSE) |
philpem@0 | 1604 | ) |
philpem@0 | 1605 | || ( (condition_met_m == `FALSE) |
philpem@0 | 1606 | && (branch_predict_m == `TRUE) |
philpem@0 | 1607 | && (branch_predict_taken_m == `TRUE) |
philpem@0 | 1608 | ) |
philpem@0 | 1609 | ) |
philpem@0 | 1610 | ) |
philpem@0 | 1611 | || (exception_m == `TRUE) |
philpem@0 | 1612 | ); |
philpem@0 | 1613 | |
philpem@0 | 1614 | // Indicate when a branch in M stage is mispredicted as being taken |
philpem@0 | 1615 | assign branch_mispredict_taken_m = (condition_met_m == `FALSE) |
philpem@0 | 1616 | && (branch_predict_m == `TRUE) |
philpem@0 | 1617 | && (branch_predict_taken_m == `TRUE); |
philpem@0 | 1618 | |
philpem@0 | 1619 | // Indicate when a branch in M stage will cause flush in X stage |
philpem@0 | 1620 | assign branch_flushX_m = (stall_m == `FALSE) |
philpem@0 | 1621 | && ( ( (branch_m == `TRUE) |
philpem@0 | 1622 | && (valid_m == `TRUE) |
philpem@0 | 1623 | && ( (condition_met_m == `TRUE) |
philpem@0 | 1624 | || ( (condition_met_m == `FALSE) |
philpem@0 | 1625 | && (branch_predict_m == `TRUE) |
philpem@0 | 1626 | && (branch_predict_taken_m == `TRUE) |
philpem@0 | 1627 | ) |
philpem@0 | 1628 | ) |
philpem@0 | 1629 | ) |
philpem@0 | 1630 | || (exception_m == `TRUE) |
philpem@0 | 1631 | ); |
philpem@0 | 1632 | |
philpem@0 | 1633 | // Generate signal that will kill instructions in each pipeline stage when necessary |
philpem@0 | 1634 | assign kill_f = ( (valid_d == `TRUE) |
philpem@0 | 1635 | && (branch_predict_taken_d == `TRUE) |
philpem@0 | 1636 | ) |
philpem@0 | 1637 | || (branch_taken_m == `TRUE) |
philpem@0 | 1638 | `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
philpem@0 | 1639 | || (branch_taken_x == `TRUE) |
philpem@0 | 1640 | `endif |
philpem@0 | 1641 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 1642 | || (icache_refill_request == `TRUE) |
philpem@0 | 1643 | `endif |
philpem@0 | 1644 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1645 | || (dcache_refill_request == `TRUE) |
philpem@0 | 1646 | `endif |
philpem@0 | 1647 | ; |
philpem@0 | 1648 | assign kill_d = (branch_taken_m == `TRUE) |
philpem@0 | 1649 | `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
philpem@0 | 1650 | || (branch_taken_x == `TRUE) |
philpem@0 | 1651 | `endif |
philpem@0 | 1652 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 1653 | || (icache_refill_request == `TRUE) |
philpem@0 | 1654 | `endif |
philpem@0 | 1655 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1656 | || (dcache_refill_request == `TRUE) |
philpem@0 | 1657 | `endif |
philpem@0 | 1658 | ; |
philpem@0 | 1659 | assign kill_x = (branch_flushX_m == `TRUE) |
philpem@0 | 1660 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1661 | || (dcache_refill_request == `TRUE) |
philpem@0 | 1662 | `endif |
philpem@0 | 1663 | ; |
philpem@0 | 1664 | assign kill_m = `FALSE |
philpem@0 | 1665 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1666 | || (dcache_refill_request == `TRUE) |
philpem@0 | 1667 | `endif |
philpem@0 | 1668 | ; |
philpem@0 | 1669 | assign kill_w = `FALSE |
philpem@0 | 1670 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1671 | || (dcache_refill_request == `TRUE) |
philpem@0 | 1672 | `endif |
philpem@0 | 1673 | ; |
philpem@0 | 1674 | |
philpem@0 | 1675 | // Exceptions |
philpem@0 | 1676 | |
philpem@0 | 1677 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1678 | assign breakpoint_exception = ( ( (break_x == `TRUE) |
philpem@0 | 1679 | || (bp_match == `TRUE) |
philpem@0 | 1680 | ) |
philpem@0 | 1681 | && (valid_x == `TRUE) |
philpem@0 | 1682 | ) |
philpem@0 | 1683 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 1684 | || (jtag_break == `TRUE) |
philpem@0 | 1685 | `endif |
philpem@0 | 1686 | ; |
philpem@0 | 1687 | `endif |
philpem@0 | 1688 | |
philpem@0 | 1689 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1690 | assign watchpoint_exception = wp_match == `TRUE; |
philpem@0 | 1691 | `endif |
philpem@0 | 1692 | |
philpem@0 | 1693 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1694 | assign instruction_bus_error_exception = ( (bus_error_x == `TRUE) |
philpem@0 | 1695 | && (valid_x == `TRUE) |
philpem@0 | 1696 | ); |
philpem@0 | 1697 | assign data_bus_error_exception = data_bus_error_seen == `TRUE; |
philpem@0 | 1698 | `endif |
philpem@0 | 1699 | |
philpem@0 | 1700 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1701 | assign divide_by_zero_exception = divide_by_zero_x == `TRUE; |
philpem@0 | 1702 | `endif |
philpem@0 | 1703 | |
philpem@0 | 1704 | assign system_call_exception = ( (scall_x == `TRUE) |
philpem@0 | 1705 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1706 | && (valid_x == `TRUE) |
philpem@0 | 1707 | `endif |
philpem@0 | 1708 | ); |
philpem@0 | 1709 | |
philpem@0 | 1710 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1711 | assign debug_exception_x = (breakpoint_exception == `TRUE) |
philpem@0 | 1712 | || (watchpoint_exception == `TRUE) |
philpem@0 | 1713 | ; |
philpem@0 | 1714 | |
philpem@0 | 1715 | assign non_debug_exception_x = (system_call_exception == `TRUE) |
philpem@0 | 1716 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 1717 | || (reset_exception == `TRUE) |
philpem@0 | 1718 | `endif |
philpem@0 | 1719 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1720 | || (instruction_bus_error_exception == `TRUE) |
philpem@0 | 1721 | || (data_bus_error_exception == `TRUE) |
philpem@0 | 1722 | `endif |
philpem@0 | 1723 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1724 | || (divide_by_zero_exception == `TRUE) |
philpem@0 | 1725 | `endif |
philpem@0 | 1726 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 1727 | || ( (interrupt_exception == `TRUE) |
philpem@0 | 1728 | `ifdef LM32_SINGLE_STEP_ENABLED |
philpem@0 | 1729 | && (dc_ss == `FALSE) |
philpem@0 | 1730 | `endif |
philpem@0 | 1731 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1732 | && (store_q_m == `FALSE) |
philpem@0 | 1733 | && (D_CYC_O == `FALSE) |
philpem@0 | 1734 | `endif |
philpem@0 | 1735 | ) |
philpem@0 | 1736 | `endif |
philpem@0 | 1737 | ; |
philpem@0 | 1738 | |
philpem@0 | 1739 | assign exception_x = (debug_exception_x == `TRUE) || (non_debug_exception_x == `TRUE); |
philpem@0 | 1740 | `else |
philpem@0 | 1741 | assign exception_x = (system_call_exception == `TRUE) |
philpem@0 | 1742 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1743 | || (instruction_bus_error_exception == `TRUE) |
philpem@0 | 1744 | || (data_bus_error_exception == `TRUE) |
philpem@0 | 1745 | `endif |
philpem@0 | 1746 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1747 | || (divide_by_zero_exception == `TRUE) |
philpem@0 | 1748 | `endif |
philpem@0 | 1749 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 1750 | || ( (interrupt_exception == `TRUE) |
philpem@0 | 1751 | `ifdef LM32_SINGLE_STEP_ENABLED |
philpem@0 | 1752 | && (dc_ss == `FALSE) |
philpem@0 | 1753 | `endif |
philpem@0 | 1754 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1755 | && (store_q_m == `FALSE) |
philpem@0 | 1756 | && (D_CYC_O == `FALSE) |
philpem@0 | 1757 | `endif |
philpem@0 | 1758 | ) |
philpem@0 | 1759 | `endif |
philpem@0 | 1760 | ; |
philpem@0 | 1761 | `endif |
philpem@0 | 1762 | |
philpem@0 | 1763 | // Exception ID |
philpem@0 | 1764 | always @(*) |
philpem@0 | 1765 | begin |
philpem@0 | 1766 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1767 | `ifdef CFG_JTAG_ENABLED |
philpem@0 | 1768 | if (reset_exception == `TRUE) |
philpem@0 | 1769 | eid_x = `LM32_EID_RESET; |
philpem@0 | 1770 | else |
philpem@0 | 1771 | `endif |
philpem@0 | 1772 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1773 | if (data_bus_error_exception == `TRUE) |
philpem@0 | 1774 | eid_x = `LM32_EID_DATA_BUS_ERROR; |
philpem@0 | 1775 | else |
philpem@0 | 1776 | `endif |
philpem@0 | 1777 | if (breakpoint_exception == `TRUE) |
philpem@0 | 1778 | eid_x = `LM32_EID_BREAKPOINT; |
philpem@0 | 1779 | else |
philpem@0 | 1780 | `endif |
philpem@0 | 1781 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 1782 | if (data_bus_error_exception == `TRUE) |
philpem@0 | 1783 | eid_x = `LM32_EID_DATA_BUS_ERROR; |
philpem@0 | 1784 | else |
philpem@0 | 1785 | if (instruction_bus_error_exception == `TRUE) |
philpem@0 | 1786 | eid_x = `LM32_EID_INST_BUS_ERROR; |
philpem@0 | 1787 | else |
philpem@0 | 1788 | `endif |
philpem@0 | 1789 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1790 | if (watchpoint_exception == `TRUE) |
philpem@0 | 1791 | eid_x = `LM32_EID_WATCHPOINT; |
philpem@0 | 1792 | else |
philpem@0 | 1793 | `endif |
philpem@0 | 1794 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1795 | if (divide_by_zero_exception == `TRUE) |
philpem@0 | 1796 | eid_x = `LM32_EID_DIVIDE_BY_ZERO; |
philpem@0 | 1797 | else |
philpem@0 | 1798 | `endif |
philpem@0 | 1799 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 1800 | if ( (interrupt_exception == `TRUE) |
philpem@0 | 1801 | `ifdef LM32_SINGLE_STEP_ENABLED |
philpem@0 | 1802 | && (dc_ss == `FALSE) |
philpem@0 | 1803 | `endif |
philpem@0 | 1804 | ) |
philpem@0 | 1805 | eid_x = `LM32_EID_INTERRUPT; |
philpem@0 | 1806 | else |
philpem@0 | 1807 | `endif |
philpem@0 | 1808 | eid_x = `LM32_EID_SCALL; |
philpem@0 | 1809 | end |
philpem@0 | 1810 | |
philpem@0 | 1811 | // Stall generation |
philpem@0 | 1812 | |
philpem@0 | 1813 | assign stall_a = (stall_f == `TRUE); |
philpem@0 | 1814 | |
philpem@0 | 1815 | assign stall_f = (stall_d == `TRUE); |
philpem@0 | 1816 | |
philpem@0 | 1817 | assign stall_d = (stall_x == `TRUE) |
philpem@0 | 1818 | || ( (interlock == `TRUE) |
philpem@0 | 1819 | && (kill_d == `FALSE) |
philpem@0 | 1820 | ) |
philpem@0 | 1821 | || ( ( (eret_d == `TRUE) |
philpem@0 | 1822 | || (scall_d == `TRUE) |
philpem@0 | 1823 | || (bus_error_d == `TRUE) |
philpem@0 | 1824 | ) |
philpem@0 | 1825 | && ( (load_q_x == `TRUE) |
philpem@0 | 1826 | || (load_q_m == `TRUE) |
philpem@0 | 1827 | || (store_q_x == `TRUE) |
philpem@0 | 1828 | || (store_q_m == `TRUE) |
philpem@0 | 1829 | || (D_CYC_O == `TRUE) |
philpem@0 | 1830 | ) |
philpem@0 | 1831 | && (kill_d == `FALSE) |
philpem@0 | 1832 | ) |
philpem@0 | 1833 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1834 | || ( ( (break_d == `TRUE) |
philpem@0 | 1835 | || (bret_d == `TRUE) |
philpem@0 | 1836 | ) |
philpem@0 | 1837 | && ( (load_q_x == `TRUE) |
philpem@0 | 1838 | || (store_q_x == `TRUE) |
philpem@0 | 1839 | || (load_q_m == `TRUE) |
philpem@0 | 1840 | || (store_q_m == `TRUE) |
philpem@0 | 1841 | || (D_CYC_O == `TRUE) |
philpem@0 | 1842 | ) |
philpem@0 | 1843 | && (kill_d == `FALSE) |
philpem@0 | 1844 | ) |
philpem@0 | 1845 | `endif |
philpem@0 | 1846 | || ( (csr_write_enable_d == `TRUE) |
philpem@0 | 1847 | && (load_q_x == `TRUE) |
philpem@0 | 1848 | ) |
philpem@0 | 1849 | ; |
philpem@0 | 1850 | |
philpem@0 | 1851 | assign stall_x = (stall_m == `TRUE) |
philpem@0 | 1852 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 1853 | || ( (mc_stall_request_x == `TRUE) |
philpem@0 | 1854 | && (kill_x == `FALSE) |
philpem@0 | 1855 | ) |
philpem@0 | 1856 | `endif |
philpem@0 | 1857 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 1858 | // Stall load/store instruction in D stage if there is an ongoing store |
philpem@0 | 1859 | // operation to instruction ROM in M stage |
philpem@0 | 1860 | || ( (irom_stall_request_x == `TRUE) |
philpem@0 | 1861 | && ( (load_d == `TRUE) |
philpem@0 | 1862 | || (store_d == `TRUE) |
philpem@0 | 1863 | ) |
philpem@0 | 1864 | ) |
philpem@0 | 1865 | `endif |
philpem@0 | 1866 | ; |
philpem@0 | 1867 | |
philpem@0 | 1868 | assign stall_m = (stall_wb_load == `TRUE) |
philpem@0 | 1869 | `ifdef CFG_SIZE_OVER_SPEED |
philpem@0 | 1870 | || (D_CYC_O == `TRUE) |
philpem@0 | 1871 | `else |
philpem@0 | 1872 | || ( (D_CYC_O == `TRUE) |
philpem@0 | 1873 | && ( (store_m == `TRUE) |
philpem@0 | 1874 | /* |
philpem@0 | 1875 | Bug: Following loop does not allow interrupts to be services since |
philpem@0 | 1876 | either D_CYC_O or store_m is always high during entire duration of |
philpem@0 | 1877 | loop. |
philpem@0 | 1878 | L1: addi r1, r1, 1 |
philpem@0 | 1879 | sw (r2,0), r1 |
philpem@0 | 1880 | bi L1 |
philpem@0 | 1881 | |
philpem@0 | 1882 | Introduce a single-cycle stall when a wishbone cycle is in progress |
philpem@0 | 1883 | and a new store instruction is in Execute stage and a interrupt |
philpem@0 | 1884 | exception has occured. This stall will ensure that D_CYC_O and |
philpem@0 | 1885 | store_m will both be low for one cycle. |
philpem@0 | 1886 | */ |
philpem@0 | 1887 | || ((store_x == `TRUE) && (interrupt_exception == `TRUE)) |
philpem@0 | 1888 | || (load_m == `TRUE) |
philpem@0 | 1889 | || (load_x == `TRUE) |
philpem@0 | 1890 | ) |
philpem@0 | 1891 | ) |
philpem@0 | 1892 | `endif |
philpem@0 | 1893 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1894 | || (dcache_stall_request == `TRUE) // Need to stall in case a taken branch is in M stage and data cache is only being flush, so wont be restarted |
philpem@0 | 1895 | `endif |
philpem@0 | 1896 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 1897 | || (icache_stall_request == `TRUE) // Pipeline needs to be stalled otherwise branches may be lost |
philpem@0 | 1898 | || ((I_CYC_O == `TRUE) && ((branch_m == `TRUE) || (exception_m == `TRUE))) |
philpem@0 | 1899 | `else |
philpem@0 | 1900 | `ifdef CFG_IWB_ENABLED |
philpem@0 | 1901 | || (I_CYC_O == `TRUE) |
philpem@0 | 1902 | `endif |
philpem@0 | 1903 | `endif |
philpem@0 | 1904 | `ifdef CFG_USER_ENABLED |
philpem@0 | 1905 | || ( (user_valid == `TRUE) // Stall whole pipeline, rather than just X stage, where the instruction is, so we don't have to worry about exceptions (maybe) |
philpem@0 | 1906 | && (user_complete == `FALSE) |
philpem@0 | 1907 | ) |
philpem@0 | 1908 | `endif |
philpem@0 | 1909 | ; |
philpem@0 | 1910 | |
philpem@0 | 1911 | // Qualify state changing control signals |
philpem@0 | 1912 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 1913 | assign q_d = (valid_d == `TRUE) && (kill_d == `FALSE); |
philpem@0 | 1914 | `endif |
philpem@0 | 1915 | `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
philpem@0 | 1916 | assign shift_left_q_d = (shift_left_d == `TRUE) && (q_d == `TRUE); |
philpem@0 | 1917 | assign shift_right_q_d = (shift_right_d == `TRUE) && (q_d == `TRUE); |
philpem@0 | 1918 | `endif |
philpem@0 | 1919 | `ifdef CFG_MC_MULTIPLY_ENABLED |
philpem@0 | 1920 | assign multiply_q_d = (multiply_d == `TRUE) && (q_d == `TRUE); |
philpem@0 | 1921 | `endif |
philpem@0 | 1922 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 1923 | assign divide_q_d = (divide_d == `TRUE) && (q_d == `TRUE); |
philpem@0 | 1924 | assign modulus_q_d = (modulus_d == `TRUE) && (q_d == `TRUE); |
philpem@0 | 1925 | `endif |
philpem@0 | 1926 | assign q_x = (valid_x == `TRUE) && (kill_x == `FALSE); |
philpem@0 | 1927 | assign csr_write_enable_q_x = (csr_write_enable_x == `TRUE) && (q_x == `TRUE); |
philpem@0 | 1928 | assign eret_q_x = (eret_x == `TRUE) && (q_x == `TRUE); |
philpem@0 | 1929 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1930 | assign bret_q_x = (bret_x == `TRUE) && (q_x == `TRUE); |
philpem@0 | 1931 | `endif |
philpem@0 | 1932 | assign load_q_x = (load_x == `TRUE) |
philpem@0 | 1933 | && (q_x == `TRUE) |
philpem@0 | 1934 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1935 | && (bp_match == `FALSE) |
philpem@0 | 1936 | `endif |
philpem@0 | 1937 | ; |
philpem@0 | 1938 | assign store_q_x = (store_x == `TRUE) |
philpem@0 | 1939 | && (q_x == `TRUE) |
philpem@0 | 1940 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1941 | && (bp_match == `FALSE) |
philpem@0 | 1942 | `endif |
philpem@0 | 1943 | ; |
philpem@0 | 1944 | `ifdef CFG_USER_ENABLED |
philpem@0 | 1945 | assign user_valid = (x_result_sel_user_x == `TRUE) && (q_x == `TRUE); |
philpem@0 | 1946 | `endif |
philpem@0 | 1947 | assign q_m = (valid_m == `TRUE) && (kill_m == `FALSE) && (exception_m == `FALSE); |
philpem@0 | 1948 | assign load_q_m = (load_m == `TRUE) && (q_m == `TRUE); |
philpem@0 | 1949 | assign store_q_m = (store_m == `TRUE) && (q_m == `TRUE); |
philpem@0 | 1950 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1951 | assign debug_exception_q_w = ((debug_exception_w == `TRUE) && (valid_w == `TRUE)); |
philpem@0 | 1952 | assign non_debug_exception_q_w = ((non_debug_exception_w == `TRUE) && (valid_w == `TRUE)); |
philpem@0 | 1953 | `else |
philpem@0 | 1954 | assign exception_q_w = ((exception_w == `TRUE) && (valid_w == `TRUE)); |
philpem@0 | 1955 | `endif |
philpem@0 | 1956 | // Don't qualify register write enables with kill, as the signal is needed early, and it doesn't matter if the instruction is killed (except for the actual write - but that is handled separately) |
philpem@0 | 1957 | assign write_enable_q_x = (write_enable_x == `TRUE) && (valid_x == `TRUE) && (branch_flushX_m == `FALSE); |
philpem@0 | 1958 | assign write_enable_q_m = (write_enable_m == `TRUE) && (valid_m == `TRUE); |
philpem@0 | 1959 | assign write_enable_q_w = (write_enable_w == `TRUE) && (valid_w == `TRUE); |
philpem@0 | 1960 | // The enable that actually does write the registers needs to be qualified with kill |
philpem@0 | 1961 | assign reg_write_enable_q_w = (write_enable_w == `TRUE) && (kill_w == `FALSE) && (valid_w == `TRUE); |
philpem@0 | 1962 | |
philpem@0 | 1963 | // Configuration (CFG) CSR |
philpem@0 | 1964 | assign cfg = { |
philpem@0 | 1965 | `LM32_REVISION, |
philpem@0 | 1966 | watchpoints[3:0], |
philpem@0 | 1967 | breakpoints[3:0], |
philpem@0 | 1968 | interrupts[5:0], |
philpem@0 | 1969 | `ifdef CFG_JTAG_UART_ENABLED |
philpem@0 | 1970 | `TRUE, |
philpem@0 | 1971 | `else |
philpem@0 | 1972 | `FALSE, |
philpem@0 | 1973 | `endif |
philpem@0 | 1974 | `ifdef CFG_ROM_DEBUG_ENABLED |
philpem@0 | 1975 | `TRUE, |
philpem@0 | 1976 | `else |
philpem@0 | 1977 | `FALSE, |
philpem@0 | 1978 | `endif |
philpem@0 | 1979 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 1980 | `TRUE, |
philpem@0 | 1981 | `else |
philpem@0 | 1982 | `FALSE, |
philpem@0 | 1983 | `endif |
philpem@0 | 1984 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 1985 | `TRUE, |
philpem@0 | 1986 | `else |
philpem@0 | 1987 | `FALSE, |
philpem@0 | 1988 | `endif |
philpem@0 | 1989 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 1990 | `TRUE, |
philpem@0 | 1991 | `else |
philpem@0 | 1992 | `FALSE, |
philpem@0 | 1993 | `endif |
philpem@0 | 1994 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 1995 | `TRUE, |
philpem@0 | 1996 | `else |
philpem@0 | 1997 | `FALSE, |
philpem@0 | 1998 | `endif |
philpem@0 | 1999 | `ifdef CFG_CYCLE_COUNTER_ENABLED |
philpem@0 | 2000 | `TRUE, |
philpem@0 | 2001 | `else |
philpem@0 | 2002 | `FALSE, |
philpem@0 | 2003 | `endif |
philpem@0 | 2004 | `ifdef CFG_USER_ENABLED |
philpem@0 | 2005 | `TRUE, |
philpem@0 | 2006 | `else |
philpem@0 | 2007 | `FALSE, |
philpem@0 | 2008 | `endif |
philpem@0 | 2009 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 2010 | `TRUE, |
philpem@0 | 2011 | `else |
philpem@0 | 2012 | `FALSE, |
philpem@0 | 2013 | `endif |
philpem@0 | 2014 | `ifdef LM32_BARREL_SHIFT_ENABLED |
philpem@0 | 2015 | `TRUE, |
philpem@0 | 2016 | `else |
philpem@0 | 2017 | `FALSE, |
philpem@0 | 2018 | `endif |
philpem@0 | 2019 | `ifdef CFG_MC_DIVIDE_ENABLED |
philpem@0 | 2020 | `TRUE, |
philpem@0 | 2021 | `else |
philpem@0 | 2022 | `FALSE, |
philpem@0 | 2023 | `endif |
philpem@0 | 2024 | `ifdef LM32_MULTIPLY_ENABLED |
philpem@0 | 2025 | `TRUE |
philpem@0 | 2026 | `else |
philpem@0 | 2027 | `FALSE |
philpem@0 | 2028 | `endif |
philpem@0 | 2029 | }; |
philpem@0 | 2030 | |
philpem@0 | 2031 | assign cfg2 = { |
philpem@0 | 2032 | 30'b0, |
philpem@0 | 2033 | `ifdef CFG_IROM_ENABLED |
philpem@0 | 2034 | `TRUE, |
philpem@0 | 2035 | `else |
philpem@0 | 2036 | `FALSE, |
philpem@0 | 2037 | `endif |
philpem@0 | 2038 | `ifdef CFG_DRAM_ENABLED |
philpem@0 | 2039 | `TRUE |
philpem@0 | 2040 | `else |
philpem@0 | 2041 | `FALSE |
philpem@0 | 2042 | `endif |
philpem@0 | 2043 | }; |
philpem@0 | 2044 | |
philpem@0 | 2045 | // Cache flush |
philpem@0 | 2046 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 2047 | assign iflush = (csr_write_enable_d == `TRUE) |
philpem@0 | 2048 | && (csr_d == `LM32_CSR_ICC) |
philpem@0 | 2049 | && (stall_d == `FALSE) |
philpem@0 | 2050 | && (kill_d == `FALSE) |
philpem@0 | 2051 | && (valid_d == `TRUE); |
philpem@0 | 2052 | `endif |
philpem@0 | 2053 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 2054 | assign dflush_x = (csr_write_enable_q_x == `TRUE) |
philpem@0 | 2055 | && (csr_x == `LM32_CSR_DCC); |
philpem@0 | 2056 | `endif |
philpem@0 | 2057 | |
philpem@0 | 2058 | // Extract CSR index |
philpem@0 | 2059 | assign csr_d = read_idx_0_d[`LM32_CSR_RNG]; |
philpem@0 | 2060 | |
philpem@0 | 2061 | // CSR reads |
philpem@0 | 2062 | always @(*) |
philpem@0 | 2063 | begin |
philpem@0 | 2064 | case (csr_x) |
philpem@0 | 2065 | `ifdef CFG_INTERRUPTS_ENABLED |
philpem@0 | 2066 | `LM32_CSR_IE, |
philpem@0 | 2067 | `LM32_CSR_IM, |
philpem@0 | 2068 | `LM32_CSR_IP: csr_read_data_x = interrupt_csr_read_data_x; |
philpem@0 | 2069 | `endif |
philpem@0 | 2070 | `ifdef CFG_CYCLE_COUNTER_ENABLED |
philpem@0 | 2071 | `LM32_CSR_CC: csr_read_data_x = cc; |
philpem@0 | 2072 | `endif |
philpem@0 | 2073 | `LM32_CSR_CFG: csr_read_data_x = cfg; |
philpem@0 | 2074 | `LM32_CSR_EBA: csr_read_data_x = {eba, 8'h00}; |
philpem@0 | 2075 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2076 | `LM32_CSR_DEBA: csr_read_data_x = {deba, 8'h00}; |
philpem@0 | 2077 | `endif |
philpem@0 | 2078 | `ifdef CFG_JTAG_UART_ENABLED |
philpem@0 | 2079 | `LM32_CSR_JTX: csr_read_data_x = jtx_csr_read_data; |
philpem@0 | 2080 | `LM32_CSR_JRX: csr_read_data_x = jrx_csr_read_data; |
philpem@0 | 2081 | `endif |
philpem@0 | 2082 | `LM32_CSR_CFG2: csr_read_data_x = cfg2; |
philpem@0 | 2083 | |
philpem@0 | 2084 | default: csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}}; |
philpem@0 | 2085 | endcase |
philpem@0 | 2086 | end |
philpem@0 | 2087 | |
philpem@0 | 2088 | ///////////////////////////////////////////////////// |
philpem@0 | 2089 | // Sequential Logic |
philpem@0 | 2090 | ///////////////////////////////////////////////////// |
philpem@0 | 2091 | |
philpem@0 | 2092 | // Exception Base Address (EBA) CSR |
philpem@0 | 2093 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2094 | begin |
philpem@0 | 2095 | if (rst_i == `TRUE) |
philpem@0 | 2096 | eba <= eba_reset[`LM32_PC_WIDTH+2-1:8]; |
philpem@0 | 2097 | else |
philpem@0 | 2098 | begin |
philpem@0 | 2099 | if ((csr_write_enable_q_x == `TRUE) && (csr_x == `LM32_CSR_EBA) && (stall_x == `FALSE)) |
philpem@0 | 2100 | eba <= operand_1_x[`LM32_PC_WIDTH+2-1:8]; |
philpem@0 | 2101 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 2102 | if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_EBA)) |
philpem@0 | 2103 | eba <= jtag_csr_write_data[`LM32_PC_WIDTH+2-1:8]; |
philpem@0 | 2104 | `endif |
philpem@0 | 2105 | end |
philpem@0 | 2106 | end |
philpem@0 | 2107 | |
philpem@0 | 2108 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2109 | // Debug Exception Base Address (DEBA) CSR |
philpem@0 | 2110 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2111 | begin |
philpem@0 | 2112 | if (rst_i == `TRUE) |
philpem@0 | 2113 | deba <= deba_reset[`LM32_PC_WIDTH+2-1:8]; |
philpem@0 | 2114 | else |
philpem@0 | 2115 | begin |
philpem@0 | 2116 | if ((csr_write_enable_q_x == `TRUE) && (csr_x == `LM32_CSR_DEBA) && (stall_x == `FALSE)) |
philpem@0 | 2117 | deba <= operand_1_x[`LM32_PC_WIDTH+2-1:8]; |
philpem@0 | 2118 | `ifdef CFG_HW_DEBUG_ENABLED |
philpem@0 | 2119 | if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_DEBA)) |
philpem@0 | 2120 | deba <= jtag_csr_write_data[`LM32_PC_WIDTH+2-1:8]; |
philpem@0 | 2121 | `endif |
philpem@0 | 2122 | end |
philpem@0 | 2123 | end |
philpem@0 | 2124 | `endif |
philpem@0 | 2125 | |
philpem@0 | 2126 | // Cycle Counter (CC) CSR |
philpem@0 | 2127 | `ifdef CFG_CYCLE_COUNTER_ENABLED |
philpem@0 | 2128 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2129 | begin |
philpem@0 | 2130 | if (rst_i == `TRUE) |
philpem@0 | 2131 | cc <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2132 | else |
philpem@0 | 2133 | cc <= cc + 1'b1; |
philpem@0 | 2134 | end |
philpem@0 | 2135 | `endif |
philpem@0 | 2136 | |
philpem@0 | 2137 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2138 | // Watch for data bus errors |
philpem@0 | 2139 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2140 | begin |
philpem@0 | 2141 | if (rst_i == `TRUE) |
philpem@0 | 2142 | data_bus_error_seen <= `FALSE; |
philpem@0 | 2143 | else |
philpem@0 | 2144 | begin |
philpem@0 | 2145 | // Set flag when bus error is detected |
philpem@0 | 2146 | if ((D_ERR_I == `TRUE) && (D_CYC_O == `TRUE)) |
philpem@0 | 2147 | data_bus_error_seen <= `TRUE; |
philpem@0 | 2148 | // Clear flag when exception is taken |
philpem@0 | 2149 | if ((exception_m == `TRUE) && (kill_m == `FALSE)) |
philpem@0 | 2150 | data_bus_error_seen <= `FALSE; |
philpem@0 | 2151 | end |
philpem@0 | 2152 | end |
philpem@0 | 2153 | `endif |
philpem@0 | 2154 | |
philpem@0 | 2155 | // Valid bits to indicate whether an instruction in a partcular pipeline stage is valid or not |
philpem@0 | 2156 | |
philpem@0 | 2157 | `ifdef CFG_ICACHE_ENABLED |
philpem@0 | 2158 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 2159 | always @(*) |
philpem@0 | 2160 | begin |
philpem@0 | 2161 | if ( (icache_refill_request == `TRUE) |
philpem@0 | 2162 | || (dcache_refill_request == `TRUE) |
philpem@0 | 2163 | ) |
philpem@0 | 2164 | valid_a = `FALSE; |
philpem@0 | 2165 | else if ( (icache_restart_request == `TRUE) |
philpem@0 | 2166 | || (dcache_restart_request == `TRUE) |
philpem@0 | 2167 | ) |
philpem@0 | 2168 | valid_a = `TRUE; |
philpem@0 | 2169 | else |
philpem@0 | 2170 | valid_a = !icache_refilling && !dcache_refilling; |
philpem@0 | 2171 | end |
philpem@0 | 2172 | `else |
philpem@0 | 2173 | always @(*) |
philpem@0 | 2174 | begin |
philpem@0 | 2175 | if (icache_refill_request == `TRUE) |
philpem@0 | 2176 | valid_a = `FALSE; |
philpem@0 | 2177 | else if (icache_restart_request == `TRUE) |
philpem@0 | 2178 | valid_a = `TRUE; |
philpem@0 | 2179 | else |
philpem@0 | 2180 | valid_a = !icache_refilling; |
philpem@0 | 2181 | end |
philpem@0 | 2182 | `endif |
philpem@0 | 2183 | `else |
philpem@0 | 2184 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 2185 | always @(*) |
philpem@0 | 2186 | begin |
philpem@0 | 2187 | if (dcache_refill_request == `TRUE) |
philpem@0 | 2188 | valid_a = `FALSE; |
philpem@0 | 2189 | else if (dcache_restart_request == `TRUE) |
philpem@0 | 2190 | valid_a = `TRUE; |
philpem@0 | 2191 | else |
philpem@0 | 2192 | valid_a = !dcache_refilling; |
philpem@0 | 2193 | end |
philpem@0 | 2194 | `endif |
philpem@0 | 2195 | `endif |
philpem@0 | 2196 | |
philpem@0 | 2197 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2198 | begin |
philpem@0 | 2199 | if (rst_i == `TRUE) |
philpem@0 | 2200 | begin |
philpem@0 | 2201 | valid_f <= `FALSE; |
philpem@0 | 2202 | valid_d <= `FALSE; |
philpem@0 | 2203 | valid_x <= `FALSE; |
philpem@0 | 2204 | valid_m <= `FALSE; |
philpem@0 | 2205 | valid_w <= `FALSE; |
philpem@0 | 2206 | end |
philpem@0 | 2207 | else |
philpem@0 | 2208 | begin |
philpem@0 | 2209 | if ((kill_f == `TRUE) || (stall_a == `FALSE)) |
philpem@0 | 2210 | `ifdef LM32_CACHE_ENABLED |
philpem@0 | 2211 | valid_f <= valid_a; |
philpem@0 | 2212 | `else |
philpem@0 | 2213 | valid_f <= `TRUE; |
philpem@0 | 2214 | `endif |
philpem@0 | 2215 | else if (stall_f == `FALSE) |
philpem@0 | 2216 | valid_f <= `FALSE; |
philpem@0 | 2217 | |
philpem@0 | 2218 | if (kill_d == `TRUE) |
philpem@0 | 2219 | valid_d <= `FALSE; |
philpem@0 | 2220 | else if (stall_f == `FALSE) |
philpem@0 | 2221 | valid_d <= valid_f & !kill_f; |
philpem@0 | 2222 | else if (stall_d == `FALSE) |
philpem@0 | 2223 | valid_d <= `FALSE; |
philpem@0 | 2224 | |
philpem@0 | 2225 | if (stall_d == `FALSE) |
philpem@0 | 2226 | valid_x <= valid_d & !kill_d; |
philpem@0 | 2227 | else if (kill_x == `TRUE) |
philpem@0 | 2228 | valid_x <= `FALSE; |
philpem@0 | 2229 | else if (stall_x == `FALSE) |
philpem@0 | 2230 | valid_x <= `FALSE; |
philpem@0 | 2231 | |
philpem@0 | 2232 | if (kill_m == `TRUE) |
philpem@0 | 2233 | valid_m <= `FALSE; |
philpem@0 | 2234 | else if (stall_x == `FALSE) |
philpem@0 | 2235 | valid_m <= valid_x & !kill_x; |
philpem@0 | 2236 | else if (stall_m == `FALSE) |
philpem@0 | 2237 | valid_m <= `FALSE; |
philpem@0 | 2238 | |
philpem@0 | 2239 | if (stall_m == `FALSE) |
philpem@0 | 2240 | valid_w <= valid_m & !kill_m; |
philpem@0 | 2241 | else |
philpem@0 | 2242 | valid_w <= `FALSE; |
philpem@0 | 2243 | end |
philpem@0 | 2244 | end |
philpem@0 | 2245 | |
philpem@0 | 2246 | // Microcode pipeline registers |
philpem@0 | 2247 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2248 | begin |
philpem@0 | 2249 | if (rst_i == `TRUE) |
philpem@0 | 2250 | begin |
philpem@0 | 2251 | `ifdef CFG_USER_ENABLED |
philpem@0 | 2252 | user_opcode <= {`LM32_USER_OPCODE_WIDTH{1'b0}}; |
philpem@0 | 2253 | `endif |
philpem@0 | 2254 | operand_0_x <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2255 | operand_1_x <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2256 | store_operand_x <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2257 | branch_target_x <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2258 | x_result_sel_csr_x <= `FALSE; |
philpem@0 | 2259 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 2260 | x_result_sel_mc_arith_x <= `FALSE; |
philpem@0 | 2261 | `endif |
philpem@0 | 2262 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 2263 | x_result_sel_shift_x <= `FALSE; |
philpem@0 | 2264 | `endif |
philpem@0 | 2265 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 2266 | x_result_sel_sext_x <= `FALSE; |
philpem@0 | 2267 | `endif |
philpem@0 | 2268 | x_result_sel_logic_x <= `FALSE; |
philpem@0 | 2269 | `ifdef CFG_USER_ENABLED |
philpem@0 | 2270 | x_result_sel_user_x <= `FALSE; |
philpem@0 | 2271 | `endif |
philpem@0 | 2272 | x_result_sel_add_x <= `FALSE; |
philpem@0 | 2273 | m_result_sel_compare_x <= `FALSE; |
philpem@0 | 2274 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2275 | m_result_sel_shift_x <= `FALSE; |
philpem@0 | 2276 | `endif |
philpem@0 | 2277 | w_result_sel_load_x <= `FALSE; |
philpem@0 | 2278 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2279 | w_result_sel_mul_x <= `FALSE; |
philpem@0 | 2280 | `endif |
philpem@0 | 2281 | x_bypass_enable_x <= `FALSE; |
philpem@0 | 2282 | m_bypass_enable_x <= `FALSE; |
philpem@0 | 2283 | write_enable_x <= `FALSE; |
philpem@0 | 2284 | write_idx_x <= {`LM32_REG_IDX_WIDTH{1'b0}}; |
philpem@0 | 2285 | csr_x <= {`LM32_CSR_WIDTH{1'b0}}; |
philpem@0 | 2286 | load_x <= `FALSE; |
philpem@0 | 2287 | store_x <= `FALSE; |
philpem@0 | 2288 | size_x <= {`LM32_SIZE_WIDTH{1'b0}}; |
philpem@0 | 2289 | sign_extend_x <= `FALSE; |
philpem@0 | 2290 | adder_op_x <= `FALSE; |
philpem@0 | 2291 | adder_op_x_n <= `FALSE; |
philpem@0 | 2292 | logic_op_x <= 4'h0; |
philpem@0 | 2293 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2294 | direction_x <= `FALSE; |
philpem@0 | 2295 | `endif |
philpem@0 | 2296 | `ifdef CFG_ROTATE_ENABLED |
philpem@0 | 2297 | rotate_x <= `FALSE; |
philpem@0 | 2298 | |
philpem@0 | 2299 | `endif |
philpem@0 | 2300 | branch_x <= `FALSE; |
philpem@0 | 2301 | branch_predict_x <= `FALSE; |
philpem@0 | 2302 | branch_predict_taken_x <= `FALSE; |
philpem@0 | 2303 | condition_x <= `LM32_CONDITION_U1; |
philpem@0 | 2304 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2305 | break_x <= `FALSE; |
philpem@0 | 2306 | `endif |
philpem@0 | 2307 | scall_x <= `FALSE; |
philpem@0 | 2308 | eret_x <= `FALSE; |
philpem@0 | 2309 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2310 | bret_x <= `FALSE; |
philpem@0 | 2311 | `endif |
philpem@0 | 2312 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2313 | bus_error_x <= `FALSE; |
philpem@0 | 2314 | data_bus_error_exception_m <= `FALSE; |
philpem@0 | 2315 | `endif |
philpem@0 | 2316 | csr_write_enable_x <= `FALSE; |
philpem@0 | 2317 | operand_m <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2318 | branch_target_m <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2319 | m_result_sel_compare_m <= `FALSE; |
philpem@0 | 2320 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2321 | m_result_sel_shift_m <= `FALSE; |
philpem@0 | 2322 | `endif |
philpem@0 | 2323 | w_result_sel_load_m <= `FALSE; |
philpem@0 | 2324 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2325 | w_result_sel_mul_m <= `FALSE; |
philpem@0 | 2326 | `endif |
philpem@0 | 2327 | m_bypass_enable_m <= `FALSE; |
philpem@0 | 2328 | branch_m <= `FALSE; |
philpem@0 | 2329 | branch_predict_m <= `FALSE; |
philpem@0 | 2330 | branch_predict_taken_m <= `FALSE; |
philpem@0 | 2331 | exception_m <= `FALSE; |
philpem@0 | 2332 | load_m <= `FALSE; |
philpem@0 | 2333 | store_m <= `FALSE; |
philpem@0 | 2334 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2335 | direction_m <= `FALSE; |
philpem@0 | 2336 | `endif |
philpem@0 | 2337 | write_enable_m <= `FALSE; |
philpem@0 | 2338 | write_idx_m <= {`LM32_REG_IDX_WIDTH{1'b0}}; |
philpem@0 | 2339 | condition_met_m <= `FALSE; |
philpem@0 | 2340 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 2341 | dflush_m <= `FALSE; |
philpem@0 | 2342 | `endif |
philpem@0 | 2343 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2344 | debug_exception_m <= `FALSE; |
philpem@0 | 2345 | non_debug_exception_m <= `FALSE; |
philpem@0 | 2346 | `endif |
philpem@0 | 2347 | operand_w <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2348 | w_result_sel_load_w <= `FALSE; |
philpem@0 | 2349 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2350 | w_result_sel_mul_w <= `FALSE; |
philpem@0 | 2351 | `endif |
philpem@0 | 2352 | write_idx_w <= {`LM32_REG_IDX_WIDTH{1'b0}}; |
philpem@0 | 2353 | write_enable_w <= `FALSE; |
philpem@0 | 2354 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2355 | debug_exception_w <= `FALSE; |
philpem@0 | 2356 | non_debug_exception_w <= `FALSE; |
philpem@0 | 2357 | `else |
philpem@0 | 2358 | exception_w <= `FALSE; |
philpem@0 | 2359 | `endif |
philpem@0 | 2360 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2361 | memop_pc_w <= {`LM32_PC_WIDTH{1'b0}}; |
philpem@0 | 2362 | `endif |
philpem@0 | 2363 | end |
philpem@0 | 2364 | else |
philpem@0 | 2365 | begin |
philpem@0 | 2366 | // D/X stage registers |
philpem@0 | 2367 | |
philpem@0 | 2368 | if (stall_x == `FALSE) |
philpem@0 | 2369 | begin |
philpem@0 | 2370 | `ifdef CFG_USER_ENABLED |
philpem@0 | 2371 | user_opcode <= user_opcode_d; |
philpem@0 | 2372 | `endif |
philpem@0 | 2373 | operand_0_x <= d_result_0; |
philpem@0 | 2374 | operand_1_x <= d_result_1; |
philpem@0 | 2375 | store_operand_x <= bypass_data_1; |
philpem@0 | 2376 | branch_target_x <= branch_reg_d == `TRUE ? bypass_data_0[`LM32_PC_RNG] : branch_target_d; |
philpem@0 | 2377 | x_result_sel_csr_x <= x_result_sel_csr_d; |
philpem@0 | 2378 | `ifdef LM32_MC_ARITHMETIC_ENABLED |
philpem@0 | 2379 | x_result_sel_mc_arith_x <= x_result_sel_mc_arith_d; |
philpem@0 | 2380 | `endif |
philpem@0 | 2381 | `ifdef LM32_NO_BARREL_SHIFT |
philpem@0 | 2382 | x_result_sel_shift_x <= x_result_sel_shift_d; |
philpem@0 | 2383 | `endif |
philpem@0 | 2384 | `ifdef CFG_SIGN_EXTEND_ENABLED |
philpem@0 | 2385 | x_result_sel_sext_x <= x_result_sel_sext_d; |
philpem@0 | 2386 | `endif |
philpem@0 | 2387 | x_result_sel_logic_x <= x_result_sel_logic_d; |
philpem@0 | 2388 | `ifdef CFG_USER_ENABLED |
philpem@0 | 2389 | x_result_sel_user_x <= x_result_sel_user_d; |
philpem@0 | 2390 | `endif |
philpem@0 | 2391 | x_result_sel_add_x <= x_result_sel_add_d; |
philpem@0 | 2392 | m_result_sel_compare_x <= m_result_sel_compare_d; |
philpem@0 | 2393 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2394 | m_result_sel_shift_x <= m_result_sel_shift_d; |
philpem@0 | 2395 | `endif |
philpem@0 | 2396 | w_result_sel_load_x <= w_result_sel_load_d; |
philpem@0 | 2397 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2398 | w_result_sel_mul_x <= w_result_sel_mul_d; |
philpem@0 | 2399 | `endif |
philpem@0 | 2400 | x_bypass_enable_x <= x_bypass_enable_d; |
philpem@0 | 2401 | m_bypass_enable_x <= m_bypass_enable_d; |
philpem@0 | 2402 | load_x <= load_d; |
philpem@0 | 2403 | store_x <= store_d; |
philpem@0 | 2404 | branch_x <= branch_d; |
philpem@0 | 2405 | branch_predict_x <= branch_predict_d; |
philpem@0 | 2406 | branch_predict_taken_x <= branch_predict_taken_d; |
philpem@0 | 2407 | write_idx_x <= write_idx_d; |
philpem@0 | 2408 | csr_x <= csr_d; |
philpem@0 | 2409 | size_x <= size_d; |
philpem@0 | 2410 | sign_extend_x <= sign_extend_d; |
philpem@0 | 2411 | adder_op_x <= adder_op_d; |
philpem@0 | 2412 | adder_op_x_n <= ~adder_op_d; |
philpem@0 | 2413 | logic_op_x <= logic_op_d; |
philpem@0 | 2414 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2415 | direction_x <= direction_d; |
philpem@0 | 2416 | `endif |
philpem@0 | 2417 | `ifdef CFG_ROTATE_ENABLED |
philpem@0 | 2418 | rotate_x <= rotate_d; |
philpem@0 | 2419 | `endif |
philpem@0 | 2420 | condition_x <= condition_d; |
philpem@0 | 2421 | csr_write_enable_x <= csr_write_enable_d; |
philpem@0 | 2422 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2423 | break_x <= break_d; |
philpem@0 | 2424 | `endif |
philpem@0 | 2425 | scall_x <= scall_d; |
philpem@0 | 2426 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2427 | bus_error_x <= bus_error_d; |
philpem@0 | 2428 | `endif |
philpem@0 | 2429 | eret_x <= eret_d; |
philpem@0 | 2430 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2431 | bret_x <= bret_d; |
philpem@0 | 2432 | `endif |
philpem@0 | 2433 | write_enable_x <= write_enable_d; |
philpem@0 | 2434 | end |
philpem@0 | 2435 | |
philpem@0 | 2436 | // X/M stage registers |
philpem@0 | 2437 | |
philpem@0 | 2438 | if (stall_m == `FALSE) |
philpem@0 | 2439 | begin |
philpem@0 | 2440 | operand_m <= x_result; |
philpem@0 | 2441 | m_result_sel_compare_m <= m_result_sel_compare_x; |
philpem@0 | 2442 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2443 | m_result_sel_shift_m <= m_result_sel_shift_x; |
philpem@0 | 2444 | `endif |
philpem@0 | 2445 | if (exception_x == `TRUE) |
philpem@0 | 2446 | begin |
philpem@0 | 2447 | w_result_sel_load_m <= `FALSE; |
philpem@0 | 2448 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2449 | w_result_sel_mul_m <= `FALSE; |
philpem@0 | 2450 | `endif |
philpem@0 | 2451 | end |
philpem@0 | 2452 | else |
philpem@0 | 2453 | begin |
philpem@0 | 2454 | w_result_sel_load_m <= w_result_sel_load_x; |
philpem@0 | 2455 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2456 | w_result_sel_mul_m <= w_result_sel_mul_x; |
philpem@0 | 2457 | `endif |
philpem@0 | 2458 | end |
philpem@0 | 2459 | m_bypass_enable_m <= m_bypass_enable_x; |
philpem@0 | 2460 | `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
philpem@0 | 2461 | direction_m <= direction_x; |
philpem@0 | 2462 | `endif |
philpem@0 | 2463 | load_m <= load_x; |
philpem@0 | 2464 | store_m <= store_x; |
philpem@0 | 2465 | `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
philpem@0 | 2466 | branch_m <= branch_x && !branch_taken_x; |
philpem@0 | 2467 | `else |
philpem@0 | 2468 | branch_m <= branch_x; |
philpem@0 | 2469 | branch_predict_m <= branch_predict_x; |
philpem@0 | 2470 | branch_predict_taken_m <= branch_predict_taken_x; |
philpem@0 | 2471 | `endif |
philpem@0 | 2472 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2473 | // Data bus errors are generated by the wishbone and are |
philpem@0 | 2474 | // made known to the processor only in next cycle (as a |
philpem@0 | 2475 | // non-debug exception). A break instruction can be seen |
philpem@0 | 2476 | // in same cycle (causing a debug exception). Handle non |
philpem@0 | 2477 | // -debug exception first! |
philpem@0 | 2478 | if (non_debug_exception_x == `TRUE) |
philpem@0 | 2479 | write_idx_m <= `LM32_EA_REG; |
philpem@0 | 2480 | else if (debug_exception_x == `TRUE) |
philpem@0 | 2481 | write_idx_m <= `LM32_BA_REG; |
philpem@0 | 2482 | else |
philpem@0 | 2483 | write_idx_m <= write_idx_x; |
philpem@0 | 2484 | `else |
philpem@0 | 2485 | if (exception_x == `TRUE) |
philpem@0 | 2486 | write_idx_m <= `LM32_EA_REG; |
philpem@0 | 2487 | else |
philpem@0 | 2488 | write_idx_m <= write_idx_x; |
philpem@0 | 2489 | `endif |
philpem@0 | 2490 | condition_met_m <= condition_met_x; |
philpem@0 | 2491 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2492 | if (exception_x == `TRUE) |
philpem@0 | 2493 | if ((dc_re == `TRUE) |
philpem@0 | 2494 | || ((debug_exception_x == `TRUE) |
philpem@0 | 2495 | && (non_debug_exception_x == `FALSE))) |
philpem@0 | 2496 | branch_target_m <= {deba, eid_x, {3{1'b0}}}; |
philpem@0 | 2497 | else |
philpem@0 | 2498 | branch_target_m <= {eba, eid_x, {3{1'b0}}}; |
philpem@0 | 2499 | else |
philpem@0 | 2500 | branch_target_m <= branch_target_x; |
philpem@0 | 2501 | `else |
philpem@0 | 2502 | branch_target_m <= exception_x == `TRUE ? {eba, eid_x, {3{1'b0}}} : branch_target_x; |
philpem@0 | 2503 | `endif |
philpem@0 | 2504 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 2505 | eid_m <= eid_x; |
philpem@0 | 2506 | `endif |
philpem@0 | 2507 | `ifdef CFG_DCACHE_ENABLED |
philpem@0 | 2508 | dflush_m <= dflush_x; |
philpem@0 | 2509 | `endif |
philpem@0 | 2510 | eret_m <= eret_q_x; |
philpem@0 | 2511 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2512 | bret_m <= bret_q_x; |
philpem@0 | 2513 | `endif |
philpem@0 | 2514 | write_enable_m <= exception_x == `TRUE ? `TRUE : write_enable_x; |
philpem@0 | 2515 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2516 | debug_exception_m <= debug_exception_x; |
philpem@0 | 2517 | non_debug_exception_m <= non_debug_exception_x; |
philpem@0 | 2518 | `endif |
philpem@0 | 2519 | end |
philpem@0 | 2520 | |
philpem@0 | 2521 | // State changing regs |
philpem@0 | 2522 | if (stall_m == `FALSE) |
philpem@0 | 2523 | begin |
philpem@0 | 2524 | if ((exception_x == `TRUE) && (q_x == `TRUE) && (stall_x == `FALSE)) |
philpem@0 | 2525 | exception_m <= `TRUE; |
philpem@0 | 2526 | else |
philpem@0 | 2527 | exception_m <= `FALSE; |
philpem@0 | 2528 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2529 | data_bus_error_exception_m <= (data_bus_error_exception == `TRUE) |
philpem@0 | 2530 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2531 | && (reset_exception == `FALSE) |
philpem@0 | 2532 | `endif |
philpem@0 | 2533 | ; |
philpem@0 | 2534 | `endif |
philpem@0 | 2535 | end |
philpem@0 | 2536 | |
philpem@0 | 2537 | // M/W stage registers |
philpem@0 | 2538 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2539 | operand_w <= exception_m == `TRUE ? (data_bus_error_exception_m ? {memop_pc_w, 2'b00} : {pc_m, 2'b00}) : m_result; |
philpem@0 | 2540 | `else |
philpem@0 | 2541 | operand_w <= exception_m == `TRUE ? {pc_m, 2'b00} : m_result; |
philpem@0 | 2542 | `endif |
philpem@0 | 2543 | w_result_sel_load_w <= w_result_sel_load_m; |
philpem@0 | 2544 | `ifdef CFG_PL_MULTIPLY_ENABLED |
philpem@0 | 2545 | w_result_sel_mul_w <= w_result_sel_mul_m; |
philpem@0 | 2546 | `endif |
philpem@0 | 2547 | write_idx_w <= write_idx_m; |
philpem@0 | 2548 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 2549 | eid_w <= eid_m; |
philpem@0 | 2550 | eret_w <= eret_m; |
philpem@0 | 2551 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2552 | bret_w <= bret_m; |
philpem@0 | 2553 | `endif |
philpem@0 | 2554 | `endif |
philpem@0 | 2555 | write_enable_w <= write_enable_m; |
philpem@0 | 2556 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2557 | debug_exception_w <= debug_exception_m; |
philpem@0 | 2558 | non_debug_exception_w <= non_debug_exception_m; |
philpem@0 | 2559 | `else |
philpem@0 | 2560 | exception_w <= exception_m; |
philpem@0 | 2561 | `endif |
philpem@0 | 2562 | `ifdef CFG_BUS_ERRORS_ENABLED |
philpem@0 | 2563 | if ( (stall_m == `FALSE) |
philpem@0 | 2564 | && ( (load_q_m == `TRUE) |
philpem@0 | 2565 | || (store_q_m == `TRUE) |
philpem@0 | 2566 | ) |
philpem@0 | 2567 | ) |
philpem@0 | 2568 | memop_pc_w <= pc_m; |
philpem@0 | 2569 | `endif |
philpem@0 | 2570 | end |
philpem@0 | 2571 | end |
philpem@0 | 2572 | |
philpem@0 | 2573 | `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
philpem@0 | 2574 | // Buffer data read from register file, in case a stall occurs, and watch for |
philpem@0 | 2575 | // any writes to the modified registers |
philpem@0 | 2576 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2577 | begin |
philpem@0 | 2578 | if (rst_i == `TRUE) |
philpem@0 | 2579 | begin |
philpem@0 | 2580 | use_buf <= `FALSE; |
philpem@0 | 2581 | reg_data_buf_0 <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2582 | reg_data_buf_1 <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2583 | end |
philpem@0 | 2584 | else |
philpem@0 | 2585 | begin |
philpem@0 | 2586 | if (stall_d == `FALSE) |
philpem@0 | 2587 | use_buf <= `FALSE; |
philpem@0 | 2588 | else if (use_buf == `FALSE) |
philpem@0 | 2589 | begin |
philpem@0 | 2590 | reg_data_buf_0 <= reg_data_live_0; |
philpem@0 | 2591 | reg_data_buf_1 <= reg_data_live_1; |
philpem@0 | 2592 | use_buf <= `TRUE; |
philpem@0 | 2593 | end |
philpem@0 | 2594 | if (reg_write_enable_q_w == `TRUE) |
philpem@0 | 2595 | begin |
philpem@0 | 2596 | if (write_idx_w == read_idx_0_d) |
philpem@0 | 2597 | reg_data_buf_0 <= w_result; |
philpem@0 | 2598 | if (write_idx_w == read_idx_1_d) |
philpem@0 | 2599 | reg_data_buf_1 <= w_result; |
philpem@0 | 2600 | end |
philpem@0 | 2601 | end |
philpem@0 | 2602 | end |
philpem@0 | 2603 | `endif |
philpem@0 | 2604 | |
philpem@0 | 2605 | `ifdef LM32_EBR_REGISTER_FILE |
philpem@0 | 2606 | `else |
philpem@0 | 2607 | // Register file write port |
philpem@0 | 2608 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2609 | begin |
philpem@0 | 2610 | if (rst_i == `TRUE) begin |
philpem@0 | 2611 | registers[0] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2612 | registers[1] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2613 | registers[2] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2614 | registers[3] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2615 | registers[4] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2616 | registers[5] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2617 | registers[6] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2618 | registers[7] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2619 | registers[8] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2620 | registers[9] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2621 | registers[10] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2622 | registers[11] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2623 | registers[12] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2624 | registers[13] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2625 | registers[14] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2626 | registers[15] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2627 | registers[16] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2628 | registers[17] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2629 | registers[18] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2630 | registers[19] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2631 | registers[20] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2632 | registers[21] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2633 | registers[22] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2634 | registers[23] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2635 | registers[24] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2636 | registers[25] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2637 | registers[26] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2638 | registers[27] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2639 | registers[28] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2640 | registers[29] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2641 | registers[30] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2642 | registers[31] <= {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2643 | end |
philpem@0 | 2644 | else begin |
philpem@0 | 2645 | if (reg_write_enable_q_w == `TRUE) |
philpem@0 | 2646 | registers[write_idx_w] <= w_result; |
philpem@0 | 2647 | end |
philpem@0 | 2648 | end |
philpem@0 | 2649 | `endif |
philpem@0 | 2650 | |
philpem@0 | 2651 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 2652 | // PC tracing logic |
philpem@0 | 2653 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 2654 | begin |
philpem@0 | 2655 | if (rst_i == `TRUE) |
philpem@0 | 2656 | begin |
philpem@0 | 2657 | trace_pc_valid <= `FALSE; |
philpem@0 | 2658 | trace_pc <= {`LM32_PC_WIDTH{1'b0}}; |
philpem@0 | 2659 | trace_exception <= `FALSE; |
philpem@0 | 2660 | trace_eid <= `LM32_EID_RESET; |
philpem@0 | 2661 | trace_eret <= `FALSE; |
philpem@0 | 2662 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2663 | trace_bret <= `FALSE; |
philpem@0 | 2664 | `endif |
philpem@0 | 2665 | pc_c <= `CFG_EBA_RESET/4; |
philpem@0 | 2666 | end |
philpem@0 | 2667 | else |
philpem@0 | 2668 | begin |
philpem@0 | 2669 | trace_pc_valid <= `FALSE; |
philpem@0 | 2670 | // Has an exception occured |
philpem@0 | 2671 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2672 | if ((debug_exception_q_w == `TRUE) || (non_debug_exception_q_w == `TRUE)) |
philpem@0 | 2673 | `else |
philpem@0 | 2674 | if (exception_q_w == `TRUE) |
philpem@0 | 2675 | `endif |
philpem@0 | 2676 | begin |
philpem@0 | 2677 | trace_exception <= `TRUE; |
philpem@0 | 2678 | trace_pc_valid <= `TRUE; |
philpem@0 | 2679 | trace_pc <= pc_w; |
philpem@0 | 2680 | trace_eid <= eid_w; |
philpem@0 | 2681 | end |
philpem@0 | 2682 | else |
philpem@0 | 2683 | trace_exception <= `FALSE; |
philpem@0 | 2684 | |
philpem@0 | 2685 | if ((valid_w == `TRUE) && (!kill_w)) |
philpem@0 | 2686 | begin |
philpem@0 | 2687 | // An instruction is commiting. Determine if it is non-sequential |
philpem@0 | 2688 | if (pc_c + 1'b1 != pc_w) |
philpem@0 | 2689 | begin |
philpem@0 | 2690 | // Non-sequential instruction |
philpem@0 | 2691 | trace_pc_valid <= `TRUE; |
philpem@0 | 2692 | trace_pc <= pc_w; |
philpem@0 | 2693 | end |
philpem@0 | 2694 | // Record PC so we can determine if next instruction is sequential or not |
philpem@0 | 2695 | pc_c <= pc_w; |
philpem@0 | 2696 | // Indicate if it was an eret/bret instruction |
philpem@0 | 2697 | trace_eret <= eret_w; |
philpem@0 | 2698 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2699 | trace_bret <= bret_w; |
philpem@0 | 2700 | `endif |
philpem@0 | 2701 | end |
philpem@0 | 2702 | else |
philpem@0 | 2703 | begin |
philpem@0 | 2704 | trace_eret <= `FALSE; |
philpem@0 | 2705 | `ifdef CFG_DEBUG_ENABLED |
philpem@0 | 2706 | trace_bret <= `FALSE; |
philpem@0 | 2707 | `endif |
philpem@0 | 2708 | end |
philpem@0 | 2709 | end |
philpem@0 | 2710 | end |
philpem@0 | 2711 | `endif |
philpem@0 | 2712 | |
philpem@0 | 2713 | ///////////////////////////////////////////////////// |
philpem@0 | 2714 | // Behavioural Logic |
philpem@0 | 2715 | ///////////////////////////////////////////////////// |
philpem@0 | 2716 | |
philpem@0 | 2717 | // synthesis translate_off |
philpem@0 | 2718 | |
philpem@0 | 2719 | // Reset register 0. Only needed for simulation. |
philpem@0 | 2720 | initial |
philpem@0 | 2721 | begin |
philpem@0 | 2722 | `ifdef LM32_EBR_REGISTER_FILE |
philpem@0 | 2723 | reg_0.mem[0] = {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2724 | reg_1.mem[0] = {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2725 | `else |
philpem@0 | 2726 | registers[0] = {`LM32_WORD_WIDTH{1'b0}}; |
philpem@0 | 2727 | `endif |
philpem@0 | 2728 | end |
philpem@0 | 2729 | |
philpem@0 | 2730 | // synthesis translate_on |
philpem@0 | 2731 | |
philpem@0 | 2732 | endmodule |