| // ================================================================== |
| // >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< |
| // ------------------------------------------------------------------ |
| // Copyright (c) 2006-2011 by Lattice Semiconductor Corporation |
| // Copyright (c) 2011-2012 Yann Sionneau <yann.sionneau@gmail.com> |
| // Copyright (c) 2012 Michael Walle <michael@walle.cc> |
| // ALL RIGHTS RESERVED |
| // ------------------------------------------------------------------ |
| // |
| // IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM. |
| // |
| // Permission: |
| // |
| // Lattice Semiconductor grants permission to use this code |
| // pursuant to the terms of the Lattice Semiconductor Corporation |
| // Open Source License Agreement. |
| // |
| // Disclaimer: |
| // |
| // Lattice Semiconductor provides no warranty regarding the use or |
| // functionality of this code. It is the user's responsibility to |
| // verify the user's design for consistency and functionality through |
| // the use of formal verification methods. |
| // |
| // -------------------------------------------------------------------- |
| // |
| // Lattice Semiconductor Corporation |
| // 5555 NE Moore Court |
| // Hillsboro, OR 97214 |
| // U.S.A |
| // |
| // TEL: 1-800-Lattice (USA and Canada) |
| // 503-286-8001 (other locations) |
| // |
| // web: http://www.latticesemi.com/ |
| // email: techsupport@latticesemi.com |
| // |
| // -------------------------------------------------------------------- |
| // FILE DETAILS |
| // Project : LatticeMico32 |
| // File : lm32_cpu.v |
| // Title : Top-level of CPU. |
| // Dependencies : lm32_include.v |
| // |
| // Version 3.8 |
| // 1. Feature: Support for dynamically switching EBA to DEBA via a GPIO. |
| // 2. Bug: EA now reports instruction that caused the data abort, rather than |
| // next instruction. |
| // |
| // Version 3.4 |
| // 1. Bug Fix: In a tight infinite loop (add, sw, bi) incoming interrupts were |
| // never serviced. |
| // |
| // Version 3.3 |
| // 1. Feature: Support for memory that is tightly coupled to processor core, and |
| // has a single-cycle access latency (same as caches). Instruction port has |
| // access to a dedicated physically-mapped memory. Data port has access to |
| // a dedicated physically-mapped memory. In order to be able to manipulate |
| // values in both these memories via the debugger, these memories also |
| // interface with the data port of LM32. |
| // 2. Feature: Extended Configuration Register |
| // 3. Bug Fix: Removed port names that conflict with keywords reserved in System- |
| // Verilog. |
| // |
| // Version 3.2 |
| // 1. Bug Fix: Single-stepping a load/store to invalid address causes debugger to |
| // hang. At the same time CPU fails to register data bus error exception. Bug |
| // is caused because (a) data bus error exception occurs after load/store has |
| // passed X stage and next sequential instruction (e.g., brk) is already in X |
| // stage, and (b) data bus error exception had lower priority than, say, brk |
| // exception. |
| // 2. Bug Fix: If a brk (or scall/eret/bret) sequentially follows a load/store to |
| // invalid location, CPU will fail to register data bus error exception. The |
| // solution is to stall scall/eret/bret/brk instructions in D pipeline stage |
| // until load/store has completed. |
| // 3. Feature: Enable precise identification of load/store that causes seg fault. |
| // 4. SYNC resets used for register file when implemented in EBRs. |
| // |
| // Version 3.1 |
| // 1. Feature: LM32 Register File can now be mapped in to on-chip block RAM (EBR) |
| // instead of distributed memory by enabling the option in LM32 GUI. |
| // 2. Feature: LM32 also adds a static branch predictor to improve branch |
| // performance. All immediate-based forward-pointing branches are predicted |
| // not-taken. All immediate-based backward-pointing branches are predicted taken. |
| // |
| // Version 7.0SP2, 3.0 |
| // No Change |
| // |
| // Version 6.1.17 |
| // Initial Release |
| // ============================================================================= |
| |
| `include "lm32_include.v" |
| |
| ///////////////////////////////////////////////////// |
| // Module interface |
| ///////////////////////////////////////////////////// |
| |
| module lm32_cpu ( |
| // ----- Inputs ------- |
| clk_i, |
| `ifdef CFG_EBR_NEGEDGE_REGISTER_FILE |
| clk_n_i, |
| `endif |
| rst_i, |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_ALTERNATE_EBA |
| at_debug, |
| `endif |
| `endif |
| // From external devices |
| `ifdef CFG_INTERRUPTS_ENABLED |
| interrupt, |
| `endif |
| // From user logic |
| `ifdef CFG_USER_ENABLED |
| user_result, |
| user_complete, |
| `endif |
| `ifdef CFG_JTAG_ENABLED |
| // From JTAG |
| jtag_clk, |
| jtag_update, |
| jtag_reg_q, |
| jtag_reg_addr_q, |
| `endif |
| `ifdef CFG_EXTERNAL_BREAK_ENABLED |
| ext_break, |
| `endif |
| `ifdef CFG_IWB_ENABLED |
| // Instruction Wishbone master |
| I_DAT_I, |
| I_ACK_I, |
| I_ERR_I, |
| I_RTY_I, |
| `endif |
| // Data Wishbone master |
| D_DAT_I, |
| D_ACK_I, |
| D_ERR_I, |
| D_RTY_I, |
| // ----- Outputs ------- |
| `ifdef CFG_TRACE_ENABLED |
| trace_pc, |
| trace_pc_valid, |
| trace_exception, |
| trace_eid, |
| trace_eret, |
| `ifdef CFG_DEBUG_ENABLED |
| trace_bret, |
| `endif |
| `endif |
| `ifdef CFG_JTAG_ENABLED |
| jtag_reg_d, |
| jtag_reg_addr_d, |
| `endif |
| `ifdef CFG_USER_ENABLED |
| user_valid, |
| user_opcode, |
| user_operand_0, |
| user_operand_1, |
| `endif |
| `ifdef CFG_IWB_ENABLED |
| // Instruction Wishbone master |
| I_DAT_O, |
| I_ADR_O, |
| I_CYC_O, |
| I_SEL_O, |
| I_STB_O, |
| I_WE_O, |
| I_CTI_O, |
| I_LOCK_O, |
| I_BTE_O, |
| `endif |
| // Data Wishbone master |
| D_DAT_O, |
| D_ADR_O, |
| D_CYC_O, |
| D_SEL_O, |
| D_STB_O, |
| D_WE_O, |
| D_CTI_O, |
| D_LOCK_O, |
| D_BTE_O |
| ); |
| |
| ///////////////////////////////////////////////////// |
| // Parameters |
| ///////////////////////////////////////////////////// |
| |
| parameter eba_reset = `CFG_EBA_RESET; // Reset value for EBA CSR |
| `ifdef CFG_DEBUG_ENABLED |
| parameter deba_reset = `CFG_DEBA_RESET; // Reset value for DEBA CSR |
| `endif |
| |
| `ifdef CFG_ICACHE_ENABLED |
| parameter icache_associativity = `CFG_ICACHE_ASSOCIATIVITY; // Associativity of the cache (Number of ways) |
| parameter icache_sets = `CFG_ICACHE_SETS; // Number of sets |
| parameter icache_bytes_per_line = `CFG_ICACHE_BYTES_PER_LINE; // Number of bytes per cache line |
| parameter icache_base_address = `CFG_ICACHE_BASE_ADDRESS; // Base address of cachable memory |
| parameter icache_limit = `CFG_ICACHE_LIMIT; // Limit (highest address) of cachable memory |
| `else |
| parameter icache_associativity = 1; |
| parameter icache_sets = 512; |
| parameter icache_bytes_per_line = 16; |
| parameter icache_base_address = 0; |
| parameter icache_limit = 0; |
| `endif |
| |
| `ifdef CFG_DCACHE_ENABLED |
| parameter dcache_associativity = `CFG_DCACHE_ASSOCIATIVITY; // Associativity of the cache (Number of ways) |
| parameter dcache_sets = `CFG_DCACHE_SETS; // Number of sets |
| parameter dcache_bytes_per_line = `CFG_DCACHE_BYTES_PER_LINE; // Number of bytes per cache line |
| parameter dcache_base_address = `CFG_DCACHE_BASE_ADDRESS; // Base address of cachable memory |
| parameter dcache_limit = `CFG_DCACHE_LIMIT; // Limit (highest address) of cachable memory |
| `else |
| parameter dcache_associativity = 1; |
| parameter dcache_sets = 512; |
| parameter dcache_bytes_per_line = 16; |
| parameter dcache_base_address = 0; |
| parameter dcache_limit = 0; |
| `endif |
| |
| `ifdef CFG_DEBUG_ENABLED |
| parameter watchpoints = `CFG_WATCHPOINTS; // Number of h/w watchpoint CSRs |
| `else |
| parameter watchpoints = 0; |
| `endif |
| `ifdef CFG_ROM_DEBUG_ENABLED |
| parameter breakpoints = `CFG_BREAKPOINTS; // Number of h/w breakpoint CSRs |
| `else |
| parameter breakpoints = 0; |
| `endif |
| |
| `ifdef CFG_INTERRUPTS_ENABLED |
| parameter interrupts = `CFG_INTERRUPTS; // Number of interrupts |
| `else |
| parameter interrupts = 0; |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Inputs |
| ///////////////////////////////////////////////////// |
| |
| input clk_i; // Clock |
| `ifdef CFG_EBR_NEGEDGE_REGISTER_FILE |
| input clk_n_i; // Inverted clock |
| `endif |
| input rst_i; // Reset |
| |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_ALTERNATE_EBA |
| input at_debug; // GPIO input that maps EBA to DEBA |
| `endif |
| `endif |
| |
| `ifdef CFG_INTERRUPTS_ENABLED |
| input [`LM32_INTERRUPT_RNG] interrupt; // Interrupt pins |
| `endif |
| |
| `ifdef CFG_USER_ENABLED |
| input [`LM32_WORD_RNG] user_result; // User-defined instruction result |
| input user_complete; // User-defined instruction execution is complete |
| `endif |
| |
| `ifdef CFG_JTAG_ENABLED |
| input jtag_clk; // JTAG clock |
| input jtag_update; // JTAG state machine is in data register update state |
| input [`LM32_BYTE_RNG] jtag_reg_q; |
| input [2:0] jtag_reg_addr_q; |
| `endif |
| |
| `ifdef CFG_IWB_ENABLED |
| input [`LM32_WORD_RNG] I_DAT_I; // Instruction Wishbone interface read data |
| input I_ACK_I; // Instruction Wishbone interface acknowledgement |
| input I_ERR_I; // Instruction Wishbone interface error |
| input I_RTY_I; // Instruction Wishbone interface retry |
| `endif |
| |
| input [`LM32_WORD_RNG] D_DAT_I; // Data Wishbone interface read data |
| input D_ACK_I; // Data Wishbone interface acknowledgement |
| input D_ERR_I; // Data Wishbone interface error |
| input D_RTY_I; // Data Wishbone interface retry |
| |
| `ifdef CFG_EXTERNAL_BREAK_ENABLED |
| input ext_break; |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Outputs |
| ///////////////////////////////////////////////////// |
| |
| `ifdef CFG_TRACE_ENABLED |
| output [`LM32_PC_RNG] trace_pc; // PC to trace |
| reg [`LM32_PC_RNG] trace_pc; |
| output trace_pc_valid; // Indicates that a new trace PC is valid |
| reg trace_pc_valid; |
| output trace_exception; // Indicates an exception has occured |
| reg trace_exception; |
| output [`LM32_EID_RNG] trace_eid; // Indicates what type of exception has occured |
| reg [`LM32_EID_RNG] trace_eid; |
| output trace_eret; // Indicates an eret instruction has been executed |
| reg trace_eret; |
| `ifdef CFG_DEBUG_ENABLED |
| output trace_bret; // Indicates a bret instruction has been executed |
| reg trace_bret; |
| `endif |
| `endif |
| |
| `ifdef CFG_JTAG_ENABLED |
| output [`LM32_BYTE_RNG] jtag_reg_d; |
| wire [`LM32_BYTE_RNG] jtag_reg_d; |
| output [2:0] jtag_reg_addr_d; |
| wire [2:0] jtag_reg_addr_d; |
| `endif |
| |
| `ifdef CFG_USER_ENABLED |
| output user_valid; // Indicates if user_opcode is valid |
| wire user_valid; |
| output [`LM32_USER_OPCODE_RNG] user_opcode; // User-defined instruction opcode |
| reg [`LM32_USER_OPCODE_RNG] user_opcode; |
| output [`LM32_WORD_RNG] user_operand_0; // First operand for user-defined instruction |
| wire [`LM32_WORD_RNG] user_operand_0; |
| output [`LM32_WORD_RNG] user_operand_1; // Second operand for user-defined instruction |
| wire [`LM32_WORD_RNG] user_operand_1; |
| `endif |
| |
| `ifdef CFG_IWB_ENABLED |
| output [`LM32_WORD_RNG] I_DAT_O; // Instruction Wishbone interface write data |
| wire [`LM32_WORD_RNG] I_DAT_O; |
| output [`LM32_WORD_RNG] I_ADR_O; // Instruction Wishbone interface address |
| wire [`LM32_WORD_RNG] I_ADR_O; |
| output I_CYC_O; // Instruction Wishbone interface cycle |
| wire I_CYC_O; |
| output [`LM32_BYTE_SELECT_RNG] I_SEL_O; // Instruction Wishbone interface byte select |
| wire [`LM32_BYTE_SELECT_RNG] I_SEL_O; |
| output I_STB_O; // Instruction Wishbone interface strobe |
| wire I_STB_O; |
| output I_WE_O; // Instruction Wishbone interface write enable |
| wire I_WE_O; |
| output [`LM32_CTYPE_RNG] I_CTI_O; // Instruction Wishbone interface cycle type |
| wire [`LM32_CTYPE_RNG] I_CTI_O; |
| output I_LOCK_O; // Instruction Wishbone interface lock bus |
| wire I_LOCK_O; |
| output [`LM32_BTYPE_RNG] I_BTE_O; // Instruction Wishbone interface burst type |
| wire [`LM32_BTYPE_RNG] I_BTE_O; |
| `endif |
| |
| output [`LM32_WORD_RNG] D_DAT_O; // Data Wishbone interface write data |
| wire [`LM32_WORD_RNG] D_DAT_O; |
| output [`LM32_WORD_RNG] D_ADR_O; // Data Wishbone interface address |
| wire [`LM32_WORD_RNG] D_ADR_O; |
| output D_CYC_O; // Data Wishbone interface cycle |
| wire D_CYC_O; |
| output [`LM32_BYTE_SELECT_RNG] D_SEL_O; // Data Wishbone interface byte select |
| wire [`LM32_BYTE_SELECT_RNG] D_SEL_O; |
| output D_STB_O; // Data Wishbone interface strobe |
| wire D_STB_O; |
| output D_WE_O; // Data Wishbone interface write enable |
| wire D_WE_O; |
| output [`LM32_CTYPE_RNG] D_CTI_O; // Data Wishbone interface cycle type |
| wire [`LM32_CTYPE_RNG] D_CTI_O; |
| output D_LOCK_O; // Date Wishbone interface lock bus |
| wire D_LOCK_O; |
| output [`LM32_BTYPE_RNG] D_BTE_O; // Data Wishbone interface burst type |
| wire [`LM32_BTYPE_RNG] D_BTE_O; |
| |
| ///////////////////////////////////////////////////// |
| // Internal nets and registers |
| ///////////////////////////////////////////////////// |
| |
| // Pipeline registers |
| |
| `ifdef LM32_CACHE_ENABLED |
| reg valid_a; // Instruction in A stage is valid |
| `endif |
| reg valid_f; // Instruction in F stage is valid |
| reg valid_d; // Instruction in D stage is valid |
| reg valid_x; // Instruction in X stage is valid |
| reg valid_m; // Instruction in M stage is valid |
| reg valid_w; // Instruction in W stage is valid |
| |
| wire q_x; |
| wire [`LM32_WORD_RNG] immediate_d; // Immediate operand |
| wire load_d; // Indicates a load instruction |
| reg load_x; |
| reg load_m; |
| wire load_q_x; |
| wire store_q_x; |
| wire store_d; // Indicates a store instruction |
| reg store_x; |
| reg store_m; |
| wire [`LM32_SIZE_RNG] size_d; // Size of load/store (byte, hword, word) |
| reg [`LM32_SIZE_RNG] size_x; |
| wire branch_d; // Indicates a branch instruction |
| wire branch_predict_d; // Indicates a branch is predicted |
| wire branch_predict_taken_d; // Indicates a branch is predicted taken |
| wire [`LM32_PC_RNG] branch_predict_address_d; // Address to which predicted branch jumps |
| wire [`LM32_PC_RNG] branch_target_d; |
| wire bi_unconditional; |
| wire bi_conditional; |
| reg branch_x; |
| reg branch_predict_x; |
| reg branch_predict_taken_x; |
| reg branch_m; |
| reg branch_predict_m; |
| reg branch_predict_taken_m; |
| wire branch_mispredict_taken_m; // Indicates a branch was mispredicted as taken |
| wire branch_flushX_m; // Indicates that instruction in X stage must be squashed |
| wire branch_reg_d; // Branch to register or immediate |
| wire [`LM32_PC_RNG] branch_offset_d; // Branch offset for immediate branches |
| reg [`LM32_PC_RNG] branch_target_x; // Address to branch to |
| reg [`LM32_PC_RNG] branch_target_m; |
| wire [`LM32_D_RESULT_SEL_0_RNG] d_result_sel_0_d; // Which result should be selected in D stage for operand 0 |
| wire [`LM32_D_RESULT_SEL_1_RNG] d_result_sel_1_d; // Which result should be selected in D stage for operand 1 |
| |
| wire x_result_sel_csr_d; // Select X stage result from CSRs |
| reg x_result_sel_csr_x; |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| wire x_result_sel_mc_arith_d; // Select X stage result from multi-cycle arithmetic unit |
| reg x_result_sel_mc_arith_x; |
| `endif |
| `ifdef LM32_NO_BARREL_SHIFT |
| wire x_result_sel_shift_d; // Select X stage result from shifter |
| reg x_result_sel_shift_x; |
| `endif |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| wire x_result_sel_sext_d; // Select X stage result from sign-extend logic |
| reg x_result_sel_sext_x; |
| `endif |
| wire x_result_sel_logic_d; // Select X stage result from logic op unit |
| reg x_result_sel_logic_x; |
| `ifdef CFG_USER_ENABLED |
| wire x_result_sel_user_d; // Select X stage result from user-defined logic |
| reg x_result_sel_user_x; |
| `endif |
| wire x_result_sel_add_d; // Select X stage result from adder |
| reg x_result_sel_add_x; |
| wire m_result_sel_compare_d; // Select M stage result from comparison logic |
| reg m_result_sel_compare_x; |
| reg m_result_sel_compare_m; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| wire m_result_sel_shift_d; // Select M stage result from shifter |
| reg m_result_sel_shift_x; |
| reg m_result_sel_shift_m; |
| `endif |
| wire w_result_sel_load_d; // Select W stage result from load/store unit |
| reg w_result_sel_load_x; |
| reg w_result_sel_load_m; |
| reg w_result_sel_load_w; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| wire w_result_sel_mul_d; // Select W stage result from multiplier |
| reg w_result_sel_mul_x; |
| reg w_result_sel_mul_m; |
| reg w_result_sel_mul_w; |
| `endif |
| wire x_bypass_enable_d; // Whether result is bypassable in X stage |
| reg x_bypass_enable_x; |
| wire m_bypass_enable_d; // Whether result is bypassable in M stage |
| reg m_bypass_enable_x; |
| reg m_bypass_enable_m; |
| wire sign_extend_d; // Whether to sign-extend or zero-extend |
| reg sign_extend_x; |
| wire write_enable_d; // Register file write enable |
| reg write_enable_x; |
| wire write_enable_q_x; |
| reg write_enable_m; |
| wire write_enable_q_m; |
| reg write_enable_w; |
| wire write_enable_q_w; |
| wire read_enable_0_d; // Register file read enable 0 |
| wire [`LM32_REG_IDX_RNG] read_idx_0_d; // Register file read index 0 |
| wire read_enable_1_d; // Register file read enable 1 |
| wire [`LM32_REG_IDX_RNG] read_idx_1_d; // Register file read index 1 |
| wire [`LM32_REG_IDX_RNG] write_idx_d; // Register file write index |
| reg [`LM32_REG_IDX_RNG] write_idx_x; |
| reg [`LM32_REG_IDX_RNG] write_idx_m; |
| reg [`LM32_REG_IDX_RNG] write_idx_w; |
| wire [`LM32_CSR_RNG] csr_d; // CSR read/write index |
| reg [`LM32_CSR_RNG] csr_x; |
| wire [`LM32_CONDITION_RNG] condition_d; // Branch condition |
| reg [`LM32_CONDITION_RNG] condition_x; |
| `ifdef CFG_DEBUG_ENABLED |
| wire break_d; // Indicates a break instruction |
| reg break_x; |
| `endif |
| wire scall_d; // Indicates a scall instruction |
| reg scall_x; |
| wire eret_d; // Indicates an eret instruction |
| reg eret_x; |
| wire eret_q_x; |
| `ifdef CFG_MMU_ENABLED |
| wire eret_k_q_x; |
| `endif |
| reg eret_m; |
| `ifdef CFG_TRACE_ENABLED |
| reg eret_w; |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| wire bret_d; // Indicates a bret instruction |
| reg bret_x; |
| wire bret_q_x; |
| `ifdef CFG_MMU_ENABLED |
| wire bret_k_q_x; |
| `endif |
| reg bret_m; |
| `ifdef CFG_TRACE_ENABLED |
| reg bret_w; |
| `endif |
| `endif |
| wire csr_write_enable_d; // CSR write enable |
| reg csr_write_enable_x; |
| wire csr_write_enable_q_x; |
| `ifdef CFG_MMU_ENABLED |
| wire csr_write_enable_k_q_x; |
| `endif |
| `ifdef CFG_USER_ENABLED |
| wire [`LM32_USER_OPCODE_RNG] user_opcode_d; // User-defined instruction opcode |
| `endif |
| |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| wire bus_error_d; // Indicates an bus error occured while fetching the instruction in this pipeline stage |
| reg bus_error_x; |
| reg data_bus_error_exception_m; |
| reg [`LM32_PC_RNG] memop_pc_w; |
| `endif |
| |
| reg [`LM32_WORD_RNG] d_result_0; // Result of instruction in D stage (operand 0) |
| reg [`LM32_WORD_RNG] d_result_1; // Result of instruction in D stage (operand 1) |
| reg [`LM32_WORD_RNG] x_result; // Result of instruction in X stage |
| reg [`LM32_WORD_RNG] m_result; // Result of instruction in M stage |
| reg [`LM32_WORD_RNG] w_result; // Result of instruction in W stage |
| |
| reg [`LM32_WORD_RNG] operand_0_x; // Operand 0 for X stage instruction |
| reg [`LM32_WORD_RNG] operand_1_x; // Operand 1 for X stage instruction |
| reg [`LM32_WORD_RNG] store_operand_x; // Data read from register to store |
| reg [`LM32_WORD_RNG] operand_m; // Operand for M stage instruction |
| reg [`LM32_WORD_RNG] operand_w; // Operand for W stage instruction |
| |
| // To/from register file |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| reg [`LM32_WORD_RNG] reg_data_live_0; |
| reg [`LM32_WORD_RNG] reg_data_live_1; |
| reg use_buf; // Whether to use reg_data_live or reg_data_buf |
| reg [`LM32_WORD_RNG] reg_data_buf_0; |
| reg [`LM32_WORD_RNG] reg_data_buf_1; |
| `endif |
| `ifdef LM32_EBR_REGISTER_FILE |
| `else |
| reg [`LM32_WORD_RNG] registers[0:(1<<`LM32_REG_IDX_WIDTH)-1]; // Register file |
| `endif |
| wire [`LM32_WORD_RNG] reg_data_0; // Register file read port 0 data |
| wire [`LM32_WORD_RNG] reg_data_1; // Register file read port 1 data |
| reg [`LM32_WORD_RNG] bypass_data_0; // Register value 0 after bypassing |
| reg [`LM32_WORD_RNG] bypass_data_1; // Register value 1 after bypassing |
| wire reg_write_enable_q_w; |
| |
| reg interlock; // Indicates pipeline should be stalled because of a read-after-write hazzard |
| |
| wire stall_a; // Stall instruction in A pipeline stage |
| wire stall_f; // Stall instruction in F pipeline stage |
| wire stall_d; // Stall instruction in D pipeline stage |
| wire stall_x; // Stall instruction in X pipeline stage |
| wire stall_m; // Stall instruction in M pipeline stage |
| |
| // To/from adder |
| wire adder_op_d; // Whether to add or subtract |
| reg adder_op_x; |
| reg adder_op_x_n; // Inverted version of adder_op_x |
| wire [`LM32_WORD_RNG] adder_result_x; // Result from adder |
| wire adder_overflow_x; // Whether a signed overflow occured |
| wire adder_carry_n_x; // Whether a carry was generated |
| |
| // To/from logical operations unit |
| wire [`LM32_LOGIC_OP_RNG] logic_op_d; // Which operation to perform |
| reg [`LM32_LOGIC_OP_RNG] logic_op_x; |
| wire [`LM32_WORD_RNG] logic_result_x; // Result of logical operation |
| |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| // From sign-extension unit |
| wire [`LM32_WORD_RNG] sextb_result_x; // Result of byte sign-extension |
| wire [`LM32_WORD_RNG] sexth_result_x; // Result of half-word sign-extenstion |
| wire [`LM32_WORD_RNG] sext_result_x; // Result of sign-extension specified by instruction |
| `endif |
| |
| // To/from shifter |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| wire direction_d; // Which direction to shift in |
| reg direction_x; |
| wire [`LM32_WORD_RNG] shifter_result_m; // Result of shifter |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| wire shift_left_d; // Indicates whether to perform a left shift or not |
| wire shift_left_q_d; |
| wire shift_right_d; // Indicates whether to perform a right shift or not |
| wire shift_right_q_d; |
| `endif |
| `ifdef LM32_NO_BARREL_SHIFT |
| wire [`LM32_WORD_RNG] shifter_result_x; // Result of single-bit right shifter |
| `endif |
| |
| // To/from multiplier |
| `ifdef LM32_MULTIPLY_ENABLED |
| wire [`LM32_WORD_RNG] multiplier_result_w; // Result from multiplier |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| wire multiply_d; // Indicates whether to perform a multiply or not |
| wire multiply_q_d; |
| `endif |
| |
| // To/from divider |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| wire divide_d; // Indicates whether to perform a divider or not |
| wire divide_q_d; |
| wire modulus_d; |
| wire modulus_q_d; |
| wire divide_by_zero_x; // Indicates an attempt was made to divide by zero |
| `endif |
| |
| // To from multi-cycle arithmetic unit |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| wire mc_stall_request_x; // Multi-cycle arithmetic unit stall request |
| wire [`LM32_WORD_RNG] mc_result_x; |
| `endif |
| |
| // From CSRs |
| `ifdef CFG_INTERRUPTS_ENABLED |
| wire [`LM32_WORD_RNG] interrupt_csr_read_data_x;// Data read from interrupt CSRs |
| `endif |
| wire [`LM32_WORD_RNG] cfg; // Configuration CSR |
| wire [`LM32_WORD_RNG] cfg2; // Extended Configuration CSR |
| `ifdef CFG_MMU_ENABLED |
| wire [`LM32_WORD_RNG] psw; // Processor Status Word CSR |
| `endif |
| `ifdef CFG_CYCLE_COUNTER_ENABLED |
| reg [`LM32_WORD_RNG] cc; // Cycle counter CSR |
| `endif |
| reg [`LM32_WORD_RNG] csr_read_data_x; // Data read from CSRs |
| |
| // To/from instruction unit |
| wire [`LM32_PC_RNG] pc_f; // PC of instruction in F stage |
| wire [`LM32_PC_RNG] pc_d; // PC of instruction in D stage |
| wire [`LM32_PC_RNG] pc_x; // PC of instruction in X stage |
| wire [`LM32_PC_RNG] pc_m; // PC of instruction in M stage |
| wire [`LM32_PC_RNG] pc_w; // PC of instruction in W stage |
| `ifdef CFG_TRACE_ENABLED |
| reg [`LM32_PC_RNG] pc_c; // PC of last commited instruction |
| `endif |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| wire [`LM32_INSTRUCTION_RNG] instruction_f; // Instruction in F stage |
| `endif |
| //pragma attribute instruction_d preserve_signal true |
| //pragma attribute instruction_d preserve_driver true |
| wire [`LM32_INSTRUCTION_RNG] instruction_d; // Instruction in D stage |
| `ifdef CFG_ICACHE_ENABLED |
| wire iflush; // Flush instruction cache |
| wire icache_stall_request; // Stall pipeline because instruction cache is busy |
| wire icache_restart_request; // Restart instruction that caused an instruction cache miss |
| wire icache_refill_request; // Request to refill instruction cache |
| wire icache_refilling; // Indicates the instruction cache is being refilled |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| wire [`LM32_WORD_RNG] irom_store_data_m; // Store data to instruction ROM |
| wire [`LM32_WORD_RNG] irom_address_xm; // Address to instruction ROM from load-store unit |
| wire [`LM32_WORD_RNG] irom_data_m; // Load data from instruction ROM |
| wire irom_we_xm; // Indicates data needs to be written to instruction ROM |
| wire irom_stall_request_x; // Indicates D stage needs to be stalled on a store to instruction ROM |
| `endif |
| |
| // To/from load/store unit |
| `ifdef CFG_DCACHE_ENABLED |
| wire dflush_x; // Flush data cache |
| reg dflush_m; |
| wire dcache_stall_request; // Stall pipeline because data cache is busy |
| wire dcache_restart_request; // Restart instruction that caused a data cache miss |
| wire dcache_refill_request; // Request to refill data cache |
| wire dcache_refilling; // Indicates the data cache is being refilled |
| `endif |
| wire [`LM32_WORD_RNG] load_data_w; // Result of a load instruction |
| wire stall_wb_load; // Stall pipeline because of a load via the data Wishbone interface |
| |
| // To/from JTAG interface |
| `ifdef CFG_JTAG_ENABLED |
| `ifdef CFG_JTAG_UART_ENABLED |
| wire [`LM32_WORD_RNG] jtx_csr_read_data; // Read data for JTX CSR |
| wire [`LM32_WORD_RNG] jrx_csr_read_data; // Read data for JRX CSR |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| wire jtag_csr_write_enable; // Debugger CSR write enable |
| wire [`LM32_WORD_RNG] jtag_csr_write_data; // Data to write to specified CSR |
| wire [`LM32_CSR_RNG] jtag_csr; // Which CSR to write |
| wire jtag_read_enable; |
| wire [`LM32_BYTE_RNG] jtag_read_data; |
| wire jtag_write_enable; |
| wire [`LM32_BYTE_RNG] jtag_write_data; |
| wire [`LM32_WORD_RNG] jtag_address; |
| wire jtag_access_complete; |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| wire jtag_break; // Request from debugger to raise a breakpoint |
| `endif |
| `endif |
| |
| // Hazzard detection |
| wire raw_x_0; // RAW hazzard between instruction in X stage and read port 0 |
| wire raw_x_1; // RAW hazzard between instruction in X stage and read port 1 |
| wire raw_m_0; // RAW hazzard between instruction in M stage and read port 0 |
| wire raw_m_1; // RAW hazzard between instruction in M stage and read port 1 |
| wire raw_w_0; // RAW hazzard between instruction in W stage and read port 0 |
| wire raw_w_1; // RAW hazzard between instruction in W stage and read port 1 |
| |
| // Control flow |
| wire cmp_zero; // Result of comparison is zero |
| wire cmp_negative; // Result of comparison is negative |
| wire cmp_overflow; // Comparison produced an overflow |
| wire cmp_carry_n; // Comparison produced a carry, inverted |
| reg condition_met_x; // Condition of branch instruction is met |
| reg condition_met_m; |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| wire branch_taken_x; // Branch is taken in X stage |
| `endif |
| wire branch_taken_m; // Branch is taken in M stage |
| |
| wire kill_f; // Kill instruction in F stage |
| wire kill_d; // Kill instruction in D stage |
| wire kill_x; // Kill instruction in X stage |
| wire kill_m; // Kill instruction in M stage |
| wire kill_w; // Kill instruction in W stage |
| |
| reg [`LM32_EBA_RNG] eba; // Exception Base Address (EBA) CSR |
| `ifdef CFG_DEBUG_ENABLED |
| reg [`LM32_EBA_RNG] deba; // Debug Exception Base Address (DEBA) CSR |
| `endif |
| reg [`LM32_EID_RNG] eid_x; // Exception ID in X stage |
| `ifdef CFG_TRACE_ENABLED |
| reg [`LM32_EID_RNG] eid_m; // Exception ID in M stage |
| reg [`LM32_EID_RNG] eid_w; // Exception ID in W stage |
| `endif |
| |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| wire dc_ss; // Is single-step enabled |
| `endif |
| wire dc_re; // Remap all exceptions |
| wire exception_x; // An exception occured in the X stage |
| reg exception_m; // An instruction that caused an exception is in the M stage |
| wire debug_exception_x; // Indicates if a debug exception has occured |
| reg debug_exception_m; |
| reg debug_exception_w; |
| wire debug_exception_q_w; |
| wire non_debug_exception_x; // Indicates if a non debug exception has occured |
| reg non_debug_exception_m; |
| reg non_debug_exception_w; |
| wire non_debug_exception_q_w; |
| `else |
| wire exception_x; // Indicates if a debug exception has occured |
| reg exception_m; |
| reg exception_w; |
| wire exception_q_w; |
| `endif |
| |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_JTAG_ENABLED |
| wire reset_exception; // Indicates if a reset exception has occured |
| `endif |
| `endif |
| `ifdef CFG_INTERRUPTS_ENABLED |
| wire interrupt_exception; // Indicates if an interrupt exception has occured |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| wire breakpoint_exception; // Indicates if a breakpoint exception has occured |
| wire watchpoint_exception; // Indicates if a watchpoint exception has occured |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| wire instruction_bus_error_exception; // Indicates if an instruction bus error exception has occured |
| wire data_bus_error_exception; // Indicates if a data bus error exception has occured |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| wire divide_by_zero_exception; // Indicates if a divide by zero exception has occured |
| `endif |
| wire system_call_exception; // Indicates if a system call exception has occured |
| |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| reg data_bus_error_seen; // Indicates if a data bus error was seen |
| `endif |
| |
| `ifdef CFG_EXTERNAL_BREAK_ENABLED |
| reg ext_break_r; |
| `endif |
| |
| `ifdef CFG_MMU_ENABLED |
| reg itlbe; // Instruction TLB enable |
| reg dtlbe; // Data TLB enable |
| reg usr; // User mode |
| reg eitlbe; // Exception instruction enable |
| reg edtlbe; // Exception data TLB enable |
| reg eusr; // Exception user mode |
| `ifdef CFG_DEBUG_ENABLED |
| reg bitlbe; // Breakpoint instruction TLB enable |
| reg bdtlbe; // Breakpoint data TLB enable |
| reg busr; // Breakpoint user mode |
| `endif |
| |
| reg itlb_invalidate; // Invalidate an ITLB entry |
| reg itlb_flush; // Flush all ITLB entries |
| reg itlb_update; // Update an ITLB entry |
| reg dtlb_invalidate; // Invalidate a DTLB entry |
| reg dtlb_flush; // Flush all DTLB entries |
| reg dtlb_update; // Update an DTLB entry |
| reg [`LM32_WORD_RNG] tlbpaddr; // TLBPADDR CSR |
| reg [`LM32_WORD_RNG] tlbvaddr; // TLBVADDR CSR |
| reg [`LM32_WORD_RNG] tlbbadvaddr; // TLBBADVADDR CSR |
| wire [`LM32_WORD_RNG] dtlb_miss_vfn; // VFN of the missed address |
| wire [`LM32_WORD_RNG] itlb_miss_vfn; // VFN of the missed instruction |
| wire itlb_miss_x; // Indicates if an ITLB miss has occured in the X stage |
| wire itlb_stall_request; // Stall pipeline because instruction TLB is busy |
| wire dtlb_miss_x; // Indicates if an DTLB miss has occured in the X stage |
| wire dtlb_fault_x; // Indicates if an DTLB fault has occured in the X stage |
| wire dtlb_stall_request; // Stall pipeline because data TLB is busy |
| |
| wire itlb_miss_exception; // Indicates if an ITLB miss exception has occured |
| wire itlb_exception; // Indicates if an ITLB exception has occured |
| wire dtlb_miss_exception; // Indicates if a DTLB miss exception has occured |
| wire dtlb_fault_exception; // Indicates if a DTLB fault exception has occured |
| wire dtlb_exception; // Indicates if a DTLB exception has occured |
| wire privilege_exception; // Indicates if a privilege exception has occured |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Functions |
| ///////////////////////////////////////////////////// |
| |
| ///////////////////////////////////////////////////// |
| // Instantiations |
| ///////////////////////////////////////////////////// |
| |
| // Instruction unit |
| lm32_instruction_unit #( |
| .eba_reset (eba_reset), |
| .associativity (icache_associativity), |
| .sets (icache_sets), |
| .bytes_per_line (icache_bytes_per_line), |
| .base_address (icache_base_address), |
| .limit (icache_limit) |
| ) instruction_unit ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_ALTERNATE_EBA |
| .at_debug (at_debug), |
| `endif |
| `endif |
| // From pipeline |
| .stall_a (stall_a), |
| .stall_f (stall_f), |
| .stall_d (stall_d), |
| .stall_x (stall_x), |
| .stall_m (stall_m), |
| .valid_f (valid_f), |
| .valid_d (valid_d), |
| .kill_f (kill_f), |
| .branch_predict_taken_d (branch_predict_taken_d), |
| .branch_predict_address_d (branch_predict_address_d), |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| .branch_taken_x (branch_taken_x), |
| .branch_target_x (branch_target_x), |
| `endif |
| .exception_m (exception_m), |
| .branch_taken_m (branch_taken_m), |
| .branch_mispredict_taken_m (branch_mispredict_taken_m), |
| .branch_target_m (branch_target_m), |
| `ifdef CFG_ICACHE_ENABLED |
| .iflush (iflush), |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| .irom_store_data_m (irom_store_data_m), |
| .irom_address_xm (irom_address_xm), |
| .irom_we_xm (irom_we_xm), |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| .dcache_restart_request (dcache_restart_request), |
| .dcache_refill_request (dcache_refill_request), |
| .dcache_refilling (dcache_refilling), |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| .itlb_enable (itlbe), |
| .tlbpaddr (tlbpaddr), |
| .tlbvaddr (tlbvaddr), |
| .itlb_update (itlb_update), |
| .itlb_flush (itlb_flush), |
| .itlb_invalidate (itlb_invalidate), |
| `endif |
| `ifdef CFG_IWB_ENABLED |
| // From Wishbone |
| .i_dat_i (I_DAT_I), |
| .i_ack_i (I_ACK_I), |
| .i_err_i (I_ERR_I), |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| .jtag_read_enable (jtag_read_enable), |
| .jtag_write_enable (jtag_write_enable), |
| .jtag_write_data (jtag_write_data), |
| .jtag_address (jtag_address), |
| `endif |
| // ----- Outputs ------- |
| // To pipeline |
| .pc_f (pc_f), |
| .pc_d (pc_d), |
| .pc_x (pc_x), |
| .pc_m (pc_m), |
| .pc_w (pc_w), |
| `ifdef CFG_ICACHE_ENABLED |
| .icache_stall_request (icache_stall_request), |
| .icache_restart_request (icache_restart_request), |
| .icache_refill_request (icache_refill_request), |
| .icache_refilling (icache_refilling), |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| .irom_data_m (irom_data_m), |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| .itlb_stall_request (itlb_stall_request), |
| .itlb_miss_vfn (itlb_miss_vfn), |
| .itlb_miss_x (itlb_miss_x), |
| `endif |
| `ifdef CFG_IWB_ENABLED |
| // To Wishbone |
| .i_dat_o (I_DAT_O), |
| .i_adr_o (I_ADR_O), |
| .i_cyc_o (I_CYC_O), |
| .i_sel_o (I_SEL_O), |
| .i_stb_o (I_STB_O), |
| .i_we_o (I_WE_O), |
| .i_cti_o (I_CTI_O), |
| .i_lock_o (I_LOCK_O), |
| .i_bte_o (I_BTE_O), |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| .jtag_read_data (jtag_read_data), |
| .jtag_access_complete (jtag_access_complete), |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| .bus_error_d (bus_error_d), |
| `endif |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| .instruction_f (instruction_f), |
| `endif |
| .instruction_d (instruction_d) |
| ); |
| |
| // Instruction decoder |
| lm32_decoder decoder ( |
| // ----- Inputs ------- |
| .instruction (instruction_d), |
| // ----- Outputs ------- |
| .d_result_sel_0 (d_result_sel_0_d), |
| .d_result_sel_1 (d_result_sel_1_d), |
| .x_result_sel_csr (x_result_sel_csr_d), |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| .x_result_sel_mc_arith (x_result_sel_mc_arith_d), |
| `endif |
| `ifdef LM32_NO_BARREL_SHIFT |
| .x_result_sel_shift (x_result_sel_shift_d), |
| `endif |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| .x_result_sel_sext (x_result_sel_sext_d), |
| `endif |
| .x_result_sel_logic (x_result_sel_logic_d), |
| `ifdef CFG_USER_ENABLED |
| .x_result_sel_user (x_result_sel_user_d), |
| `endif |
| .x_result_sel_add (x_result_sel_add_d), |
| .m_result_sel_compare (m_result_sel_compare_d), |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| .m_result_sel_shift (m_result_sel_shift_d), |
| `endif |
| .w_result_sel_load (w_result_sel_load_d), |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| .w_result_sel_mul (w_result_sel_mul_d), |
| `endif |
| .x_bypass_enable (x_bypass_enable_d), |
| .m_bypass_enable (m_bypass_enable_d), |
| .read_enable_0 (read_enable_0_d), |
| .read_idx_0 (read_idx_0_d), |
| .read_enable_1 (read_enable_1_d), |
| .read_idx_1 (read_idx_1_d), |
| .write_enable (write_enable_d), |
| .write_idx (write_idx_d), |
| .immediate (immediate_d), |
| .branch_offset (branch_offset_d), |
| .load (load_d), |
| .store (store_d), |
| .size (size_d), |
| .sign_extend (sign_extend_d), |
| .adder_op (adder_op_d), |
| .logic_op (logic_op_d), |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| .direction (direction_d), |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| .shift_left (shift_left_d), |
| .shift_right (shift_right_d), |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| .multiply (multiply_d), |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| .divide (divide_d), |
| .modulus (modulus_d), |
| `endif |
| .branch (branch_d), |
| .bi_unconditional (bi_unconditional), |
| .bi_conditional (bi_conditional), |
| .branch_reg (branch_reg_d), |
| .condition (condition_d), |
| `ifdef CFG_DEBUG_ENABLED |
| .break_opcode (break_d), |
| `endif |
| .scall (scall_d), |
| .eret (eret_d), |
| `ifdef CFG_DEBUG_ENABLED |
| .bret (bret_d), |
| `endif |
| `ifdef CFG_USER_ENABLED |
| .user_opcode (user_opcode_d), |
| `endif |
| .csr_write_enable (csr_write_enable_d) |
| ); |
| |
| // Load/store unit |
| lm32_load_store_unit #( |
| .associativity (dcache_associativity), |
| .sets (dcache_sets), |
| .bytes_per_line (dcache_bytes_per_line), |
| .base_address (dcache_base_address), |
| .limit (dcache_limit) |
| ) load_store_unit ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| // From pipeline |
| .stall_a (stall_a), |
| .stall_x (stall_x), |
| .stall_m (stall_m), |
| .kill_m (kill_m), |
| .exception_m (exception_m), |
| .store_operand_x (store_operand_x), |
| .load_store_address_x (adder_result_x), |
| .load_store_address_m (operand_m), |
| .load_store_address_w (operand_w[1:0]), |
| `ifdef CFG_MMU_ENABLED |
| .load_d (load_d), |
| .store_d (store_d), |
| `endif |
| .load_x (load_x), |
| .store_x (store_x), |
| .load_q_x (load_q_x), |
| .store_q_x (store_q_x), |
| .load_q_m (load_q_m), |
| .store_q_m (store_q_m), |
| .sign_extend_x (sign_extend_x), |
| .size_x (size_x), |
| `ifdef CFG_DCACHE_ENABLED |
| .dflush (dflush_m), |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| .irom_data_m (irom_data_m), |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| .dtlb_enable (dtlbe), |
| .tlbpaddr (tlbpaddr), |
| .tlbvaddr (tlbvaddr), |
| .dtlb_update (dtlb_update), |
| .dtlb_flush (dtlb_flush), |
| .dtlb_invalidate (dtlb_invalidate), |
| `endif |
| // From Wishbone |
| .d_dat_i (D_DAT_I), |
| .d_ack_i (D_ACK_I), |
| .d_err_i (D_ERR_I), |
| .d_rty_i (D_RTY_I), |
| // ----- Outputs ------- |
| // To pipeline |
| `ifdef CFG_DCACHE_ENABLED |
| .dcache_refill_request (dcache_refill_request), |
| .dcache_restart_request (dcache_restart_request), |
| .dcache_stall_request (dcache_stall_request), |
| .dcache_refilling (dcache_refilling), |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| .irom_store_data_m (irom_store_data_m), |
| .irom_address_xm (irom_address_xm), |
| .irom_we_xm (irom_we_xm), |
| .irom_stall_request_x (irom_stall_request_x), |
| `endif |
| .load_data_w (load_data_w), |
| .stall_wb_load (stall_wb_load), |
| `ifdef CFG_MMU_ENABLED |
| .dtlb_stall_request (dtlb_stall_request), |
| .dtlb_miss_vfn (dtlb_miss_vfn), |
| .dtlb_miss_x (dtlb_miss_x), |
| .dtlb_fault_x (dtlb_fault_x), |
| `endif |
| // To Wishbone |
| .d_dat_o (D_DAT_O), |
| .d_adr_o (D_ADR_O), |
| .d_cyc_o (D_CYC_O), |
| .d_sel_o (D_SEL_O), |
| .d_stb_o (D_STB_O), |
| .d_we_o (D_WE_O), |
| .d_cti_o (D_CTI_O), |
| .d_lock_o (D_LOCK_O), |
| .d_bte_o (D_BTE_O) |
| ); |
| |
| // Adder |
| lm32_adder adder ( |
| // ----- Inputs ------- |
| .adder_op_x (adder_op_x), |
| .adder_op_x_n (adder_op_x_n), |
| .operand_0_x (operand_0_x), |
| .operand_1_x (operand_1_x), |
| // ----- Outputs ------- |
| .adder_result_x (adder_result_x), |
| .adder_carry_n_x (adder_carry_n_x), |
| .adder_overflow_x (adder_overflow_x) |
| ); |
| |
| // Logic operations |
| lm32_logic_op logic_op ( |
| // ----- Inputs ------- |
| .logic_op_x (logic_op_x), |
| .operand_0_x (operand_0_x), |
| |
| .operand_1_x (operand_1_x), |
| // ----- Outputs ------- |
| .logic_result_x (logic_result_x) |
| ); |
| |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| // Pipelined barrel-shifter |
| lm32_shifter shifter ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| .stall_x (stall_x), |
| .direction_x (direction_x), |
| .sign_extend_x (sign_extend_x), |
| .operand_0_x (operand_0_x), |
| .operand_1_x (operand_1_x), |
| // ----- Outputs ------- |
| .shifter_result_m (shifter_result_m) |
| ); |
| `endif |
| |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| // Pipeline fixed-point multiplier |
| lm32_multiplier multiplier ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| .stall_x (stall_x), |
| .stall_m (stall_m), |
| .operand_0 (d_result_0), |
| .operand_1 (d_result_1), |
| // ----- Outputs ------- |
| .result (multiplier_result_w) |
| ); |
| `endif |
| |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| // Multi-cycle arithmetic |
| lm32_mc_arithmetic mc_arithmetic ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| .stall_d (stall_d), |
| .kill_x (kill_x), |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| .divide_d (divide_q_d), |
| .modulus_d (modulus_q_d), |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| .multiply_d (multiply_q_d), |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| .shift_left_d (shift_left_q_d), |
| .shift_right_d (shift_right_q_d), |
| .sign_extend_d (sign_extend_d), |
| `endif |
| .operand_0_d (d_result_0), |
| .operand_1_d (d_result_1), |
| // ----- Outputs ------- |
| .result_x (mc_result_x), |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| .divide_by_zero_x (divide_by_zero_x), |
| `endif |
| .stall_request_x (mc_stall_request_x) |
| ); |
| `endif |
| |
| `ifdef CFG_INTERRUPTS_ENABLED |
| // Interrupt unit |
| lm32_interrupt interrupt_unit ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| // From external devices |
| .interrupt (interrupt), |
| // From pipeline |
| .stall_x (stall_x), |
| `ifdef CFG_DEBUG_ENABLED |
| .non_debug_exception (non_debug_exception_q_w), |
| .debug_exception (debug_exception_q_w), |
| `else |
| .exception (exception_q_w), |
| `endif |
| .eret_q_x (eret_k_q_x), |
| `ifdef CFG_DEBUG_ENABLED |
| .bret_q_x (bret_k_q_x), |
| `endif |
| .csr (csr_x), |
| .csr_write_data (operand_1_x), |
| .csr_write_enable (csr_write_enable_k_q_x), |
| // ----- Outputs ------- |
| .interrupt_exception (interrupt_exception), |
| // To pipeline |
| .csr_read_data (interrupt_csr_read_data_x) |
| ); |
| `endif |
| |
| `ifdef CFG_JTAG_ENABLED |
| // JTAG interface |
| lm32_jtag jtag ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| // From JTAG |
| .jtag_clk (jtag_clk), |
| .jtag_update (jtag_update), |
| .jtag_reg_q (jtag_reg_q), |
| .jtag_reg_addr_q (jtag_reg_addr_q), |
| // From pipeline |
| `ifdef CFG_JTAG_UART_ENABLED |
| .csr (csr_x), |
| .csr_write_data (operand_1_x), |
| .csr_write_enable (csr_write_enable_k_q_x), |
| .stall_x (stall_x), |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| .jtag_read_data (jtag_read_data), |
| .jtag_access_complete (jtag_access_complete), |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| .exception_q_w (debug_exception_q_w || non_debug_exception_q_w), |
| `endif |
| // ----- Outputs ------- |
| // To pipeline |
| `ifdef CFG_JTAG_UART_ENABLED |
| .jtx_csr_read_data (jtx_csr_read_data), |
| .jrx_csr_read_data (jrx_csr_read_data), |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| .jtag_csr_write_enable (jtag_csr_write_enable), |
| .jtag_csr_write_data (jtag_csr_write_data), |
| .jtag_csr (jtag_csr), |
| .jtag_read_enable (jtag_read_enable), |
| .jtag_write_enable (jtag_write_enable), |
| .jtag_write_data (jtag_write_data), |
| .jtag_address (jtag_address), |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| .jtag_break (jtag_break), |
| .jtag_reset (reset_exception), |
| `endif |
| // To JTAG |
| .jtag_reg_d (jtag_reg_d), |
| .jtag_reg_addr_d (jtag_reg_addr_d) |
| ); |
| `endif |
| |
| `ifdef CFG_DEBUG_ENABLED |
| // Debug unit |
| lm32_debug #( |
| .breakpoints (breakpoints), |
| .watchpoints (watchpoints) |
| ) hw_debug ( |
| // ----- Inputs ------- |
| .clk_i (clk_i), |
| .rst_i (rst_i), |
| .pc_x (pc_x), |
| .load_x (load_x), |
| .store_x (store_x), |
| .load_store_address_x (adder_result_x), |
| .csr_write_enable_x (csr_write_enable_k_q_x), |
| .csr_write_data (operand_1_x), |
| .csr_x (csr_x), |
| `ifdef CFG_HW_DEBUG_ENABLED |
| .jtag_csr_write_enable (jtag_csr_write_enable), |
| .jtag_csr_write_data (jtag_csr_write_data), |
| .jtag_csr (jtag_csr), |
| `endif |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| .eret_q_x (eret_k_q_x), |
| .bret_q_x (bret_k_q_x), |
| .stall_x (stall_x), |
| .exception_x (exception_x), |
| .q_x (q_x), |
| `ifdef CFG_DCACHE_ENABLED |
| .dcache_refill_request (dcache_refill_request), |
| `endif |
| `endif |
| // ----- Outputs ------- |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| .dc_ss (dc_ss), |
| `endif |
| .dc_re (dc_re), |
| .bp_match (bp_match), |
| .wp_match (wp_match) |
| ); |
| `endif |
| |
| // Register file |
| |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| /*---------------------------------------------------------------------- |
| Register File is implemented using EBRs. There can be three accesses to |
| the register file in each cycle: two reads and one write. On-chip block |
| RAM has two read/write ports. To accomodate three accesses, two on-chip |
| block RAMs are used (each register file "write" is made to both block |
| RAMs). |
| |
| One limitation of the on-chip block RAMs is that one cannot perform a |
| read and write to same location in a cycle (if this is done, then the |
| data read out is indeterminate). |
| ----------------------------------------------------------------------*/ |
| wire [31:0] regfile_data_0, regfile_data_1; |
| reg [31:0] w_result_d; |
| reg regfile_raw_0, regfile_raw_0_nxt; |
| reg regfile_raw_1, regfile_raw_1_nxt; |
| |
| /*---------------------------------------------------------------------- |
| Check if read and write is being performed to same register in current |
| cycle? This is done by comparing the read and write IDXs. |
| ----------------------------------------------------------------------*/ |
| always @(reg_write_enable_q_w or write_idx_w or instruction_f) |
| begin |
| if (reg_write_enable_q_w |
| && (write_idx_w == instruction_f[25:21])) |
| regfile_raw_0_nxt = 1'b1; |
| else |
| regfile_raw_0_nxt = 1'b0; |
| |
| if (reg_write_enable_q_w |
| && (write_idx_w == instruction_f[20:16])) |
| regfile_raw_1_nxt = 1'b1; |
| else |
| regfile_raw_1_nxt = 1'b0; |
| end |
| |
| /*---------------------------------------------------------------------- |
| Select latched (delayed) write value or data from register file. If |
| read in previous cycle was performed to register written to in same |
| cycle, then latched (delayed) write value is selected. |
| ----------------------------------------------------------------------*/ |
| always @(regfile_raw_0 or w_result_d or regfile_data_0) |
| if (regfile_raw_0) |
| reg_data_live_0 = w_result_d; |
| else |
| reg_data_live_0 = regfile_data_0; |
| |
| /*---------------------------------------------------------------------- |
| Select latched (delayed) write value or data from register file. If |
| read in previous cycle was performed to register written to in same |
| cycle, then latched (delayed) write value is selected. |
| ----------------------------------------------------------------------*/ |
| always @(regfile_raw_1 or w_result_d or regfile_data_1) |
| if (regfile_raw_1) |
| reg_data_live_1 = w_result_d; |
| else |
| reg_data_live_1 = regfile_data_1; |
| |
| /*---------------------------------------------------------------------- |
| Latch value written to register file |
| ----------------------------------------------------------------------*/ |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| if (rst_i == `TRUE) |
| begin |
| regfile_raw_0 <= 1'b0; |
| regfile_raw_1 <= 1'b0; |
| w_result_d <= 32'b0; |
| end |
| else |
| begin |
| regfile_raw_0 <= regfile_raw_0_nxt; |
| regfile_raw_1 <= regfile_raw_1_nxt; |
| w_result_d <= w_result; |
| end |
| |
| /*---------------------------------------------------------------------- |
| Register file instantiation as Pseudo-Dual Port EBRs. |
| ----------------------------------------------------------------------*/ |
| // Modified by GSI: removed non-portable RAM instantiation |
| lm32_ram |
| #( |
| // ----- Parameters ----- |
| .data_width(32), |
| .address_width(5) |
| ) |
| reg_0 |
| ( |
| // ----- Inputs ----- |
| .read_clk (clk_i), |
| .write_clk (clk_i), |
| .reset (rst_i), |
| .enable_read (`TRUE), |
| .read_address (instruction_f[25:21]), |
| .enable_write (`TRUE), |
| .write_address (write_idx_w), |
| .write_data (w_result), |
| .write_enable (reg_write_enable_q_w), |
| // ----- Outputs ----- |
| .read_data (regfile_data_0) |
| ); |
| |
| lm32_ram |
| #( |
| .data_width(32), |
| .address_width(5) |
| ) |
| reg_1 |
| ( |
| // ----- Inputs ----- |
| .read_clk (clk_i), |
| .write_clk (clk_i), |
| .reset (rst_i), |
| .enable_read (`TRUE), |
| .read_address (instruction_f[20:16]), |
| .enable_write (`TRUE), |
| .write_address (write_idx_w), |
| .write_data (w_result), |
| .write_enable (reg_write_enable_q_w), |
| // ----- Outputs ----- |
| .read_data (regfile_data_1) |
| ); |
| `endif |
| |
| `ifdef CFG_EBR_NEGEDGE_REGISTER_FILE |
| lm32_ram |
| #( |
| .data_width(32), |
| .address_width(5) |
| ) |
| reg_0 |
| ( |
| // ----- Inputs ----- |
| .read_clk (clk_i), |
| .write_clk (clk_n_i), |
| .reset (rst_i), |
| .enable_read (stall_f == `FALSE), |
| .read_address (read_idx_0_d), |
| .enable_write (`TRUE), |
| .write_address (write_idx_w), |
| .write_data (w_result), |
| .write_enable (reg_write_enable_q_w), |
| // ----- Outputs ----- |
| .read_data (reg_data_0) |
| ); |
| |
| lm32_ram |
| #( |
| .data_width(32), |
| .address_width(5) |
| ) |
| reg_1 |
| ( |
| // ----- Inputs ----- |
| .read_clk (clk_i), |
| .write_clk (clk_n_i), |
| .reset (rst_i), |
| .enable_read (stall_f == `FALSE), |
| .read_address (read_idx_1_d), |
| .enable_write (`TRUE), |
| .write_address (write_idx_w), |
| .write_data (w_result), |
| .write_enable (reg_write_enable_q_w), |
| // ----- Outputs ----- |
| .read_data (reg_data_1) |
| ); |
| `endif |
| |
| |
| ///////////////////////////////////////////////////// |
| // Combinational Logic |
| ///////////////////////////////////////////////////// |
| |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| // Select between buffered and live data from register file |
| assign reg_data_0 = use_buf ? reg_data_buf_0 : reg_data_live_0; |
| assign reg_data_1 = use_buf ? reg_data_buf_1 : reg_data_live_1; |
| `endif |
| `ifdef LM32_EBR_REGISTER_FILE |
| `else |
| // Register file read ports |
| assign reg_data_0 = registers[read_idx_0_d]; |
| assign reg_data_1 = registers[read_idx_1_d]; |
| `endif |
| |
| // Detect read-after-write hazzards |
| assign raw_x_0 = (write_idx_x == read_idx_0_d) && (write_enable_q_x == `TRUE); |
| assign raw_m_0 = (write_idx_m == read_idx_0_d) && (write_enable_q_m == `TRUE); |
| assign raw_w_0 = (write_idx_w == read_idx_0_d) && (write_enable_q_w == `TRUE); |
| assign raw_x_1 = (write_idx_x == read_idx_1_d) && (write_enable_q_x == `TRUE); |
| assign raw_m_1 = (write_idx_m == read_idx_1_d) && (write_enable_q_m == `TRUE); |
| assign raw_w_1 = (write_idx_w == read_idx_1_d) && (write_enable_q_w == `TRUE); |
| |
| // Interlock detection - Raise an interlock for RAW hazzards |
| always @(*) |
| begin |
| if ( ( (x_bypass_enable_x == `FALSE) |
| && ( ((read_enable_0_d == `TRUE) && (raw_x_0 == `TRUE)) |
| || ((read_enable_1_d == `TRUE) && (raw_x_1 == `TRUE)) |
| ) |
| ) |
| || ( (m_bypass_enable_m == `FALSE) |
| && ( ((read_enable_0_d == `TRUE) && (raw_m_0 == `TRUE)) |
| || ((read_enable_1_d == `TRUE) && (raw_m_1 == `TRUE)) |
| ) |
| ) |
| ) |
| interlock = `TRUE; |
| else |
| interlock = `FALSE; |
| end |
| |
| // Bypass for reg port 0 |
| always @(*) |
| begin |
| if (raw_x_0 == `TRUE) |
| bypass_data_0 = x_result; |
| else if (raw_m_0 == `TRUE) |
| bypass_data_0 = m_result; |
| else if (raw_w_0 == `TRUE) |
| bypass_data_0 = w_result; |
| else |
| bypass_data_0 = reg_data_0; |
| end |
| |
| // Bypass for reg port 1 |
| always @(*) |
| begin |
| if (raw_x_1 == `TRUE) |
| bypass_data_1 = x_result; |
| else if (raw_m_1 == `TRUE) |
| bypass_data_1 = m_result; |
| else if (raw_w_1 == `TRUE) |
| bypass_data_1 = w_result; |
| else |
| bypass_data_1 = reg_data_1; |
| end |
| |
| /*---------------------------------------------------------------------- |
| Branch prediction is performed in D stage of pipeline. Only PC-relative |
| branches are predicted: forward-pointing conditional branches are not- |
| taken, while backward-pointing conditional branches are taken. |
| Unconditional branches are always predicted taken! |
| ----------------------------------------------------------------------*/ |
| assign branch_predict_d = bi_unconditional | bi_conditional; |
| assign branch_predict_taken_d = bi_unconditional ? 1'b1 : (bi_conditional ? instruction_d[15] : 1'b0); |
| |
| // Compute branch target address: Branch PC PLUS Offset |
| assign branch_target_d = pc_d + branch_offset_d; |
| |
| // Compute fetch address. Address of instruction sequentially after the |
| // branch if branch is not taken. Target address of branch is branch is |
| // taken |
| assign branch_predict_address_d = branch_predict_taken_d ? branch_target_d : pc_f; |
| |
| // D stage result selection |
| always @(*) |
| begin |
| d_result_0 = d_result_sel_0_d[0] ? {pc_f, 2'b00} : bypass_data_0; |
| case (d_result_sel_1_d) |
| `LM32_D_RESULT_SEL_1_ZERO: d_result_1 = {`LM32_WORD_WIDTH{1'b0}}; |
| `LM32_D_RESULT_SEL_1_REG_1: d_result_1 = bypass_data_1; |
| `LM32_D_RESULT_SEL_1_IMMEDIATE: d_result_1 = immediate_d; |
| default: d_result_1 = {`LM32_WORD_WIDTH{1'bx}}; |
| endcase |
| end |
| |
| `ifdef CFG_USER_ENABLED |
| // Operands for user-defined instructions |
| assign user_operand_0 = operand_0_x; |
| assign user_operand_1 = operand_1_x; |
| `endif |
| |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| // Sign-extension |
| assign sextb_result_x = {{24{operand_0_x[7]}}, operand_0_x[7:0]}; |
| assign sexth_result_x = {{16{operand_0_x[15]}}, operand_0_x[15:0]}; |
| assign sext_result_x = size_x == `LM32_SIZE_BYTE ? sextb_result_x : sexth_result_x; |
| `endif |
| |
| `ifdef LM32_NO_BARREL_SHIFT |
| // Only single bit shift operations are supported when barrel-shifter isn't implemented |
| assign shifter_result_x = {operand_0_x[`LM32_WORD_WIDTH-1] & sign_extend_x, operand_0_x[`LM32_WORD_WIDTH-1:1]}; |
| `endif |
| |
| // Condition evaluation |
| assign cmp_zero = operand_0_x == operand_1_x; |
| assign cmp_negative = adder_result_x[`LM32_WORD_WIDTH-1]; |
| assign cmp_overflow = adder_overflow_x; |
| assign cmp_carry_n = adder_carry_n_x; |
| always @(*) |
| begin |
| case (condition_x) |
| `LM32_CONDITION_U1: condition_met_x = `TRUE; |
| `LM32_CONDITION_U2: condition_met_x = `TRUE; |
| `LM32_CONDITION_E: condition_met_x = cmp_zero; |
| `LM32_CONDITION_NE: condition_met_x = !cmp_zero; |
| `LM32_CONDITION_G: condition_met_x = !cmp_zero && (cmp_negative == cmp_overflow); |
| `LM32_CONDITION_GU: condition_met_x = cmp_carry_n && !cmp_zero; |
| `LM32_CONDITION_GE: condition_met_x = cmp_negative == cmp_overflow; |
| `LM32_CONDITION_GEU: condition_met_x = cmp_carry_n; |
| default: condition_met_x = 1'bx; |
| endcase |
| end |
| |
| // X stage result selection |
| always @(*) |
| begin |
| x_result = x_result_sel_add_x ? adder_result_x |
| : x_result_sel_csr_x ? csr_read_data_x |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| : x_result_sel_sext_x ? sext_result_x |
| `endif |
| `ifdef CFG_USER_ENABLED |
| : x_result_sel_user_x ? user_result |
| `endif |
| `ifdef LM32_NO_BARREL_SHIFT |
| : x_result_sel_shift_x ? shifter_result_x |
| `endif |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| : x_result_sel_mc_arith_x ? mc_result_x |
| `endif |
| : logic_result_x; |
| end |
| |
| // M stage result selection |
| always @(*) |
| begin |
| m_result = m_result_sel_compare_m ? {{`LM32_WORD_WIDTH-1{1'b0}}, condition_met_m} |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| : m_result_sel_shift_m ? shifter_result_m |
| `endif |
| : operand_m; |
| end |
| |
| // W stage result selection |
| always @(*) |
| begin |
| w_result = w_result_sel_load_w ? load_data_w |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| : w_result_sel_mul_w ? multiplier_result_w |
| `endif |
| : operand_w; |
| end |
| |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| // Indicate when a branch should be taken in X stage |
| assign branch_taken_x = (stall_x == `FALSE) |
| && ( (branch_x == `TRUE) |
| && ((condition_x == `LM32_CONDITION_U1) || (condition_x == `LM32_CONDITION_U2)) |
| && (valid_x == `TRUE) |
| && (branch_predict_x == `FALSE) |
| ); |
| `endif |
| |
| // Indicate when a branch should be taken in M stage (exceptions are a type of branch) |
| assign branch_taken_m = (stall_m == `FALSE) |
| && ( ( (branch_m == `TRUE) |
| && (valid_m == `TRUE) |
| && ( ( (condition_met_m == `TRUE) |
| && (branch_predict_taken_m == `FALSE) |
| ) |
| || ( (condition_met_m == `FALSE) |
| && (branch_predict_m == `TRUE) |
| && (branch_predict_taken_m == `TRUE) |
| ) |
| ) |
| ) |
| || (exception_m == `TRUE) |
| ); |
| |
| // Indicate when a branch in M stage is mispredicted as being taken |
| assign branch_mispredict_taken_m = (condition_met_m == `FALSE) |
| && (branch_predict_m == `TRUE) |
| && (branch_predict_taken_m == `TRUE); |
| |
| // Indicate when a branch in M stage will cause flush in X stage |
| assign branch_flushX_m = (stall_m == `FALSE) |
| && ( ( (branch_m == `TRUE) |
| && (valid_m == `TRUE) |
| && ( (condition_met_m == `TRUE) |
| || ( (condition_met_m == `FALSE) |
| && (branch_predict_m == `TRUE) |
| && (branch_predict_taken_m == `TRUE) |
| ) |
| ) |
| ) |
| || (exception_m == `TRUE) |
| ); |
| |
| // Generate signal that will kill instructions in each pipeline stage when necessary |
| assign kill_f = ( (valid_d == `TRUE) |
| && (branch_predict_taken_d == `TRUE) |
| ) |
| || (branch_taken_m == `TRUE) |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| || (branch_taken_x == `TRUE) |
| `endif |
| `ifdef CFG_ICACHE_ENABLED |
| || (icache_refill_request == `TRUE) |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| || (dcache_refill_request == `TRUE) |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| || (itlb_miss_exception == `TRUE) |
| `endif |
| ; |
| assign kill_d = (branch_taken_m == `TRUE) |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| || (branch_taken_x == `TRUE) |
| `endif |
| `ifdef CFG_ICACHE_ENABLED |
| || (icache_refill_request == `TRUE) |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| || (dcache_refill_request == `TRUE) |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| || (itlb_miss_exception == `TRUE) |
| `endif |
| ; |
| assign kill_x = (branch_flushX_m == `TRUE) |
| `ifdef CFG_DCACHE_ENABLED |
| || (dcache_refill_request == `TRUE) |
| `endif |
| ; |
| assign kill_m = `FALSE |
| `ifdef CFG_DCACHE_ENABLED |
| || (dcache_refill_request == `TRUE) |
| `endif |
| ; |
| assign kill_w = `FALSE |
| `ifdef CFG_DCACHE_ENABLED |
| || (dcache_refill_request == `TRUE) |
| `endif |
| ; |
| |
| // Exceptions |
| |
| `ifdef CFG_DEBUG_ENABLED |
| assign breakpoint_exception = ( ( (break_x == `TRUE) |
| || (bp_match == `TRUE) |
| ) |
| && (valid_x == `TRUE) |
| ) |
| `ifdef CFG_JTAG_ENABLED |
| || (jtag_break == `TRUE) |
| `endif |
| `ifdef CFG_EXTERNAL_BREAK_ENABLED |
| || (ext_break_r == `TRUE) |
| `endif |
| ; |
| `endif |
| |
| `ifdef CFG_DEBUG_ENABLED |
| assign watchpoint_exception = wp_match == `TRUE; |
| `endif |
| |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| assign instruction_bus_error_exception = ( (bus_error_x == `TRUE) |
| && (valid_x == `TRUE) |
| ); |
| assign data_bus_error_exception = data_bus_error_seen == `TRUE; |
| `endif |
| |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| assign divide_by_zero_exception = divide_by_zero_x == `TRUE; |
| `endif |
| |
| assign system_call_exception = ( (scall_x == `TRUE) |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| && (valid_x == `TRUE) |
| `endif |
| ); |
| |
| `ifdef CFG_MMU_ENABLED |
| assign itlb_miss_exception = ( (itlb_miss_x == `TRUE) |
| && (itlbe == `TRUE) |
| && (valid_x == `TRUE) |
| ); |
| assign itlb_exception = (itlb_miss_exception == `TRUE); |
| |
| assign dtlb_miss_exception = ( (dtlb_miss_x == `TRUE) |
| && (dtlbe == `TRUE) |
| && (valid_x == `TRUE) |
| ); |
| assign dtlb_fault_exception = ( (dtlb_fault_x == `TRUE) |
| && (dtlbe == `TRUE) |
| && (valid_x == `TRUE) |
| ); |
| assign dtlb_exception = (dtlb_miss_exception == `TRUE) || (dtlb_fault_exception == `TRUE); |
| |
| assign privilege_exception = ( (usr == `TRUE) |
| && ( (csr_write_enable_q_x == `TRUE) |
| || (eret_q_x == `TRUE) |
| `ifdef CFG_DEBUG_ENABLED |
| || (bret_q_x == `TRUE) |
| `endif |
| ) |
| ); |
| `endif |
| |
| `ifdef CFG_DEBUG_ENABLED |
| assign debug_exception_x = (breakpoint_exception == `TRUE) |
| || (watchpoint_exception == `TRUE) |
| ; |
| |
| assign non_debug_exception_x = (system_call_exception == `TRUE) |
| `ifdef CFG_JTAG_ENABLED |
| || (reset_exception == `TRUE) |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| || (instruction_bus_error_exception == `TRUE) |
| || (data_bus_error_exception == `TRUE) |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| || (divide_by_zero_exception == `TRUE) |
| `endif |
| `ifdef CFG_INTERRUPTS_ENABLED |
| || ( (interrupt_exception == `TRUE) |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| && (dc_ss == `FALSE) |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| && (store_q_m == `FALSE) |
| && (D_CYC_O == `FALSE) |
| `endif |
| ) |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| || (itlb_exception == `TRUE) |
| || (dtlb_exception == `TRUE) |
| || (privilege_exception == `TRUE) |
| `endif |
| ; |
| |
| assign exception_x = (debug_exception_x == `TRUE) || (non_debug_exception_x == `TRUE); |
| `else |
| assign exception_x = (system_call_exception == `TRUE) |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| || (instruction_bus_error_exception == `TRUE) |
| || (data_bus_error_exception == `TRUE) |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| || (divide_by_zero_exception == `TRUE) |
| `endif |
| `ifdef CFG_INTERRUPTS_ENABLED |
| || ( (interrupt_exception == `TRUE) |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| && (dc_ss == `FALSE) |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| && (store_q_m == `FALSE) |
| && (D_CYC_O == `FALSE) |
| `endif |
| ) |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| || (itlb_exception == `TRUE) |
| || (dtlb_exception == `TRUE) |
| || (privilege_exception == `TRUE) |
| `endif |
| ; |
| `endif |
| |
| // Exception ID |
| always @(*) |
| begin |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_JTAG_ENABLED |
| if (reset_exception == `TRUE) |
| eid_x = `LM32_EID_RESET; |
| else |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| if (data_bus_error_exception == `TRUE) |
| eid_x = `LM32_EID_DATA_BUS_ERROR; |
| else |
| `endif |
| if (breakpoint_exception == `TRUE) |
| eid_x = `LM32_EID_BREAKPOINT; |
| else |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| if (data_bus_error_exception == `TRUE) |
| eid_x = `LM32_EID_DATA_BUS_ERROR; |
| else |
| if (instruction_bus_error_exception == `TRUE) |
| eid_x = `LM32_EID_INST_BUS_ERROR; |
| else |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| if (watchpoint_exception == `TRUE) |
| eid_x = `LM32_EID_WATCHPOINT; |
| else |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| if (divide_by_zero_exception == `TRUE) |
| eid_x = `LM32_EID_DIVIDE_BY_ZERO; |
| else |
| `endif |
| `ifdef CFG_INTERRUPTS_ENABLED |
| if ( (interrupt_exception == `TRUE) |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| && (dc_ss == `FALSE) |
| `endif |
| ) |
| eid_x = `LM32_EID_INTERRUPT; |
| else |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| if (itlb_miss_exception == `TRUE) |
| eid_x = `LM32_EID_ITLB_MISS; |
| else |
| if (dtlb_miss_exception == `TRUE) |
| eid_x = `LM32_EID_DTLB_MISS; |
| else |
| if (dtlb_fault_exception == `TRUE) |
| eid_x = `LM32_EID_DTLB_FAULT; |
| else |
| if (privilege_exception == `TRUE) |
| eid_x = `LM32_EID_PRIVILEGE; |
| else |
| `endif |
| eid_x = `LM32_EID_SCALL; |
| end |
| |
| // Stall generation |
| |
| assign stall_a = (stall_f == `TRUE); |
| |
| assign stall_f = (stall_d == `TRUE) |
| `ifdef CFG_MMU_ENABLED |
| // We need to stall for one cycle. Otherwise the icache |
| // starts one cycle earlier and the restart address will be |
| // wrong in case of a miss, that is one instruction is |
| // skipped. |
| || ( (itlbe == `TRUE) |
| `ifdef CFG_DEBUG_ENABLED |
| && ( (debug_exception_q_w == `TRUE) |
| || (non_debug_exception_q_w == `TRUE) |
| ) |
| `else |
| && (exception_q_w == `TRUE) |
| `endif |
| ) |
| `endif |
| ; |
| |
| assign stall_d = (stall_x == `TRUE) |
| || ( (interlock == `TRUE) |
| && (kill_d == `FALSE) |
| ) |
| || ( ( (eret_d == `TRUE) |
| || (scall_d == `TRUE) |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| || (bus_error_d == `TRUE) |
| `endif |
| ) |
| && ( (load_q_x == `TRUE) |
| || (load_q_m == `TRUE) |
| || (store_q_x == `TRUE) |
| || (store_q_m == `TRUE) |
| || (D_CYC_O == `TRUE) |
| ) |
| && (kill_d == `FALSE) |
| ) |
| `ifdef CFG_DEBUG_ENABLED |
| || ( ( (break_d == `TRUE) |
| || (bret_d == `TRUE) |
| ) |
| && ( (load_q_x == `TRUE) |
| || (store_q_x == `TRUE) |
| || (load_q_m == `TRUE) |
| || (store_q_m == `TRUE) |
| || (D_CYC_O == `TRUE) |
| ) |
| && (kill_d == `FALSE) |
| ) |
| `endif |
| || ( (csr_write_enable_d == `TRUE) |
| && (load_q_x == `TRUE) |
| ) |
| ; |
| |
| assign stall_x = (stall_m == `TRUE) |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| || ( (mc_stall_request_x == `TRUE) |
| && (kill_x == `FALSE) |
| ) |
| `endif |
| `ifdef CFG_IROM_ENABLED |
| // Stall load/store instruction in D stage if there is an ongoing store |
| // operation to instruction ROM in M stage |
| || ( (irom_stall_request_x == `TRUE) |
| && ( (load_d == `TRUE) |
| || (store_d == `TRUE) |
| ) |
| ) |
| `endif |
| ; |
| |
| assign stall_m = (stall_wb_load == `TRUE) |
| `ifdef CFG_SIZE_OVER_SPEED |
| || (D_CYC_O == `TRUE) |
| `else |
| || ( (D_CYC_O == `TRUE) |
| && ( (store_m == `TRUE) |
| /* |
| Bug: Following loop does not allow interrupts to be services since |
| either D_CYC_O or store_m is always high during entire duration of |
| loop. |
| L1: addi r1, r1, 1 |
| sw (r2,0), r1 |
| bi L1 |
| |
| Introduce a single-cycle stall when a wishbone cycle is in progress |
| and a new store instruction is in Execute stage and a interrupt |
| exception has occured. This stall will ensure that D_CYC_O and |
| store_m will both be low for one cycle. |
| */ |
| `ifdef CFG_INTERRUPTS_ENABLED |
| || ((store_x == `TRUE) && (interrupt_exception == `TRUE)) |
| `endif |
| || (load_m == `TRUE) |
| || (load_x == `TRUE) |
| ) |
| ) |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| || (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 |
| `endif |
| `ifdef CFG_ICACHE_ENABLED |
| || (icache_stall_request == `TRUE) // Pipeline needs to be stalled otherwise branches may be lost |
| || ((I_CYC_O == `TRUE) && ((branch_m == `TRUE) || (exception_m == `TRUE))) |
| `else |
| `ifdef CFG_IWB_ENABLED |
| || (I_CYC_O == `TRUE) |
| `endif |
| `endif |
| `ifdef CFG_USER_ENABLED |
| || ( (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) |
| && (user_complete == `FALSE) |
| ) |
| `endif |
| `ifdef CFG_MMU_ENABLED |
| || (itlb_stall_request == `TRUE) // ITLB is busy |
| || (dtlb_stall_request == `TRUE) // DTLB is busy or a lookup is in progress |
| `endif |
| ; |
| |
| // Qualify state changing control signals |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| assign q_d = (valid_d == `TRUE) && (kill_d == `FALSE); |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| assign shift_left_q_d = (shift_left_d == `TRUE) && (q_d == `TRUE); |
| assign shift_right_q_d = (shift_right_d == `TRUE) && (q_d == `TRUE); |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| assign multiply_q_d = (multiply_d == `TRUE) && (q_d == `TRUE); |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| assign divide_q_d = (divide_d == `TRUE) && (q_d == `TRUE); |
| assign modulus_q_d = (modulus_d == `TRUE) && (q_d == `TRUE); |
| `endif |
| assign q_x = (valid_x == `TRUE) && (kill_x == `FALSE); |
| assign csr_write_enable_q_x = (csr_write_enable_x == `TRUE) && (q_x == `TRUE); |
| assign csr_write_enable_k_q_x = (csr_write_enable_q_x == `TRUE) |
| `ifdef CFG_MMU_ENABLED |
| && (usr == `FALSE) |
| `endif |
| ; |
| assign eret_q_x = (eret_x == `TRUE) && (q_x == `TRUE); |
| assign eret_k_q_x = (eret_q_x == `TRUE) |
| `ifdef CFG_MMU_ENABLED |
| && (usr == `FALSE) |
| `endif |
| ; |
| `ifdef CFG_DEBUG_ENABLED |
| assign bret_q_x = (bret_x == `TRUE) && (q_x == `TRUE); |
| assign bret_k_q_x = (bret_q_x == `TRUE) |
| `ifdef CFG_MMU_ENABLED |
| && (usr == `FALSE) |
| `endif |
| ; |
| `endif |
| assign load_q_x = (load_x == `TRUE) |
| && (q_x == `TRUE) |
| `ifdef CFG_DEBUG_ENABLED |
| && (bp_match == `FALSE) |
| `endif |
| ; |
| assign store_q_x = (store_x == `TRUE) |
| && (q_x == `TRUE) |
| `ifdef CFG_DEBUG_ENABLED |
| && (bp_match == `FALSE) |
| `endif |
| ; |
| `ifdef CFG_USER_ENABLED |
| assign user_valid = (x_result_sel_user_x == `TRUE) && (q_x == `TRUE); |
| `endif |
| assign q_m = (valid_m == `TRUE) && (kill_m == `FALSE) && (exception_m == `FALSE); |
| assign load_q_m = (load_m == `TRUE) && (q_m == `TRUE); |
| assign store_q_m = (store_m == `TRUE) && (q_m == `TRUE); |
| `ifdef CFG_DEBUG_ENABLED |
| assign debug_exception_q_w = ((debug_exception_w == `TRUE) && (valid_w == `TRUE)); |
| assign non_debug_exception_q_w = ((non_debug_exception_w == `TRUE) && (valid_w == `TRUE)); |
| `else |
| assign exception_q_w = ((exception_w == `TRUE) && (valid_w == `TRUE)); |
| `endif |
| // 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) |
| assign write_enable_q_x = (write_enable_x == `TRUE) && (valid_x == `TRUE) && (branch_flushX_m == `FALSE); |
| assign write_enable_q_m = (write_enable_m == `TRUE) && (valid_m == `TRUE); |
| assign write_enable_q_w = (write_enable_w == `TRUE) && (valid_w == `TRUE); |
| // The enable that actually does write the registers needs to be qualified with kill |
| assign reg_write_enable_q_w = (write_enable_w == `TRUE) && (kill_w == `FALSE) && (valid_w == `TRUE) || rst_i; |
| |
| // Configuration (CFG) CSR |
| assign cfg = { |
| `LM32_REVISION, |
| watchpoints[3:0], |
| breakpoints[3:0], |
| interrupts[5:0], |
| `ifdef CFG_JTAG_UART_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_ROM_DEBUG_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_HW_DEBUG_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_ICACHE_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_CYCLE_COUNTER_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_USER_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef LM32_BARREL_SHIFT_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef LM32_MULTIPLY_ENABLED |
| `TRUE |
| `else |
| `FALSE |
| `endif |
| }; |
| |
| assign cfg2 = { |
| `ifdef CFG_MMU_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| 29'b0, |
| `ifdef CFG_IROM_ENABLED |
| `TRUE, |
| `else |
| `FALSE, |
| `endif |
| `ifdef CFG_DRAM_ENABLED |
| `TRUE |
| `else |
| `FALSE |
| `endif |
| }; |
| |
| `ifdef CFG_MMU_ENABLED |
| assign psw = { |
| {`LM32_WORD_WIDTH-12{1'b0}}, |
| `ifdef CFG_DEBUG_ENABLED |
| busr, |
| `else |
| `FALSE, |
| `endif |
| eusr, |
| usr, |
| `ifdef CFG_DEBUG_ENABLED |
| bdtlbe, |
| `else |
| `FALSE, |
| `endif |
| edtlbe, |
| dtlbe, |
| `ifdef CFG_DEBUG_ENABLED |
| bitlbe, |
| `else |
| `FALSE, |
| `endif |
| eitlbe, |
| itlbe, |
| interrupt_csr_read_data_x[2:0] |
| }; |
| `endif |
| |
| // Cache flush |
| `ifdef CFG_ICACHE_ENABLED |
| assign iflush = ( (csr_write_enable_d == `TRUE) |
| && (csr_d == `LM32_CSR_ICC) |
| && (stall_d == `FALSE) |
| && (kill_d == `FALSE) |
| && (valid_d == `TRUE)) |
| // Added by GSI: needed to flush cache after loading firmware per JTAG |
| `ifdef CFG_HW_DEBUG_ENABLED |
| || |
| ( (jtag_csr_write_enable == `TRUE) |
| && (jtag_csr == `LM32_CSR_ICC)) |
| `endif |
| ; |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| assign dflush_x = ( (csr_write_enable_q_x == `TRUE) |
| && (csr_x == `LM32_CSR_DCC)) |
| // Added by GSI: needed to flush cache after loading firmware per JTAG |
| `ifdef CFG_HW_DEBUG_ENABLED |
| || |
| ( (jtag_csr_write_enable == `TRUE) |
| && (jtag_csr == `LM32_CSR_DCC)) |
| `endif |
| ; |
| `endif |
| |
| // Extract CSR index |
| assign csr_d = read_idx_0_d[`LM32_CSR_RNG]; |
| |
| // CSR reads |
| always @(*) |
| begin |
| case (csr_x) |
| `ifdef CFG_INTERRUPTS_ENABLED |
| `LM32_CSR_IE, |
| `LM32_CSR_IM, |
| `LM32_CSR_IP: csr_read_data_x = interrupt_csr_read_data_x; |
| `endif |
| `ifdef CFG_CYCLE_COUNTER_ENABLED |
| `LM32_CSR_CC: csr_read_data_x = cc; |
| `endif |
| `LM32_CSR_CFG: csr_read_data_x = cfg; |
| `LM32_CSR_EBA: csr_read_data_x = {eba, {(`LM32_WORD_WIDTH-`LM32_EBA_WIDTH){1'b0}}}; |
| `ifdef CFG_DEBUG_ENABLED |
| `LM32_CSR_DEBA: csr_read_data_x = {deba, {(`LM32_WORD_WIDTH-`LM32_EBA_WIDTH){1'b0}}}; |
| `endif |
| `ifdef CFG_JTAG_UART_ENABLED |
| `LM32_CSR_JTX: csr_read_data_x = jtx_csr_read_data; |
| `LM32_CSR_JRX: csr_read_data_x = jrx_csr_read_data; |
| `endif |
| `LM32_CSR_CFG2: csr_read_data_x = cfg2; |
| `ifdef CFG_MMU_ENABLED |
| `LM32_CSR_PSW: csr_read_data_x = psw; |
| `LM32_CSR_TLBVADDR: csr_read_data_x = tlbvaddr; |
| `LM32_CSR_TLBBADVADDR: csr_read_data_x = tlbbadvaddr; |
| `endif |
| |
| default: csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}}; |
| endcase |
| end |
| |
| ///////////////////////////////////////////////////// |
| // Sequential Logic |
| ///////////////////////////////////////////////////// |
| |
| `ifdef CFG_MMU_ENABLED |
| // Processor status word (PSW) handling |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i) |
| begin |
| itlbe <= `FALSE; |
| eitlbe <= `FALSE; |
| dtlbe <= `FALSE; |
| edtlbe <= `FALSE; |
| usr <= `FALSE; |
| eusr <= `FALSE; |
| `ifdef CFG_DEBUG_ENABLED |
| bitlbe <= `FALSE; |
| bdtlbe <= `FALSE; |
| busr <= `FALSE; |
| `endif |
| end |
| else |
| begin |
| `ifdef CFG_DEBUG_ENABLED |
| if (non_debug_exception_q_w == `TRUE) |
| begin |
| // Save and then clear ITLB and DTLB enable |
| eitlbe <= itlbe; |
| itlbe <= `FALSE; |
| edtlbe <= dtlbe; |
| dtlbe <= `FALSE; |
| eusr <= usr; |
| usr <= `FALSE; |
| end |
| else if (debug_exception_q_w == `TRUE) |
| begin |
| // Save and then clear TLB enable |
| bitlbe <= itlbe; |
| itlbe <= `FALSE; |
| bdtlbe <= dtlbe; |
| dtlbe <= `FALSE; |
| busr <= usr; |
| usr <= `FALSE; |
| end |
| `else |
| if (exception_q_w == `TRUE) |
| begin |
| // Save and then clear ITLB and DTLB enable |
| eitlbe <= itlbe; |
| itlbe <= `FALSE; |
| edtlbe <= dtlbe; |
| dtlbe <= `FALSE; |
| eusr <= usr; |
| usr <= `FALSE; |
| end |
| `endif |
| |
| else if (stall_x == `FALSE) |
| begin |
| if (eret_k_q_x == `TRUE) |
| begin |
| // Restore ITLB and DTLB enable |
| itlbe <= eitlbe; |
| dtlbe <= edtlbe; |
| usr <= eusr; |
| end |
| `ifdef CFG_DEBUG_ENABLED |
| else if (bret_k_q_x == `TRUE) |
| begin |
| // Restore ITLB and DTLB enable |
| itlbe <= bitlbe; |
| dtlbe <= bdtlbe; |
| usr <= busr; |
| end |
| `endif |
| else if (csr_write_enable_k_q_x == `TRUE) |
| begin |
| // Handle wcsr write |
| if (csr_x == `LM32_CSR_PSW) |
| begin |
| // ie, eie and bie are shadowed from IE register |
| itlbe <= operand_1_x[3]; |
| eitlbe <= operand_1_x[4]; |
| dtlbe <= operand_1_x[6]; |
| edtlbe <= operand_1_x[7]; |
| usr <= operand_1_x[9]; |
| eusr <= operand_1_x[10]; |
| `ifdef CFG_DEBUG_ENABLED |
| bitlbe <= operand_1_x[5]; |
| bdtlbe <= operand_1_x[8]; |
| busr <= operand_1_x[11]; |
| `endif |
| end |
| end |
| end |
| end |
| end |
| |
| // TLBVADDR CSR |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| itlb_flush <= `FALSE; |
| itlb_invalidate <= `FALSE; |
| dtlb_flush <= `FALSE; |
| dtlb_invalidate <= `FALSE; |
| tlbvaddr <= {`LM32_WORD_WIDTH{1'b0}}; |
| end |
| else |
| begin |
| itlb_flush <= `FALSE; |
| itlb_invalidate <= `FALSE; |
| dtlb_flush <= `FALSE; |
| dtlb_invalidate <= `FALSE; |
| if (stall_x == `FALSE) |
| begin |
| if (dtlb_exception == `TRUE) |
| tlbvaddr <= {dtlb_miss_vfn[`LM32_WORD_WIDTH-1:1], 1'b1}; |
| else if (itlb_exception == `TRUE) |
| tlbvaddr <= {itlb_miss_vfn[`LM32_WORD_WIDTH-1:1], 1'b0}; |
| else if ((csr_write_enable_k_q_x == `TRUE) && (csr_x == `LM32_CSR_TLBVADDR)) |
| begin |
| tlbvaddr <= operand_1_x; |
| if (operand_1_x[0] == 1'b0) |
| begin |
| case (operand_1_x[`LM32_TLB_OP_RNG]) |
| `LM32_TLB_OP_FLUSH: itlb_flush <= `TRUE; |
| `LM32_TLB_OP_INVALIDATE: itlb_invalidate <= `TRUE; |
| endcase |
| end |
| if (operand_1_x[0] == 1'b1) |
| begin |
| case (operand_1_x[`LM32_TLB_OP_RNG]) |
| `LM32_TLB_OP_FLUSH: dtlb_flush <= `TRUE; |
| `LM32_TLB_OP_INVALIDATE: dtlb_invalidate <= `TRUE; |
| endcase |
| end |
| end |
| end |
| end |
| end |
| |
| // TLBPADDR CSR |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| itlb_update <= `FALSE; |
| dtlb_update <= `FALSE; |
| tlbpaddr <= {`LM32_WORD_WIDTH{1'b0}}; |
| end |
| else |
| begin |
| itlb_update <= `FALSE; |
| dtlb_update <= `FALSE; |
| if ((csr_write_enable_k_q_x == `TRUE) && (csr_x == `LM32_CSR_TLBPADDR) && (stall_x == `FALSE)) |
| begin |
| /* updates take change in the M stage */ |
| tlbpaddr <= operand_1_x; |
| if (operand_1_x[0] == 1'b0) |
| itlb_update <= `TRUE; |
| if (operand_1_x[0] == 1'b1) |
| dtlb_update <= `TRUE; |
| end |
| end |
| end |
| |
| // TLBBADVADDR CSR |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| tlbbadvaddr <= {`LM32_WORD_WIDTH{1'b0}}; |
| else |
| begin |
| if (stall_x == `FALSE) |
| begin |
| if (dtlb_exception == `TRUE) |
| tlbbadvaddr <= adder_result_x; |
| else if (itlb_exception == `TRUE) |
| tlbbadvaddr <= {pc_x, {`LM32_WORD_WIDTH-`LM32_PC_WIDTH{1'b0}}}; |
| end |
| end |
| end |
| `endif |
| |
| // Exception Base Address (EBA) CSR |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| eba <= eba_reset[`LM32_EBA_RNG]; |
| else |
| begin |
| if ((csr_write_enable_k_q_x == `TRUE) && (csr_x == `LM32_CSR_EBA) && (stall_x == `FALSE)) |
| eba <= operand_1_x[`LM32_EBA_RNG]; |
| `ifdef CFG_HW_DEBUG_ENABLED |
| if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_EBA)) |
| eba <= jtag_csr_write_data[`LM32_EBA_RNG]; |
| `endif |
| end |
| end |
| |
| `ifdef CFG_DEBUG_ENABLED |
| // Debug Exception Base Address (DEBA) CSR |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| deba <= deba_reset[`LM32_EBA_RNG]; |
| else |
| begin |
| if ((csr_write_enable_k_q_x == `TRUE) && (csr_x == `LM32_CSR_DEBA) && (stall_x == `FALSE)) |
| deba <= operand_1_x[`LM32_EBA_RNG]; |
| `ifdef CFG_HW_DEBUG_ENABLED |
| if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_DEBA)) |
| deba <= jtag_csr_write_data[`LM32_EBA_RNG]; |
| `endif |
| end |
| end |
| `endif |
| |
| // Cycle Counter (CC) CSR |
| `ifdef CFG_CYCLE_COUNTER_ENABLED |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| cc <= {`LM32_WORD_WIDTH{1'b0}}; |
| else |
| cc <= cc + 1'b1; |
| end |
| `endif |
| |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| // Watch for data bus errors |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| data_bus_error_seen <= `FALSE; |
| else |
| begin |
| // Set flag when bus error is detected |
| if ((D_ERR_I == `TRUE) && (D_CYC_O == `TRUE)) |
| data_bus_error_seen <= `TRUE; |
| // Clear flag when exception is taken |
| if ((exception_m == `TRUE) && (kill_m == `FALSE)) |
| data_bus_error_seen <= `FALSE; |
| end |
| end |
| `endif |
| |
| `ifdef CFG_EXTERNAL_BREAK_ENABLED |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| ext_break_r <= `FALSE; |
| else |
| begin |
| if (ext_break == `TRUE) |
| ext_break_r <= `TRUE; |
| if (debug_exception_q_w == `TRUE) |
| ext_break_r <= `FALSE; |
| end |
| end |
| `endif |
| |
| // Valid bits to indicate whether an instruction in a partcular pipeline stage is valid or not |
| |
| `ifdef CFG_ICACHE_ENABLED |
| `ifdef CFG_DCACHE_ENABLED |
| always @(*) |
| begin |
| if ( (icache_refill_request == `TRUE) |
| || (dcache_refill_request == `TRUE) |
| ) |
| valid_a = `FALSE; |
| else if ( (icache_restart_request == `TRUE) |
| || (dcache_restart_request == `TRUE) |
| ) |
| valid_a = `TRUE; |
| else |
| valid_a = !icache_refilling && !dcache_refilling; |
| end |
| `else |
| always @(*) |
| begin |
| if (icache_refill_request == `TRUE) |
| valid_a = `FALSE; |
| else if (icache_restart_request == `TRUE) |
| valid_a = `TRUE; |
| else |
| valid_a = !icache_refilling; |
| end |
| `endif |
| `else |
| `ifdef CFG_DCACHE_ENABLED |
| always @(*) |
| begin |
| if (dcache_refill_request == `TRUE) |
| valid_a = `FALSE; |
| else if (dcache_restart_request == `TRUE) |
| valid_a = `TRUE; |
| else |
| valid_a = !dcache_refilling; |
| end |
| `endif |
| `endif |
| |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| valid_f <= `FALSE; |
| valid_d <= `FALSE; |
| valid_x <= `FALSE; |
| valid_m <= `FALSE; |
| valid_w <= `FALSE; |
| end |
| else |
| begin |
| if ((kill_f == `TRUE) || (stall_a == `FALSE)) |
| `ifdef LM32_CACHE_ENABLED |
| valid_f <= valid_a; |
| `else |
| valid_f <= `TRUE; |
| `endif |
| else if (stall_f == `FALSE) |
| valid_f <= `FALSE; |
| |
| if (kill_d == `TRUE) |
| valid_d <= `FALSE; |
| else if (stall_f == `FALSE) |
| valid_d <= valid_f & !kill_f; |
| else if (stall_d == `FALSE) |
| valid_d <= `FALSE; |
| |
| if (stall_d == `FALSE) |
| valid_x <= valid_d & !kill_d; |
| else if (kill_x == `TRUE) |
| valid_x <= `FALSE; |
| else if (stall_x == `FALSE) |
| valid_x <= `FALSE; |
| |
| if (kill_m == `TRUE) |
| valid_m <= `FALSE; |
| else if (stall_x == `FALSE) |
| valid_m <= valid_x & !kill_x; |
| else if (stall_m == `FALSE) |
| valid_m <= `FALSE; |
| |
| if (stall_m == `FALSE) |
| valid_w <= valid_m & !kill_m; |
| else |
| valid_w <= `FALSE; |
| end |
| end |
| |
| // Microcode pipeline registers |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| `ifdef CFG_USER_ENABLED |
| user_opcode <= {`LM32_USER_OPCODE_WIDTH{1'b0}}; |
| `endif |
| operand_0_x <= {`LM32_WORD_WIDTH{1'b0}}; |
| operand_1_x <= {`LM32_WORD_WIDTH{1'b0}}; |
| store_operand_x <= {`LM32_WORD_WIDTH{1'b0}}; |
| branch_target_x <= {`LM32_PC_WIDTH{1'b0}}; |
| x_result_sel_csr_x <= `FALSE; |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| x_result_sel_mc_arith_x <= `FALSE; |
| `endif |
| `ifdef LM32_NO_BARREL_SHIFT |
| x_result_sel_shift_x <= `FALSE; |
| `endif |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| x_result_sel_sext_x <= `FALSE; |
| `endif |
| x_result_sel_logic_x <= `FALSE; |
| `ifdef CFG_USER_ENABLED |
| x_result_sel_user_x <= `FALSE; |
| `endif |
| x_result_sel_add_x <= `FALSE; |
| m_result_sel_compare_x <= `FALSE; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| m_result_sel_shift_x <= `FALSE; |
| `endif |
| w_result_sel_load_x <= `FALSE; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_x <= `FALSE; |
| `endif |
| x_bypass_enable_x <= `FALSE; |
| m_bypass_enable_x <= `FALSE; |
| write_enable_x <= `FALSE; |
| write_idx_x <= {`LM32_REG_IDX_WIDTH{1'b0}}; |
| csr_x <= {`LM32_CSR_WIDTH{1'b0}}; |
| load_x <= `FALSE; |
| store_x <= `FALSE; |
| size_x <= {`LM32_SIZE_WIDTH{1'b0}}; |
| sign_extend_x <= `FALSE; |
| adder_op_x <= `FALSE; |
| adder_op_x_n <= `FALSE; |
| logic_op_x <= 4'h0; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| direction_x <= `FALSE; |
| `endif |
| branch_x <= `FALSE; |
| branch_predict_x <= `FALSE; |
| branch_predict_taken_x <= `FALSE; |
| condition_x <= `LM32_CONDITION_U1; |
| `ifdef CFG_DEBUG_ENABLED |
| break_x <= `FALSE; |
| `endif |
| scall_x <= `FALSE; |
| eret_x <= `FALSE; |
| `ifdef CFG_DEBUG_ENABLED |
| bret_x <= `FALSE; |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_x <= `FALSE; |
| data_bus_error_exception_m <= `FALSE; |
| `endif |
| csr_write_enable_x <= `FALSE; |
| operand_m <= {`LM32_WORD_WIDTH{1'b0}}; |
| branch_target_m <= {`LM32_PC_WIDTH{1'b0}}; |
| m_result_sel_compare_m <= `FALSE; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| m_result_sel_shift_m <= `FALSE; |
| `endif |
| w_result_sel_load_m <= `FALSE; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_m <= `FALSE; |
| `endif |
| m_bypass_enable_m <= `FALSE; |
| branch_m <= `FALSE; |
| branch_predict_m <= `FALSE; |
| branch_predict_taken_m <= `FALSE; |
| exception_m <= `FALSE; |
| load_m <= `FALSE; |
| store_m <= `FALSE; |
| write_enable_m <= `FALSE; |
| write_idx_m <= {`LM32_REG_IDX_WIDTH{1'b0}}; |
| condition_met_m <= `FALSE; |
| `ifdef CFG_DCACHE_ENABLED |
| dflush_m <= `FALSE; |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| debug_exception_m <= `FALSE; |
| non_debug_exception_m <= `FALSE; |
| `endif |
| operand_w <= {`LM32_WORD_WIDTH{1'b0}}; |
| w_result_sel_load_w <= `FALSE; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_w <= `FALSE; |
| `endif |
| write_idx_w <= {`LM32_REG_IDX_WIDTH{1'b0}}; |
| write_enable_w <= `FALSE; |
| `ifdef CFG_DEBUG_ENABLED |
| debug_exception_w <= `FALSE; |
| non_debug_exception_w <= `FALSE; |
| `else |
| exception_w <= `FALSE; |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| memop_pc_w <= {`LM32_PC_WIDTH{1'b0}}; |
| `endif |
| end |
| else |
| begin |
| // D/X stage registers |
| |
| if (stall_x == `FALSE) |
| begin |
| `ifdef CFG_USER_ENABLED |
| user_opcode <= user_opcode_d; |
| `endif |
| operand_0_x <= d_result_0; |
| operand_1_x <= d_result_1; |
| store_operand_x <= bypass_data_1; |
| branch_target_x <= branch_reg_d == `TRUE ? bypass_data_0[`LM32_PC_RNG] : branch_target_d; |
| x_result_sel_csr_x <= x_result_sel_csr_d; |
| `ifdef LM32_MC_ARITHMETIC_ENABLED |
| x_result_sel_mc_arith_x <= x_result_sel_mc_arith_d; |
| `endif |
| `ifdef LM32_NO_BARREL_SHIFT |
| x_result_sel_shift_x <= x_result_sel_shift_d; |
| `endif |
| `ifdef CFG_SIGN_EXTEND_ENABLED |
| x_result_sel_sext_x <= x_result_sel_sext_d; |
| `endif |
| x_result_sel_logic_x <= x_result_sel_logic_d; |
| `ifdef CFG_USER_ENABLED |
| x_result_sel_user_x <= x_result_sel_user_d; |
| `endif |
| x_result_sel_add_x <= x_result_sel_add_d; |
| m_result_sel_compare_x <= m_result_sel_compare_d; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| m_result_sel_shift_x <= m_result_sel_shift_d; |
| `endif |
| w_result_sel_load_x <= w_result_sel_load_d; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_x <= w_result_sel_mul_d; |
| `endif |
| x_bypass_enable_x <= x_bypass_enable_d; |
| m_bypass_enable_x <= m_bypass_enable_d; |
| load_x <= load_d; |
| store_x <= store_d; |
| branch_x <= branch_d; |
| branch_predict_x <= branch_predict_d; |
| branch_predict_taken_x <= branch_predict_taken_d; |
| write_idx_x <= write_idx_d; |
| csr_x <= csr_d; |
| size_x <= size_d; |
| sign_extend_x <= sign_extend_d; |
| adder_op_x <= adder_op_d; |
| adder_op_x_n <= ~adder_op_d; |
| logic_op_x <= logic_op_d; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| direction_x <= direction_d; |
| `endif |
| condition_x <= condition_d; |
| csr_write_enable_x <= csr_write_enable_d; |
| `ifdef CFG_DEBUG_ENABLED |
| break_x <= break_d; |
| `endif |
| scall_x <= scall_d; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| bus_error_x <= bus_error_d; |
| `endif |
| eret_x <= eret_d; |
| `ifdef CFG_DEBUG_ENABLED |
| bret_x <= bret_d; |
| `endif |
| write_enable_x <= write_enable_d; |
| end |
| |
| // X/M stage registers |
| |
| if (stall_m == `FALSE) |
| begin |
| operand_m <= x_result; |
| m_result_sel_compare_m <= m_result_sel_compare_x; |
| `ifdef CFG_PL_BARREL_SHIFT_ENABLED |
| m_result_sel_shift_m <= m_result_sel_shift_x; |
| `endif |
| if (exception_x == `TRUE) |
| begin |
| w_result_sel_load_m <= `FALSE; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_m <= `FALSE; |
| `endif |
| end |
| else |
| begin |
| w_result_sel_load_m <= w_result_sel_load_x; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_m <= w_result_sel_mul_x; |
| `endif |
| end |
| m_bypass_enable_m <= m_bypass_enable_x; |
| load_m <= load_x; |
| store_m <= store_x; |
| `ifdef CFG_FAST_UNCONDITIONAL_BRANCH |
| branch_m <= branch_x && !branch_taken_x; |
| `else |
| branch_m <= branch_x; |
| branch_predict_m <= branch_predict_x; |
| branch_predict_taken_m <= branch_predict_taken_x; |
| `endif |
| `ifdef CFG_DEBUG_ENABLED |
| // Data bus errors are generated by the wishbone and are |
| // made known to the processor only in next cycle (as a |
| // non-debug exception). A break instruction can be seen |
| // in same cycle (causing a debug exception). Handle non |
| // -debug exception first! |
| if (non_debug_exception_x == `TRUE) |
| write_idx_m <= `LM32_EA_REG; |
| else if (debug_exception_x == `TRUE) |
| write_idx_m <= `LM32_BA_REG; |
| else |
| write_idx_m <= write_idx_x; |
| `else |
| if (exception_x == `TRUE) |
| write_idx_m <= `LM32_EA_REG; |
| else |
| write_idx_m <= write_idx_x; |
| `endif |
| condition_met_m <= condition_met_x; |
| `ifdef CFG_DEBUG_ENABLED |
| if (exception_x == `TRUE) |
| if ( (dc_re == `TRUE) |
| `ifdef CFG_ALTERNATE_EBA |
| || (at_debug == `TRUE) |
| `endif |
| || ( (debug_exception_x == `TRUE) |
| && (non_debug_exception_x == `FALSE)) |
| ) |
| branch_target_m <= {deba, eid_x, {3{1'b0}}}; |
| else |
| branch_target_m <= {eba, eid_x, {3{1'b0}}}; |
| else |
| branch_target_m <= branch_target_x; |
| `else |
| branch_target_m <= exception_x == `TRUE ? {eba, eid_x, {3{1'b0}}} : branch_target_x; |
| `endif |
| `ifdef CFG_TRACE_ENABLED |
| eid_m <= eid_x; |
| `endif |
| `ifdef CFG_DCACHE_ENABLED |
| dflush_m <= dflush_x; |
| `endif |
| eret_m <= eret_k_q_x; |
| `ifdef CFG_DEBUG_ENABLED |
| bret_m <= bret_k_q_x; |
| `endif |
| write_enable_m <= exception_x == `TRUE ? `TRUE : write_enable_x; |
| `ifdef CFG_DEBUG_ENABLED |
| debug_exception_m <= debug_exception_x; |
| non_debug_exception_m <= non_debug_exception_x; |
| `endif |
| end |
| |
| // State changing regs |
| if (stall_m == `FALSE) |
| begin |
| if ((exception_x == `TRUE) && (q_x == `TRUE) && (stall_x == `FALSE)) |
| exception_m <= `TRUE; |
| else |
| exception_m <= `FALSE; |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| data_bus_error_exception_m <= (data_bus_error_exception == `TRUE) |
| `ifdef CFG_DEBUG_ENABLED |
| `ifdef CFG_JTAG_ENABLED |
| && (reset_exception == `FALSE) |
| `endif |
| `endif |
| ; |
| `endif |
| end |
| |
| // M/W stage registers |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| operand_w <= exception_m == `TRUE ? (data_bus_error_exception_m ? {memop_pc_w, 2'b00} : {pc_m, 2'b00}) : m_result; |
| `else |
| operand_w <= exception_m == `TRUE ? {pc_m, 2'b00} : m_result; |
| `endif |
| w_result_sel_load_w <= w_result_sel_load_m; |
| `ifdef CFG_PL_MULTIPLY_ENABLED |
| w_result_sel_mul_w <= w_result_sel_mul_m; |
| `endif |
| write_idx_w <= write_idx_m; |
| `ifdef CFG_TRACE_ENABLED |
| eid_w <= eid_m; |
| eret_w <= eret_m; |
| `ifdef CFG_DEBUG_ENABLED |
| bret_w <= bret_m; |
| `endif |
| `endif |
| write_enable_w <= write_enable_m; |
| `ifdef CFG_DEBUG_ENABLED |
| debug_exception_w <= debug_exception_m; |
| non_debug_exception_w <= non_debug_exception_m; |
| `else |
| exception_w <= exception_m; |
| `endif |
| `ifdef CFG_BUS_ERRORS_ENABLED |
| if ( (stall_m == `FALSE) |
| && (data_bus_error_exception == `FALSE) |
| && ( (load_q_m == `TRUE) |
| || (store_q_m == `TRUE) |
| ) |
| ) |
| memop_pc_w <= pc_m; |
| `endif |
| end |
| end |
| |
| `ifdef CFG_EBR_POSEDGE_REGISTER_FILE |
| // Buffer data read from register file, in case a stall occurs, and watch for |
| // any writes to the modified registers |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| use_buf <= `FALSE; |
| reg_data_buf_0 <= {`LM32_WORD_WIDTH{1'b0}}; |
| reg_data_buf_1 <= {`LM32_WORD_WIDTH{1'b0}}; |
| end |
| else |
| begin |
| if (stall_d == `FALSE) |
| use_buf <= `FALSE; |
| else if (use_buf == `FALSE) |
| begin |
| reg_data_buf_0 <= reg_data_live_0; |
| reg_data_buf_1 <= reg_data_live_1; |
| use_buf <= `TRUE; |
| end |
| if (reg_write_enable_q_w == `TRUE) |
| begin |
| if (write_idx_w == read_idx_0_d) |
| reg_data_buf_0 <= w_result; |
| if (write_idx_w == read_idx_1_d) |
| reg_data_buf_1 <= w_result; |
| end |
| end |
| end |
| `endif |
| |
| `ifdef LM32_EBR_REGISTER_FILE |
| `else |
| // Register file write port |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| begin |
| if (reg_write_enable_q_w == `TRUE) |
| registers[write_idx_w] <= w_result; |
| end |
| end |
| `endif |
| |
| `ifdef CFG_TRACE_ENABLED |
| // PC tracing logic |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| trace_pc_valid <= `FALSE; |
| trace_pc <= {`LM32_PC_WIDTH{1'b0}}; |
| trace_exception <= `FALSE; |
| trace_eid <= `LM32_EID_RESET; |
| trace_eret <= `FALSE; |
| `ifdef CFG_DEBUG_ENABLED |
| trace_bret <= `FALSE; |
| `endif |
| pc_c <= eba_reset/4; |
| end |
| else |
| begin |
| trace_pc_valid <= `FALSE; |
| // Has an exception occured |
| `ifdef CFG_DEBUG_ENABLED |
| if ((debug_exception_q_w == `TRUE) || (non_debug_exception_q_w == `TRUE)) |
| `else |
| if (exception_q_w == `TRUE) |
| `endif |
| begin |
| trace_exception <= `TRUE; |
| trace_pc_valid <= `TRUE; |
| trace_pc <= pc_w; |
| trace_eid <= eid_w; |
| end |
| else |
| trace_exception <= `FALSE; |
| |
| if ((valid_w == `TRUE) && (!kill_w)) |
| begin |
| // An instruction is commiting. Determine if it is non-sequential |
| if (pc_c + 1'b1 != pc_w) |
| begin |
| // Non-sequential instruction |
| trace_pc_valid <= `TRUE; |
| trace_pc <= pc_w; |
| end |
| // Record PC so we can determine if next instruction is sequential or not |
| pc_c <= pc_w; |
| // Indicate if it was an eret/bret instruction |
| trace_eret <= eret_w; |
| `ifdef CFG_DEBUG_ENABLED |
| trace_bret <= bret_w; |
| `endif |
| end |
| else |
| begin |
| trace_eret <= `FALSE; |
| `ifdef CFG_DEBUG_ENABLED |
| trace_bret <= `FALSE; |
| `endif |
| end |
| end |
| end |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Behavioural Logic |
| ///////////////////////////////////////////////////// |
| |
| // synthesis translate_off |
| |
| // Reset register 0. Only needed for simulation. |
| initial |
| begin |
| `ifdef LM32_EBR_REGISTER_FILE |
| reg_0.mem[0] = {`LM32_WORD_WIDTH{1'b0}}; |
| reg_1.mem[0] = {`LM32_WORD_WIDTH{1'b0}}; |
| `else |
| registers[0] = {`LM32_WORD_WIDTH{1'b0}}; |
| `endif |
| end |
| |
| // synthesis translate_on |
| |
| endmodule |