diff --git a/doc/cs_registers.rst b/doc/cs_registers.rst index c4edb280..2da4fe36 100644 --- a/doc/cs_registers.rst +++ b/doc/cs_registers.rst @@ -26,6 +26,8 @@ Ibex implements all the Control and Status Registers (CSRs) listed in the follow +---------+--------------------+--------+-----------------------------------------------+ | 0x342 | ``mcause`` | RW | Machine Trap Cause | +---------+--------------------+--------+-----------------------------------------------+ +| 0x343 | ``mtval`` | WARL | Machine Trap Value Register | ++---------+--------------------+--------+-----------------------------------------------+ | 0x7B0 | ``dcsr`` | RW | Debug Control and Status Register | +---------+--------------------+--------+-----------------------------------------------+ | 0x7B1 | ``dpc`` | RW | Debug PC | @@ -117,6 +119,21 @@ Reset Value: ``0x0000_0000`` | 4:0 | R | **Exception Code** | +-------+-----+------------------------------------------------------------------+ +Machine Trap Value (mtval) +-------------------------- + +CSR Address: ``0x343`` + +Reset Value: ``0x0000_0000`` + +When an exception is encountered, this register can hold exception-specific information to assist software in handling the trap. + + * In the case of errors in the load-store unit ``mtval`` holds the address of the transaction causing the error. + * If this transaction is misaligned, ``mtval`` holds the address of the missing transaction part. + * In the case of illegal instruction exceptions, ``mtval`` holds the actual faulting instruction. + +For all other exceptions, ``mtval`` is 0. + .. _csr-mhartid: diff --git a/rtl/ibex_controller.sv b/rtl/ibex_controller.sv index cebd5061..aae04166 100644 --- a/rtl/ibex_controller.sv +++ b/rtl/ibex_controller.sv @@ -45,8 +45,10 @@ module ibex_controller ( input logic csr_status_i, // decoder has CSR status instr // from IF/ID pipeline - input logic instr_valid_i, // instruction coming from IF/ID stage - // is valid + input logic instr_valid_i, // instr from IF-ID reg is valid + input logic [31:0] instr_i, // instr from IF-ID reg, for mtval + input logic [15:0] instr_compressed_i, // instr from IF-ID reg, for mtval + input logic instr_is_compressed_i, // instr from IF-ID reg is compressed // from prefetcher output logic instr_req_o, // start fetching instructions @@ -58,6 +60,7 @@ module ibex_controller ( output ibex_defines::exc_pc_sel_e exc_pc_mux_o, // IF stage selector for exception PC // LSU + input logic [31:0] lsu_addr_last_i, // for mtval input logic load_err_i, input logic store_err_i, @@ -92,10 +95,11 @@ module ibex_controller ( output logic csr_save_if_o, output logic csr_save_id_o, - output ibex_defines::exc_cause_e csr_cause_o, output logic csr_restore_mret_id_o, output logic csr_restore_dret_id_o, output logic csr_save_cause_o, + output ibex_defines::exc_cause_e csr_cause_o, + output logic [31:0] csr_mtval_o, // stall signals output logic halt_if_o, @@ -154,16 +158,14 @@ module ibex_controller ( csr_save_if_o = 1'b0; csr_save_id_o = 1'b0; csr_restore_mret_id_o = 1'b0; - csr_restore_dret_id_o = 1'b0; - csr_save_cause_o = 1'b0; + csr_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00 + csr_mtval_o = '0; exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00 exc_pc_mux_o = EXC_PC_IRQ; - csr_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00 - pc_mux_o = PC_BOOT; pc_set_o = 1'b0; @@ -342,7 +344,7 @@ module ibex_controller ( pc_set_o = 1'b1; exc_pc_mux_o = EXC_PC_DBD; - csr_save_if_o = 1'b1; + csr_save_if_o = 1'b1; debug_csr_save_o = 1'b1; csr_save_cause_o = 1'b1; @@ -433,6 +435,7 @@ module ibex_controller ( end exc_cause_o = EXC_CAUSE_ILLEGAL_INSN; csr_cause_o = EXC_CAUSE_ILLEGAL_INSN; + csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i; end mret_insn_i: begin //mret @@ -492,6 +495,7 @@ module ibex_controller ( exc_pc_mux_o = EXC_PC_LOAD; exc_cause_o = EXC_CAUSE_LOAD_ACCESS_FAULT; csr_cause_o = EXC_CAUSE_LOAD_ACCESS_FAULT; + csr_mtval_o = lsu_addr_last_i; end store_err_q: begin pc_mux_o = PC_EXCEPTION; @@ -501,6 +505,7 @@ module ibex_controller ( exc_pc_mux_o = EXC_PC_STORE; exc_cause_o = EXC_CAUSE_STORE_ACCESS_FAULT; csr_cause_o = EXC_CAUSE_STORE_ACCESS_FAULT; + csr_mtval_o = lsu_addr_last_i; end default:; diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 0b4c2e4f..b50f1fb1 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -109,18 +109,20 @@ module ibex_core #( // IF/ID signals logic instr_valid_id; - logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage - logic is_compressed_id; - logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage - logic illegal_insn_id; // ID stage sees an illegal instruction - logic [31:0] pc_if; // Program counter in IF stage - logic [31:0] pc_id; // Program counter in ID stage + logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage + logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage + logic instr_is_compressed_id; + logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage + logic illegal_insn_id; // ID stage sees an illegal instruction + logic [31:0] pc_if; // Program counter in IF stage + logic [31:0] pc_id; // Program counter in ID stage logic clear_instr_valid; logic pc_set; - pc_sel_e pc_mux_id; // Mux selector for next PC - exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC - exc_cause_e exc_cause; // Exception cause + IRQ ID for vectorized interrupt lines + + pc_sel_e pc_mux_id; // Mux selector for next PC + exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC + exc_cause_e exc_cause; // Exception cause logic lsu_load_err; logic lsu_store_err; @@ -129,7 +131,7 @@ module ibex_core #( logic is_decoding; logic data_misaligned; - logic [31:0] misaligned_addr; + logic [31:0] lsu_addr_last; // Jump and branch target and decision (EX->IF) logic [31:0] jump_target_ex; @@ -147,7 +149,7 @@ module ibex_core #( logic [31:0] alu_operand_a_ex; logic [31:0] alu_operand_b_ex; - logic [31:0] alu_adder_result_ex; // Used to forward computed address to LSU + logic [31:0] alu_adder_result_ex; // Used to forward computed address to LSU logic [31:0] regfile_wdata_ex; // Multiplier Control @@ -167,8 +169,9 @@ module ibex_core #( csr_num_e csr_addr; logic [31:0] csr_rdata; logic [31:0] csr_wdata; - logic illegal_csr_insn_id; // CSR access to non-existent register, - // with wrong priviledge level, or missing write permissions + logic illegal_csr_insn_id; // CSR access to non-existent register, + // with wrong priviledge level, + // or missing write permissions // Data Memory Control logic data_we_ex; @@ -190,18 +193,19 @@ module ibex_core #( logic data_valid_lsu; // Signals between instruction core interface and pipe (if and id stages) - logic instr_req_int; // Id stage asserts a req to instruction core interface + logic instr_req_int; // Id stage asserts a req to instruction core interface // Interrupts logic m_irq_enable; logic [31:0] mepc, depc; - logic csr_save_cause; logic csr_save_if; logic csr_save_id; - exc_cause_e csr_cause; logic csr_restore_mret_id; logic csr_restore_dret_id; + logic csr_save_cause; + exc_cause_e csr_cause; + logic [31:0] csr_mtval; // debug mode and dcsr configuration dbg_cause_e debug_cause; @@ -221,7 +225,6 @@ module ibex_core #( // RISC-V Formal Interface signals `ifdef RVFI logic [31:0] rvfi_insn_opcode; - logic [15:0] compressed_instr; logic rvfi_valid_int; logic [4:0] rvfi_rs1_addr_id; logic [4:0] rvfi_rs2_addr_id; @@ -296,52 +299,50 @@ module ibex_core #( .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) ) if_stage_i ( - .clk_i ( clk ), - .rst_ni ( rst_ni ), + .clk_i ( clk ), + .rst_ni ( rst_ni ), // boot address (trap vector location) - .boot_addr_i ( boot_addr_i ), + .boot_addr_i ( boot_addr_i ), // instruction request control - .req_i ( instr_req_int ), + .req_i ( instr_req_int ), // instruction cache interface - .instr_req_o ( instr_req_o ), - .instr_addr_o ( instr_addr_o ), - .instr_gnt_i ( instr_gnt_i ), - .instr_rvalid_i ( instr_rvalid_i ), - .instr_rdata_i ( instr_rdata_i ), + .instr_req_o ( instr_req_o ), + .instr_addr_o ( instr_addr_o ), + .instr_gnt_i ( instr_gnt_i ), + .instr_rvalid_i ( instr_rvalid_i ), + .instr_rdata_i ( instr_rdata_i ), // outputs to ID stage - .instr_valid_id_o ( instr_valid_id ), - .instr_rdata_id_o ( instr_rdata_id ), - .is_compressed_id_o ( is_compressed_id ), -`ifdef RVFI - .instr_rdata_compressed_o ( compressed_instr ), -`endif - .illegal_c_insn_id_o ( illegal_c_insn_id ), - .pc_if_o ( pc_if ), - .pc_id_o ( pc_id ), + .instr_valid_id_o ( instr_valid_id ), + .instr_rdata_id_o ( instr_rdata_id ), + .instr_rdata_c_id_o ( instr_rdata_c_id ), + .instr_is_compressed_id_o ( instr_is_compressed_id ), + .illegal_c_insn_id_o ( illegal_c_insn_id ), + .pc_if_o ( pc_if ), + .pc_id_o ( pc_id ), // control signals - .clear_instr_valid_i ( clear_instr_valid ), - .pc_set_i ( pc_set ), - .exception_pc_reg_i ( mepc ), // exception return address - .depc_i ( depc ), // debug return address - .pc_mux_i ( pc_mux_id ), // sel for pc multiplexer - .exc_pc_mux_i ( exc_pc_mux_id ), - .exc_vec_pc_mux_i ( exc_cause ), + .clear_instr_valid_i ( clear_instr_valid ), + .pc_set_i ( pc_set ), + .exception_pc_reg_i ( mepc ), // exception return address + .depc_i ( depc ), // debug return address + .pc_mux_i ( pc_mux_id ), // sel for pc multiplexer + .exc_pc_mux_i ( exc_pc_mux_id ), + .exc_vec_pc_mux_i ( exc_cause ), // Jump targets - .jump_target_ex_i ( jump_target_ex ), + .jump_target_ex_i ( jump_target_ex ), // pipeline stalls - .halt_if_i ( halt_if ), - .id_ready_i ( id_ready ), - .if_valid_o ( if_valid ), + .halt_if_i ( halt_if ), + .id_ready_i ( id_ready ), + .if_valid_o ( if_valid ), - .if_busy_o ( if_busy ), - .perf_imiss_o ( perf_imiss ) + .if_busy_o ( if_busy ), + .perf_imiss_o ( perf_imiss ) ); @@ -353,49 +354,50 @@ module ibex_core #( .RV32E ( RV32E ), .RV32M ( RV32M ) ) id_stage_i ( - .clk_i ( clk ), - .rst_ni ( rst_ni ), + .clk_i ( clk ), + .rst_ni ( rst_ni ), - .test_en_i ( test_en_i ), + .test_en_i ( test_en_i ), // Processor Enable - .fetch_enable_i ( fetch_enable_i ), - .ctrl_busy_o ( ctrl_busy ), - .core_ctrl_firstfetch_o ( core_ctrl_firstfetch ), - .is_decoding_o ( is_decoding ), - .illegal_insn_o ( illegal_insn_id ), + .fetch_enable_i ( fetch_enable_i ), + .ctrl_busy_o ( ctrl_busy ), + .core_ctrl_firstfetch_o ( core_ctrl_firstfetch ), + .is_decoding_o ( is_decoding ), + .illegal_insn_o ( illegal_insn_id ), // Interface to instruction memory - .instr_valid_i ( instr_valid_id ), - .instr_rdata_i ( instr_rdata_id ), - .instr_req_o ( instr_req_int ), + .instr_valid_i ( instr_valid_id ), + .instr_rdata_i ( instr_rdata_id ), + .instr_rdata_c_i ( instr_rdata_c_id ), + .instr_is_compressed_i ( instr_is_compressed_id ), + .instr_req_o ( instr_req_int ), // Jumps and branches - .branch_decision_i ( branch_decision ), + .branch_decision_i ( branch_decision ), // IF and ID control signals - .clear_instr_valid_o ( clear_instr_valid ), - .pc_set_o ( pc_set ), - .pc_mux_o ( pc_mux_id ), - .exc_pc_mux_o ( exc_pc_mux_id ), - .exc_cause_o ( exc_cause ), + .clear_instr_valid_o ( clear_instr_valid ), + .pc_set_o ( pc_set ), + .pc_mux_o ( pc_mux_id ), + .exc_pc_mux_o ( exc_pc_mux_id ), + .exc_cause_o ( exc_cause ), - .illegal_c_insn_i ( illegal_c_insn_id ), - .is_compressed_i ( is_compressed_id ), + .illegal_c_insn_i ( illegal_c_insn_id ), - .pc_id_i ( pc_id ), + .pc_id_i ( pc_id ), // Stalls - .halt_if_o ( halt_if ), + .halt_if_o ( halt_if ), - .id_ready_o ( id_ready ), - .ex_ready_i ( ex_ready ), + .id_ready_o ( id_ready ), + .ex_ready_i ( ex_ready ), - .id_valid_o ( id_valid ), + .id_valid_o ( id_valid ), - .alu_operator_ex_o ( alu_operator_ex ), - .alu_operand_a_ex_o ( alu_operand_a_ex ), - .alu_operand_b_ex_o ( alu_operand_b_ex ), + .alu_operator_ex_o ( alu_operator_ex ), + .alu_operand_a_ex_o ( alu_operand_a_ex ), + .alu_operand_b_ex_o ( alu_operand_b_ex ), .mult_en_ex_o ( mult_en_ex ), .div_en_ex_o ( div_en_ex ), @@ -405,63 +407,64 @@ module ibex_core #( .multdiv_operand_b_ex_o ( multdiv_operand_b_ex ), // CSR ID/EX - .csr_access_ex_o ( csr_access_ex ), - .csr_op_ex_o ( csr_op_ex ), - .csr_cause_o ( csr_cause ), - .csr_save_if_o ( csr_save_if ), // control signal to save pc - .csr_save_id_o ( csr_save_id ), // control signal to save pc - .csr_restore_mret_id_o ( csr_restore_mret_id ), // control signal to restore pc - .csr_restore_dret_id_o ( csr_restore_dret_id ), // control signal to restore pc - .csr_save_cause_o ( csr_save_cause ), - .illegal_csr_insn_i ( illegal_csr_insn_id ), + .csr_access_ex_o ( csr_access_ex ), + .csr_op_ex_o ( csr_op_ex ), + .csr_save_if_o ( csr_save_if ), // control signal to save pc + .csr_save_id_o ( csr_save_id ), // control signal to save pc + .csr_restore_mret_id_o ( csr_restore_mret_id ), // control signal to restore pc + .csr_restore_dret_id_o ( csr_restore_dret_id ), // control signal to restore pc + .csr_save_cause_o ( csr_save_cause ), + .csr_cause_o ( csr_cause ), + .csr_mtval_o ( csr_mtval ), + .illegal_csr_insn_i ( illegal_csr_insn_id ), // LSU - .data_req_ex_o ( data_req_ex ), // to load store unit - .data_we_ex_o ( data_we_ex ), // to load store unit - .data_type_ex_o ( data_type_ex ), // to load store unit - .data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit - .data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit - .data_wdata_ex_o ( data_wdata_ex ), // to load store unit + .data_req_ex_o ( data_req_ex ), // to load store unit + .data_we_ex_o ( data_we_ex ), // to load store unit + .data_type_ex_o ( data_type_ex ), // to load store unit + .data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit + .data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit + .data_wdata_ex_o ( data_wdata_ex ), // to load store unit - .data_misaligned_i ( data_misaligned ), - .misaligned_addr_i ( misaligned_addr ), + .data_misaligned_i ( data_misaligned ), + .lsu_addr_last_i ( lsu_addr_last ), - .lsu_load_err_i ( lsu_load_err ), - .lsu_store_err_i ( lsu_store_err ), + .lsu_load_err_i ( lsu_load_err ), + .lsu_store_err_i ( lsu_store_err ), // Interrupt Signals - .irq_i ( irq_i ), // incoming interrupts - .irq_id_i ( irq_id_i ), - .m_irq_enable_i ( m_irq_enable ), - .irq_ack_o ( irq_ack_o ), - .irq_id_o ( irq_id_o ), + .irq_i ( irq_i ), // incoming interrupts + .irq_id_i ( irq_id_i ), + .m_irq_enable_i ( m_irq_enable ), + .irq_ack_o ( irq_ack_o ), + .irq_id_o ( irq_id_o ), // Debug Signal - .debug_cause_o ( debug_cause ), - .debug_csr_save_o ( debug_csr_save ), - .debug_req_i ( debug_req_i ), - .debug_single_step_i ( debug_single_step ), - .debug_ebreakm_i ( debug_ebreakm ), + .debug_cause_o ( debug_cause ), + .debug_csr_save_o ( debug_csr_save ), + .debug_req_i ( debug_req_i ), + .debug_single_step_i ( debug_single_step ), + .debug_ebreakm_i ( debug_ebreakm ), // write data to commit in the register file - .regfile_wdata_lsu_i ( regfile_wdata_lsu ), - .regfile_wdata_ex_i ( regfile_wdata_ex ), - .csr_rdata_i ( csr_rdata ), + .regfile_wdata_lsu_i ( regfile_wdata_lsu ), + .regfile_wdata_ex_i ( regfile_wdata_ex ), + .csr_rdata_i ( csr_rdata ), `ifdef RVFI - .rfvi_reg_raddr_ra_o ( rvfi_rs1_addr_id ), - .rfvi_reg_rdata_ra_o ( rvfi_rs1_data_id ), - .rfvi_reg_raddr_rb_o ( rvfi_rs2_addr_id ), - .rfvi_reg_rdata_rb_o ( rvfi_rs2_data_id ), - .rfvi_reg_waddr_rd_o ( rvfi_rd_addr_id ), - .rfvi_reg_wdata_rd_o ( rvfi_rd_wdata_id ), - .rfvi_reg_we_o ( rvfi_rd_we_id ), + .rfvi_reg_raddr_ra_o ( rvfi_rs1_addr_id ), + .rfvi_reg_rdata_ra_o ( rvfi_rs1_data_id ), + .rfvi_reg_raddr_rb_o ( rvfi_rs2_addr_id ), + .rfvi_reg_rdata_rb_o ( rvfi_rs2_data_id ), + .rfvi_reg_waddr_rd_o ( rvfi_rd_addr_id ), + .rfvi_reg_wdata_rd_o ( rvfi_rd_wdata_id ), + .rfvi_reg_we_o ( rvfi_rd_we_id ), `endif // Performance Counters - .perf_jump_o ( perf_jump ), - .perf_branch_o ( perf_branch ), - .perf_tbranch_o ( perf_tbranch ) + .perf_jump_o ( perf_jump ), + .perf_branch_o ( perf_branch ), + .perf_tbranch_o ( perf_tbranch ) ); @@ -528,7 +531,7 @@ module ibex_core #( .adder_result_ex_i ( alu_adder_result_ex), .data_misaligned_o ( data_misaligned ), - .misaligned_addr_o ( misaligned_addr ), + .addr_last_o ( lsu_addr_last ), // exception signals .load_err_o ( lsu_load_err ), @@ -563,57 +566,59 @@ module ibex_core #( .RV32E ( RV32E ), .RV32M ( RV32M ) ) cs_registers_i ( - .clk_i ( clk ), - .rst_ni ( rst_ni ), + .clk_i ( clk ), + .rst_ni ( rst_ni ), // Core and Cluster ID from outside - .core_id_i ( core_id_i ), - .cluster_id_i ( cluster_id_i ), + .core_id_i ( core_id_i ), + .cluster_id_i ( cluster_id_i ), // boot address - .boot_addr_i ( boot_addr_i ), + .boot_addr_i ( boot_addr_i ), + // Interface to CSRs (SRAM like) - .csr_access_i ( csr_access ), - .csr_addr_i ( csr_addr ), - .csr_wdata_i ( csr_wdata ), - .csr_op_i ( csr_op ), - .csr_rdata_o ( csr_rdata ), + .csr_access_i ( csr_access ), + .csr_addr_i ( csr_addr ), + .csr_wdata_i ( csr_wdata ), + .csr_op_i ( csr_op ), + .csr_rdata_o ( csr_rdata ), // Interrupt related control signals - .m_irq_enable_o ( m_irq_enable ), - .mepc_o ( mepc ), + .m_irq_enable_o ( m_irq_enable ), + .mepc_o ( mepc ), // debug - .debug_cause_i ( debug_cause ), - .debug_csr_save_i ( debug_csr_save ), - .depc_o ( depc ), - .debug_single_step_o ( debug_single_step ), - .debug_ebreakm_o ( debug_ebreakm ), + .debug_cause_i ( debug_cause ), + .debug_csr_save_i ( debug_csr_save ), + .depc_o ( depc ), + .debug_single_step_o ( debug_single_step ), + .debug_ebreakm_o ( debug_ebreakm ), - .pc_if_i ( pc_if ), - .pc_id_i ( pc_id ), + .pc_if_i ( pc_if ), + .pc_id_i ( pc_id ), - .csr_save_if_i ( csr_save_if ), - .csr_save_id_i ( csr_save_id ), - .csr_restore_mret_i ( csr_restore_mret_id ), - .csr_restore_dret_i ( csr_restore_dret_id ), - .csr_cause_i ( csr_cause ), - .csr_save_cause_i ( csr_save_cause ), - .illegal_csr_insn_o ( illegal_csr_insn_id ), + .csr_save_if_i ( csr_save_if ), + .csr_save_id_i ( csr_save_id ), + .csr_restore_mret_i ( csr_restore_mret_id ), + .csr_restore_dret_i ( csr_restore_dret_id ), + .csr_save_cause_i ( csr_save_cause ), + .csr_cause_i ( csr_cause ), + .csr_mtval_i ( csr_mtval ), + .illegal_csr_insn_o ( illegal_csr_insn_id ), // performance counter related signals - .insn_ret_i ( insn_ret ), - .id_valid_i ( id_valid ), - .is_compressed_i ( is_compressed_id ), - .is_decoding_i ( is_decoding ), + .insn_ret_i ( insn_ret ), + .id_valid_i ( id_valid ), + .instr_is_compressed_i ( instr_is_compressed_id ), + .is_decoding_i ( is_decoding ), - .imiss_i ( perf_imiss ), - .pc_set_i ( pc_set ), - .jump_i ( perf_jump ), - .branch_i ( perf_branch ), - .branch_taken_i ( perf_tbranch ), - .mem_load_i ( perf_load ), - .mem_store_i ( perf_store ), - .lsu_busy_i ( lsu_busy ) + .imiss_i ( perf_imiss ), + .pc_set_i ( pc_set ), + .jump_i ( perf_jump ), + .branch_i ( perf_branch ), + .branch_taken_i ( perf_tbranch ), + .mem_load_i ( perf_load ), + .mem_store_i ( perf_store ), + .lsu_busy_i ( lsu_busy ) ); `ifdef RVFI @@ -672,7 +677,7 @@ module ibex_core #( always_comb begin if (is_compressed_id) begin - rvfi_insn_opcode = {16'b0, compressed_instr}; + rvfi_insn_opcode = {16'b0, instr_rdata_c_id}; end else begin rvfi_insn_opcode = instr_rdata_id; end diff --git a/rtl/ibex_cs_registers.sv b/rtl/ibex_cs_registers.sv index f33cfc70..9b7830e1 100644 --- a/rtl/ibex_cs_registers.sv +++ b/rtl/ibex_cs_registers.sv @@ -66,26 +66,26 @@ module ibex_cs_registers #( input logic csr_save_id_i, input logic csr_restore_mret_i, input logic csr_restore_dret_i, - - input ibex_defines::exc_cause_e csr_cause_i, input logic csr_save_cause_i, + input logic [31:0] csr_mtval_i, + input ibex_defines::exc_cause_e csr_cause_i, - output logic illegal_csr_insn_o, // access to non-existent CSR, - // with wrong priviledge level, or - // missing write permissions + output logic illegal_csr_insn_o, // access to non-existent CSR, + // with wrong priviledge level, or + // missing write permissions // Performance Counters - input logic insn_ret_i, // instr retired in ID/EX stage - input logic id_valid_i, // ID stage is done - input logic is_compressed_i, // compressed instr in ID - input logic is_decoding_i, // controller is in DECODE state + input logic insn_ret_i, // instr retired in ID/EX stage + input logic id_valid_i, // ID stage is done + input logic instr_is_compressed_i, // compressed instr in ID + input logic is_decoding_i, // controller is in DECODE state - input logic imiss_i, // instr fetch - input logic pc_set_i, // PC was set to a new value - input logic jump_i, // jump instr seen (j, jr, jal, jalr) - input logic branch_i, // branch instr seen (bf, bnf) - input logic branch_taken_i, // branch was taken - input logic mem_load_i, // load from memory in this cycle - input logic mem_store_i, // store to memory in this cycle + input logic imiss_i, // instr fetch + input logic pc_set_i, // PC was set to a new value + input logic jump_i, // jump instr seen (j, jr, jal, jalr) + input logic branch_i, // branch instr seen (bf, bnf) + input logic branch_taken_i, // branch was taken + input logic mem_load_i, // load from memory in this cycle + input logic mem_store_i, // store to memory in this cycle input logic lsu_busy_i ); @@ -155,6 +155,7 @@ module ibex_cs_registers #( Status_t mstatus_q, mstatus_n; logic [31:0] mepc_q, mepc_n; logic [31:0] mcause_q, mcause_n; + logic [31:0] mtval_q, mtval_n; Dcsr_t dcsr_q, dcsr_n; logic [31:0] depc_q, depc_n; logic [31:0] dscratch0_q, dscratch0_n; @@ -229,6 +230,8 @@ module ibex_cs_registers #( // mcause: exception cause CSR_MCAUSE: csr_rdata_int = {mcause_q[5], 26'b0, mcause_q[4:0]}; + // mtval: trap value + CSR_MTVAL: csr_rdata_int = mtval_q; CSR_DCSR: csr_rdata_int = dcsr_q; CSR_DPC: csr_rdata_int = depc_q; @@ -283,6 +286,7 @@ module ibex_cs_registers #( mstatus_n = mstatus_q; mepc_n = mepc_q; mcause_n = mcause_q; + mtval_n = mtval_q; dcsr_n = dcsr_q; depc_n = depc_q; dscratch0_n = dscratch0_q; @@ -309,6 +313,9 @@ module ibex_cs_registers #( // mcause CSR_MCAUSE: if (csr_we_int) mcause_n = {csr_wdata_int[31], csr_wdata_int[4:0]}; + // mtval: trap value + CSR_MTVAL: if (csr_we_int) mtval_n = csr_wdata_int; + CSR_DCSR: begin if (csr_we_int) begin dcsr_n = csr_wdata_int; @@ -415,6 +422,7 @@ module ibex_cs_registers #( mstatus_n.mpp = PRIV_LVL_M; mepc_n = exception_pc; mcause_n = csr_cause_i; + mtval_n = csr_mtval_i; end end //csr_save_cause_i @@ -474,6 +482,7 @@ module ibex_cs_registers #( }; mepc_q <= '0; mcause_q <= '0; + mtval_q <= '0; dcsr_q <= '{ xdebugver: XDEBUGVER_NO, // 4'h0 cause: DBG_CAUSE_NONE, // 3'h0 @@ -492,6 +501,7 @@ module ibex_cs_registers #( }; mepc_q <= mepc_n; mcause_q <= mcause_n; + mtval_q <= mtval_n; dcsr_q <= dcsr_n; depc_q <= depc_n; dscratch0_q <= dscratch0_n; @@ -532,8 +542,8 @@ module ibex_cs_registers #( mhpmcounter_incr[7] = jump_i; // num of jumps (unconditional) mhpmcounter_incr[8] = branch_i; // num of branches (conditional) mhpmcounter_incr[9] = branch_taken_i; // num of taken branches (conditional) - mhpmcounter_incr[10] = is_compressed_i // num of compressed instr - & id_valid_i & is_decoding_i; + mhpmcounter_incr[10] = is_decoding_i // num of compressed instr + & id_valid_i & instr_is_compressed_i; // inactive counters for (int unsigned i=3+MHPMCounterNum; i<32; i++) begin : gen_mhpmcounter_incr_inactive diff --git a/rtl/ibex_defines.sv b/rtl/ibex_defines.sv index 2e0a53a5..7b939fbb 100644 --- a/rtl/ibex_defines.sv +++ b/rtl/ibex_defines.sv @@ -226,6 +226,7 @@ typedef enum logic[11:0] { // Machine trap handling CSR_MEPC = 12'h341, CSR_MCAUSE = 12'h342, + CSR_MTVAL = 12'h343, // Debug/trace CSR_DCSR = 12'h7b0, diff --git a/rtl/ibex_id_stage.sv b/rtl/ibex_id_stage.sv index 6654bfc8..2626b173 100644 --- a/rtl/ibex_id_stage.sv +++ b/rtl/ibex_id_stage.sv @@ -53,7 +53,9 @@ module ibex_id_stage #( // Interface to IF stage input logic instr_valid_i, - input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage + input logic [31:0] instr_rdata_i, // from IF-ID pipeline registers + input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers + input logic instr_is_compressed_i, output logic instr_req_o, // Jumps and branches @@ -66,7 +68,6 @@ module ibex_id_stage #( output ibex_defines::exc_pc_sel_e exc_pc_mux_o, input logic illegal_c_insn_i, - input logic is_compressed_i, input logic [31:0] pc_id_i, @@ -92,12 +93,13 @@ module ibex_id_stage #( // CSR output logic csr_access_ex_o, output ibex_defines::csr_op_e csr_op_ex_o, - output ibex_defines::exc_cause_e csr_cause_o, output logic csr_save_if_o, output logic csr_save_id_o, output logic csr_restore_mret_id_o, output logic csr_restore_dret_id_o, output logic csr_save_cause_o, + output ibex_defines::exc_cause_e csr_cause_o, + output logic [31:0] csr_mtval_o, input logic illegal_csr_insn_i, // Interface to load store unit @@ -109,7 +111,7 @@ module ibex_id_stage #( output logic [31:0] data_wdata_ex_o, input logic data_misaligned_i, - input logic [31:0] misaligned_addr_i, + input logic [31:0] lsu_addr_last_i, // Interrupt signals input logic irq_i, @@ -300,7 +302,7 @@ module ibex_id_stage #( always_comb begin : alu_operand_a_mux unique case (alu_op_a_mux_sel) OP_A_REG_A: alu_operand_a = regfile_data_ra_id; - OP_A_FWD: alu_operand_a = misaligned_addr_i; + OP_A_FWD: alu_operand_a = lsu_addr_last_i; OP_A_CURRPC: alu_operand_a = pc_id_i; OP_A_IMM: alu_operand_a = imm_a; default: alu_operand_a = 'X; @@ -321,7 +323,7 @@ module ibex_id_stage #( IMM_B_B: imm_b = imm_b_type; IMM_B_U: imm_b = imm_u_type; IMM_B_J: imm_b = imm_j_type; - IMM_B_INCR_PC: imm_b = is_compressed_i ? 32'h2 : 32'h4; + IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4; IMM_B_INCR_ADDR: imm_b = 32'h4; default: imm_b = imm_i_type; endcase @@ -331,7 +333,7 @@ module ibex_id_stage #( assign alu_operand_b = (alu_op_b_mux_sel == OP_B_IMM) ? imm_b : regfile_data_rb_id; // Signals used by tracer - assign operand_a_fw_id = data_misaligned_i ? misaligned_addr_i : regfile_data_ra_id; + assign operand_a_fw_id = data_misaligned_i ? lsu_addr_last_i : regfile_data_ra_id; assign operand_b_fw_id = regfile_data_rb_id; assign unused_operand_a_fw_id = operand_a_fw_id; @@ -483,6 +485,9 @@ module ibex_id_stage #( // from IF/ID pipeline .instr_valid_i ( instr_valid_i ), + .instr_i ( instr ), + .instr_compressed_i ( instr_rdata_c_i ), + .instr_is_compressed_i ( instr_is_compressed_i ), // from prefetcher .instr_req_o ( instr_req_o ), @@ -494,6 +499,7 @@ module ibex_id_stage #( .exc_cause_o ( exc_cause_o ), // LSU + .lsu_addr_last_i ( lsu_addr_last_i ), .load_err_i ( lsu_load_err_i ), .store_err_i ( lsu_store_err_i ), @@ -517,12 +523,13 @@ module ibex_id_stage #( .exc_kill_o ( exc_kill ), // CSR Controller Signals - .csr_save_cause_o ( csr_save_cause_o ), - .csr_cause_o ( csr_cause_o ), .csr_save_if_o ( csr_save_if_o ), .csr_save_id_o ( csr_save_id_o ), .csr_restore_mret_id_o ( csr_restore_mret_id_o ), .csr_restore_dret_id_o ( csr_restore_dret_id_o ), + .csr_save_cause_o ( csr_save_cause_o ), + .csr_cause_o ( csr_cause_o ), + .csr_mtval_o ( csr_mtval_o ), // Debug Signal .debug_cause_o ( debug_cause_o ), diff --git a/rtl/ibex_if_stage.sv b/rtl/ibex_if_stage.sv index 2149b479..bd87c1b7 100644 --- a/rtl/ibex_if_stage.sv +++ b/rtl/ibex_if_stage.sv @@ -40,48 +40,50 @@ module ibex_if_stage #( input logic [31:0] boot_addr_i, // instruction request control input logic req_i, + // instruction cache interface output logic instr_req_o, output logic [31:0] instr_addr_o, input logic instr_gnt_i, input logic instr_rvalid_i, input logic [31:0] instr_rdata_i, - // Output of IF Pipeline stage - output logic instr_valid_id_o, // instr in IF/ID is valid - output logic [31:0] instr_rdata_id_o, // read instr is sampled and sent - // to ID stage for decoding - output logic is_compressed_id_o, // compressed decoder thinks this is - // a compressed instr -`ifdef RVFI - output logic [15:0] instr_rdata_compressed_o, -`endif - output logic illegal_c_insn_id_o, // compressed decoder thinks this is - // an invalid instr + // Output of IF Pipeline stage + output logic instr_valid_id_o, // instr in IF-ID is valid + output logic [31:0] instr_rdata_id_o, // instr for ID stage + output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage + // (mtval), meaningful only if + // instr_is_compressed_id_o = 1'b1 + output logic instr_is_compressed_id_o, // compressed decoder thinks this + // is a compressed instr + output logic illegal_c_insn_id_o, // compressed decoder thinks this + // is an invalid instr output logic [31:0] pc_if_o, output logic [31:0] pc_id_o, + // Forwarding ports - control signals - input logic clear_instr_valid_i, // clear instr valid bit in IF/ID - input logic pc_set_i, // set the PC to a new value - input logic [31:0] exception_pc_reg_i, // address used to restore PC when - // the interrupt/exception is served - input logic [31:0] depc_i, // address used to restore PC when - // the debug request is served - input ibex_defines::pc_sel_e pc_mux_i, // selector for PC multiplexer - input ibex_defines::exc_pc_sel_e exc_pc_mux_i, // selects ISR address - input ibex_defines::exc_cause_e exc_vec_pc_mux_i, // selects ISR address for vectorized - // interrupt lines + input logic clear_instr_valid_i, // clear instr valid bit in IF-ID + input logic pc_set_i, // set the PC to a new value + input logic [31:0] exception_pc_reg_i, // PC to restore after handling + // the interrupt/exception + input logic [31:0] depc_i, // PC to restore after handling + // the debug request + input ibex_defines::pc_sel_e pc_mux_i, // selector for PC multiplexer + input ibex_defines::exc_pc_sel_e exc_pc_mux_i, // selects ISR address + input ibex_defines::exc_cause_e exc_vec_pc_mux_i, // selects ISR address for + // vectorized interrupt lines // jump and branch target and decision - input logic [31:0] jump_target_ex_i, // jump target address + input logic [31:0] jump_target_ex_i, // jump target address // pipeline stall input logic halt_if_i, input logic id_ready_i, output logic if_valid_o, + // misc signals - output logic if_busy_o, // IF stage is busy fetching instr - output logic perf_imiss_o // instr fetch miss + output logic if_busy_o, // IF stage is busy fetching instr + output logic perf_imiss_o // instr fetch miss ); import ibex_defines::*; @@ -214,13 +216,13 @@ module ibex_if_stage #( // to ease timing closure logic [31:0] instr_decompressed; logic illegal_c_insn; - logic instr_compressed_int; + logic instr_is_compressed_int; ibex_compressed_decoder compressed_decoder_i ( - .instr_i ( fetch_rdata ), - .instr_o ( instr_decompressed ), - .is_compressed_o ( instr_compressed_int ), - .illegal_instr_o ( illegal_c_insn ) + .instr_i ( fetch_rdata ), + .instr_o ( instr_decompressed ), + .is_compressed_o ( instr_is_compressed_int ), + .illegal_instr_o ( illegal_c_insn ) ); // IF-ID pipeline registers, frozen when the ID stage is stalled @@ -228,21 +230,17 @@ module ibex_if_stage #( if (!rst_ni) begin instr_valid_id_o <= 1'b0; instr_rdata_id_o <= '0; + instr_rdata_c_id_o <= '0; + instr_is_compressed_id_o <= 1'b0; illegal_c_insn_id_o <= 1'b0; - is_compressed_id_o <= 1'b0; -`ifdef RVFI - instr_rdata_compressed_o <= '0; -`endif pc_id_o <= '0; end else begin if (if_valid_o) begin instr_valid_id_o <= 1'b1; instr_rdata_id_o <= instr_decompressed; + instr_rdata_c_id_o <= fetch_rdata[15:0]; + instr_is_compressed_id_o <= instr_is_compressed_int; illegal_c_insn_id_o <= illegal_c_insn; - is_compressed_id_o <= instr_compressed_int; -`ifdef RVFI - instr_rdata_compressed_o <= fetch_rdata[15:0]; -`endif pc_id_o <= pc_if_o; end else if (clear_instr_valid_i) begin instr_valid_id_o <= 1'b0; diff --git a/rtl/ibex_load_store_unit.sv b/rtl/ibex_load_store_unit.sv index 35b6ae63..a0b95315 100644 --- a/rtl/ibex_load_store_unit.sv +++ b/rtl/ibex_load_store_unit.sv @@ -52,17 +52,19 @@ module ibex_load_store_unit ( output logic [31:0] data_rdata_ex_o, // requested data -> to EX input logic data_req_ex_i, // data request -> from EX - input logic [31:0] adder_result_ex_i, + input logic [31:0] adder_result_ex_i, // address computed in ALU -> from EX output logic data_misaligned_o, // misaligned access detected -> to controller - output logic [31:0] misaligned_addr_o, + output logic [31:0] addr_last_o, // address of last transaction -> to controller + // -> mtval + // -> AGU for misaligned accesses // exception signals output logic load_err_o, output logic store_err_o, // stall signal - output logic lsu_update_addr_o, // LSU ready for new data in EX stage + output logic lsu_update_addr_o, // LSU ready for new data in EX stage output logic data_valid_o, output logic busy_o @@ -70,6 +72,7 @@ module ibex_load_store_unit ( logic [31:0] data_addr; logic [31:0] data_addr_w_aligned; + logic [31:0] addr_last_q, addr_last_n; // registers for data_rdata alignment and sign extension logic [1:0] data_type_q; @@ -85,7 +88,6 @@ module ibex_load_store_unit ( logic misaligned_st; // high if we are currently performing the second part // of a misaligned store logic data_misaligned, data_misaligned_q; - logic increase_address; typedef enum logic [2:0] { IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID @@ -289,19 +291,26 @@ module ibex_load_store_unit ( endcase //~case(rdata_type_q) end + // store last output address for mtval + AGU for misaligned transactions + // do not update in case of errors, mtval needs the failing address + always_comb begin + addr_last_n = addr_last_q; + if (data_req_o & data_gnt_i & ~(load_err_o | store_err_o)) begin + addr_last_n = data_addr_o; + end + end + always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin ls_fsm_cs <= IDLE; + addr_last_q <= '0; rdata_q <= '0; data_misaligned_q <= '0; - misaligned_addr_o <= 32'b0; end else begin ls_fsm_cs <= ls_fsm_ns; + addr_last_q <= addr_last_n; if (lsu_update_addr_o) begin data_misaligned_q <= data_misaligned; - if (increase_address) begin - misaligned_addr_o <= data_addr; - end end if (data_rvalid_i && !data_we_q) begin // if we have detected a misaligned access, and we are @@ -333,6 +342,8 @@ module ibex_load_store_unit ( assign misaligned_st = data_misaligned_q; + assign addr_last_o = addr_last_q; + // to know what kind of error to signal, we need to know the type of the transaction to which // the outsanding rvalid belongs. assign load_err_o = data_err_i & data_rvalid_i & ~data_we_q; @@ -347,17 +358,15 @@ module ibex_load_store_unit ( lsu_update_addr_o = 1'b0; data_valid_o = 1'b0; - increase_address = 1'b0; data_misaligned_o = 1'b0; unique case(ls_fsm_cs) // starts from not active and stays in IDLE until request was granted IDLE: begin if (data_req_ex_i) begin - data_req_o = data_req_ex_i; + data_req_o = data_req_ex_i; if (data_gnt_i) begin - lsu_update_addr_o = 1'b1; - increase_address = data_misaligned; + lsu_update_addr_o = 1'b1; ls_fsm_ns = data_misaligned ? WAIT_RVALID_MIS : WAIT_RVALID; end else begin ls_fsm_ns = data_misaligned ? WAIT_GNT_MIS : WAIT_GNT; @@ -369,15 +378,12 @@ module ibex_load_store_unit ( data_req_o = 1'b1; if (data_gnt_i) begin lsu_update_addr_o = 1'b1; - increase_address = data_misaligned; ls_fsm_ns = WAIT_RVALID_MIS; end end // WAIT_GNT_MIS // wait for rvalid in WB stage and send a new request if there is any WAIT_RVALID_MIS: begin - //increase_address goes down, we already have the proper address - increase_address = 1'b0; //tell the controller to update the address data_misaligned_o = 1'b1; data_req_o = 1'b0;