OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [src_processor/] [lm32/] [verilog/] [src/] [lm32_cpu.v] - Rev 17

Go to most recent revision | Compare with Previous | Blame | View Log

// =============================================================================
//                           COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation        TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court                            408-826-6000 (other locations)
// Hillsboro, OR 97124                     web  : http://www.latticesemi.com/
// U.S.A                                   email: techsupport@latticesemi.com
// =============================================================================/
//                         FILE DETAILS
// Project          : LatticeMico32
// File             : lm32_cpu.v
// Title            : Top-level of CPU.
// Dependencies     : lm32_include.v
// Version          : 6.1.17
// =============================================================================
 
`include "lm32_include.v"
 
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
 
module lm32_cpu (
    // ----- Inputs -------
    clk_i,
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
    clk_n_i,
`endif    
    rst_i,
    // From external devices
`ifdef CFG_INTERRUPTS_ENABLED
    interrupt_n,
`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_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 = 4'h0;
`endif
`ifdef CFG_ROM_DEBUG_ENABLED
parameter breakpoints = `CFG_BREAKPOINTS;                       // Number of h/w breakpoint CSRs
`else
parameter breakpoints = 4'h0;
`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_INTERRUPTS_ENABLED
input [`LM32_INTERRUPT_RNG] interrupt_n;        // Interrupt pins, active-low
`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
 
/////////////////////////////////////////////////////
// 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 [`LM32_WORD_RNG] immediate_d;              // Immediate operand
wire load_d;                                    // Indicates a load instruction
reg load_x;                                     
reg load_m;
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
reg branch_x;                                   
reg branch_m;
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;
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;
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_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;
`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
wire [`LM32_WORD_RNG] reg_data_live_0;          
wire [`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
`ifdef CFG_ROTATE_ENABLED
wire rotate_d;                                  // Whether we should rotate or shift
reg rotate_x;                                    
`endif
wire direction_d;                               // Which direction to shift in
reg direction_x;                                        
reg direction_m;
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
`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
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
 
// 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_PC_WIDTH+2-1:8] eba;                 // Exception Base Address (EBA) CSR
`ifdef CFG_DEBUG_ENABLED
reg [`LM32_PC_WIDTH+2-1:8] 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
 
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`define  INCLUDE_FUNCTION
`include "lm32_functions.v"
 
/////////////////////////////////////////////////////
// Instantiations
///////////////////////////////////////////////////// 
 
// Instruction unit
lm32_instruction_unit #(
    .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),
    // 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),
    .kill_f                 (kill_f),
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH    
    .branch_taken_x         (branch_taken_x),
    .branch_target_x        (branch_target_x),
`endif
    .branch_taken_m         (branch_taken_m),
    .branch_target_m        (branch_target_m),
`ifdef CFG_ICACHE_ENABLED
    .iflush                 (iflush),
`endif
`ifdef CFG_DCACHE_ENABLED
    .dcache_restart_request (dcache_restart_request),
    .dcache_refill_request  (dcache_refill_request),
    .dcache_refilling       (dcache_refilling),
`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),
    .i_rty_i                (I_RTY_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_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)
    );
 
// Trace instructions in simulation
lm32_simtrace simtrace (
    .clk_i                  (clk_i),
    .rst_i                  (rst_i),
    .stall_x                (stall_x),
    .stall_m                (stall_m),
    .valid_w                (valid_w),
    .kill_w                 (kill_w),
    .instruction_d          (instruction_d),
    .pc_w                   (pc_w)
    );
 
// 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),
    .branch_reg             (branch_reg_d),
    .condition              (condition_d),
`ifdef CFG_DEBUG_ENABLED
    .break                  (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)
    ); 
wire load_q_x,load_q_m,store_q_m;
 
// 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_x                 (kill_x),
    .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]),
    .load_q_x               (load_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
    // 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    
    .load_data_w            (load_data_w),
    .stall_wb_load          (stall_wb_load),
    // 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 (
    // ----- Inputs -------
    .clk_i                  (clk_i), 
    .rst_i                  (rst_i),
    // From external devices
    .interrupt_n            (interrupt_n),
    // 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_q_x),
`ifdef CFG_DEBUG_ENABLED
    .bret_q_x               (bret_q_x),
`endif
    .csr                    (csr_x),
    .csr_write_data         (operand_1_x),
    .csr_write_enable       (csr_write_enable_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_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_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_q_x),
    .bret_q_x               (bret_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
 
lm32_ram #(
    // ----- Parameters -------
    .data_width             (`LM32_WORD_WIDTH),
    .address_width          (`LM32_REG_IDX_WIDTH)    
  ) reg_0 (
    // ----- Inputs -------
    .read_clk               (clk_i), 
    .write_clk              (clk_i), 
    .reset                  (rst_i),
    .enable_read            (stall_d == `FALSE),
    .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              (reg_data_live_0)
    );
 
lm32_ram #(
    // ----- Parameters -------
    .data_width             (`LM32_WORD_WIDTH),
    .address_width          (`LM32_REG_IDX_WIDTH)    
  ) reg_1 (
    // ----- Inputs -------
    .read_clk               (clk_i), 
    .write_clk              (clk_i), 
    .reset                  (rst_i),
    .enable_read            (stall_d == `FALSE),
    .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              (reg_data_live_1)
    );
 
`endif
 
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
 
lm32_ram #(
    // ----- Parameters -------
    .data_width             (`LM32_WORD_WIDTH),
    .address_width          (`LM32_REG_IDX_WIDTH)    
  ) reg_0 (
    // ----- Inputs -------
    .read_clk               (clk_n_i), 
    .write_clk              (clk_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 #(
    // ----- Parameters -------
    .data_width             (`LM32_WORD_WIDTH),
    .address_width          (`LM32_REG_IDX_WIDTH)    
  ) reg_1 (
    // ----- Inputs -------
    .read_clk               (clk_n_i), 
    .write_clk              (clk_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
 
// 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)
                             ); 
`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) 
                                  && (condition_met_m == `TRUE) 
                                  && (valid_m == `TRUE)
                                 ) 
                              || (exception_m == `TRUE)
                             );
 
// Generate signal that will kill instructions in each pipeline stage when necessary
assign kill_f =    (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
                ;
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
                ;
assign kill_x =    (branch_taken_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)
`ifdef CFG_JTAG_ENABLED
                              || (jtag_break == `TRUE)
`endif
                              ;
assign watchpoint_exception = wp_match == `TRUE;
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
assign instruction_bus_error_exception = bus_error_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_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                            
                               )
`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                            
                               )
`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     
         if (breakpoint_exception == `TRUE)
        eid_x = `LM32_EID_BREAKPOINT;
    else
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
         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_BUS_ERRORS_ENABLED
         if (data_bus_error_exception == `TRUE)
        eid_x = `LM32_EID_DATA_BUS_ERROR;
    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
        eid_x = `LM32_EID_SCALL;
end
 
// Stall generation
 
assign stall_a = (stall_f == `TRUE);
 
assign stall_f = (stall_d == `TRUE);
 
assign stall_d =   (stall_x == `TRUE) 
                || (   (interlock == `TRUE)
                    && (kill_d == `FALSE)
                   ) 
                || (   (eret_d == `TRUE)
                    && (load_q_x == `TRUE)
                   )
`ifdef CFG_DEBUG_ENABLED
                || (   (bret_d == `TRUE)
                    && (load_q_x == `TRUE)
                   )
`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
                 ;
 
assign stall_m =    (stall_wb_load == `TRUE)
`ifdef CFG_SIZE_OVER_SPEED
                 || (D_CYC_O == `TRUE)
`else
                 || (   (D_CYC_O == `TRUE)
                     && (   (store_m == `TRUE)
                         || (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
                 ;      
 
// Qualify state changing control signals
`ifdef LM32_MC_ARITHMETIC_ENABLED
wire   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
wire   q_x = (valid_x == `TRUE) && (kill_x == `FALSE);
assign csr_write_enable_q_x = (csr_write_enable_x == `TRUE) && (q_x == `TRUE);
assign eret_q_x = (eret_x == `TRUE) && (q_x == `TRUE);
`ifdef CFG_DEBUG_ENABLED
assign bret_q_x = (bret_x == `TRUE) && (q_x == `TRUE);
`endif
assign load_q_x = (load_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                              
wire   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);
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);
 
// 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
              };
 
// 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);
`endif 
`ifdef CFG_DCACHE_ENABLED
assign dflush_x =  (csr_write_enable_q_x == `TRUE) 
                && (csr_x == `LM32_CSR_DCC);
`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, 8'h00};
`ifdef CFG_DEBUG_ENABLED
    `LM32_CSR_DEBA: csr_read_data_x = {deba, 8'h00};
`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
    default:        csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}};
    endcase
end
 
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
 
// Exception Base Address (EBA) CSR
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
        eba <= eba_reset[`LM32_PC_WIDTH+2-1:8];
    else
    begin
        if ((csr_write_enable_q_x == `TRUE) && (csr_x == `LM32_CSR_EBA) && (stall_x == `FALSE))
            eba <= operand_1_x[`LM32_PC_WIDTH+2-1:8];
`ifdef CFG_HW_DEBUG_ENABLED
        if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_EBA))
            eba <= jtag_csr_write_data[`LM32_PC_WIDTH+2-1:8];
`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_PC_WIDTH+2-1:8];
    else
    begin
        if ((csr_write_enable_q_x == `TRUE) && (csr_x == `LM32_CSR_DEBA) && (stall_x == `FALSE))
            deba <= operand_1_x[`LM32_PC_WIDTH+2-1:8];
`ifdef CFG_HW_DEBUG_ENABLED
        if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_DEBA))
            deba <= jtag_csr_write_data[`LM32_PC_WIDTH+2-1:8];
`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
 
// 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 (kill_x == `TRUE)
            valid_x <= `FALSE;
        else if (stall_d == `FALSE)
            valid_x <= valid_d & !kill_d;
        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_WORD_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
`ifdef CFG_ROTATE_ENABLED
        rotate_x <= `FALSE;
 
`endif
        branch_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;
`endif
        csr_write_enable_x <= `FALSE;
        operand_m <= {`LM32_WORD_WIDTH{1'b0}};
        branch_target_m <= {`LM32_WORD_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;
        exception_m <= `FALSE;
        load_m <= `FALSE;
        store_m <= `FALSE;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
        direction_m <= `FALSE;
`endif
        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
    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] : pc_d + branch_offset_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;
            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
`ifdef CFG_ROTATE_ENABLED
            rotate_x <= rotate_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;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
            direction_m <= direction_x;
`endif
            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;
`endif
`ifdef CFG_DEBUG_ENABLED
            if (debug_exception_x == `TRUE) 
                write_idx_m <= `LM32_BA_REG;
            else if (non_debug_exception_x == `TRUE)
                write_idx_m <= `LM32_EA_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
            branch_target_m <= exception_x == `TRUE ? {(debug_exception_x == `TRUE) || (dc_re == `TRUE) ? deba : eba, eid_x, {3{1'b0}}} : 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_q_x;
`ifdef CFG_DEBUG_ENABLED
            bret_m <= bret_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;
        end
 
        // M/W stage registers
 
        operand_w <= exception_m == `TRUE ? {pc_m, 2'b00} : m_result;        
        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
    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
// Adding a reset causes a huge slowdown and requires lots of extra LUTs
always @(posedge clk_i)
begin
    if (reg_write_enable_q_w == `TRUE)
        registers[write_idx_w] <= w_result;
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 <= `CFG_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 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.