diff --git a/controller.sv b/controller.sv index 8048e0d8..d6a70eb4 100644 --- a/controller.sv +++ b/controller.sv @@ -43,7 +43,7 @@ module riscv_controller // decoder related signals output logic deassert_we_o, // deassert write enable for next instruction - input logic illegal_insn_i, // decoder encountered an invalid instruction + input logic illegal_insn_i, // decoder encountered an invalid instruction // TODO: Remove? input logic eret_insn_i, // decoder encountered an eret instruction input logic pipe_flush_i, // decoder wants to do a pipe flush @@ -75,14 +75,12 @@ module riscv_controller input logic branch_decision_i, // branch decision is available in EX stage - // Interrupt signals - input logic irq_present_i, // there is an IRQ, so if we are sleeping we should wake up now // Exception Controller Signals - input logic exc_pc_sel_i, // exception execution requested - input logic exc_pipe_flush_i, // flush pipeline after exception handling + input logic exc_req_i, + output logic exc_ack_o, + + // TODO input logic trap_hit_i, // a trap was hit, so we have to flush EX and WB - output logic illegal_insn_o, // illegal instruction encountered - output logic clear_isr_running_o, // an l.rfe instruction was encountered, exit ISR // Debug Unit Signals input logic dbg_stall_i, // Pipeline stall is requested @@ -146,7 +144,7 @@ module riscv_controller always_ff @(negedge clk) begin // print warning in case of decoding errors - if (illegal_insn_o) begin + if (illegal_insn_i) begin $display("%t: Illegal instruction (core %0d) at PC 0x%h:", $time, riscv_core.core_id_i, riscv_id_stage.current_pc_id_i); end @@ -168,6 +166,8 @@ module riscv_controller // Default values instr_req_o = 1'b1; + exc_ack_o = 1'b0; + pc_mux_sel_o = `PC_BOOT; pc_set_o = 1'b0; @@ -179,8 +179,6 @@ module riscv_controller halt_if_o = 1'b0; halt_id_o = 1'b0; dbg_trap_o = 1'b0; - illegal_insn_o = 1'b0; - clear_isr_running_o = 1'b0; unique case (ctrl_fsm_cs) // We were just reset, wait for fetch_enable @@ -211,8 +209,9 @@ module riscv_controller core_busy_o = 1'b0; instr_req_o = 1'b0; - if (fetch_enable_i || irq_present_i) + if (fetch_enable_i || exc_req_i) begin + // TODO: Check if we need to handle IRQs here ctrl_fsm_ns = FIRST_FETCH; end end // case: SLEEP @@ -225,6 +224,8 @@ module riscv_controller ctrl_fsm_ns = DECODE; end + // TODO: Check if we need to handle IRQs here + // hwloop detected, jump to start address! // Attention: This has to be done in the DECODE and the FIRST_FETCH states if (hwloop_jump_i == 1'b1) begin @@ -266,14 +267,10 @@ module riscv_controller pc_set_o = 1'b1; end - // handle illegal instructions - if (illegal_insn_i) begin - illegal_insn_o = 1'b1; - end - - if (exc_pc_sel_i) begin - pc_mux_sel_o = `PC_EXCEPTION; - pc_set_o = 1'b1; + if (exc_req_i) begin + pc_mux_sel_o = `PC_EXCEPTION; + pc_set_o = 1'b1; + exc_ack_o = 1'b1; // we don't have to change our current state here as the prefetch // buffer is automatically invalidated, thus the next instruction @@ -282,14 +279,21 @@ module riscv_controller end if (eret_insn_i) begin - clear_isr_running_o = 1'b1; pc_mux_sel_o = `PC_ERET; pc_set_o = 1'b1; + + // go back to sleep if core was woken up for this interrupt + if (fetch_enable_i == 1'b0) begin + halt_if_o = 1'b1; + halt_id_o = 1'b1; + + ctrl_fsm_ns = FLUSH_EX; + end end // handle WFI instruction, flush pipeline and (potentially) go to // sleep - if (pipe_flush_i || exc_pipe_flush_i) + if (pipe_flush_i) begin halt_if_o = 1'b1; halt_id_o = 1'b1; diff --git a/cs_registers.sv b/cs_registers.sv index 87b2a880..71e43bb6 100644 --- a/cs_registers.sv +++ b/cs_registers.sv @@ -45,14 +45,17 @@ module riscv_cs_registers output logic [31:0] csr_rdata_o, // Interrupts - input logic [31:0] curr_pc_if_i, - input logic [31:0] curr_pc_id_i, - input logic save_pc_if_i, - input logic save_pc_id_i, - output logic irq_enable_o, output logic [31:0] epcr_o, + input logic [31:0] curr_pc_if_i, + input logic [31:0] curr_pc_id_i, + input logic save_pc_if_i, + input logic save_pc_id_i, + + input logic [5:0] exc_cause_i, + input logic save_exc_cause_i, + // Performance Counters input logic id_valid_i, // ID stage is done input logic is_compressed_i, // compressed instruction in ID @@ -107,6 +110,7 @@ module riscv_cs_registers // Interrupt control signals logic irq_enable, irq_enable_n; + logic [5:0] exc_cause, exc_cause_n; //////////////////////////////////////////// @@ -131,6 +135,8 @@ module riscv_cs_registers 12'h340: csr_rdata_int = csr[`CSR_IDX_MSCRATCH]; // mepc: exception program counter 12'h341: csr_rdata_int = csr[`CSR_IDX_MEPC]; + // mcause: exception cause + 12'h342: csr_rdata_int = {exc_cause[5], 26'b0, exc_cause[4:0]}; // mcpuid: RV32I 12'hF00: csr_rdata_int = 32'h00_00_01_00; @@ -147,6 +153,7 @@ module riscv_cs_registers begin csr_n = csr; irq_enable_n = irq_enable; + exc_cause_n = exc_cause; case (csr_addr_i) // mstatus: IE bit @@ -156,6 +163,8 @@ module riscv_cs_registers 12'h340: if (csr_we_int) csr_n[`CSR_IDX_MSCRATCH] = csr_wdata_int; // mepc: exception program counter 12'h341: if (csr_we_int) csr_n[`CSR_IDX_MEPC] = csr_wdata_int; + // mcause + 12'h342: if (csr_we_int) exc_cause_n = {csr_wdata_int[5], csr_wdata_int[4:0]}; endcase end @@ -202,18 +211,23 @@ module riscv_cs_registers begin csr <= '{default: 32'b0}; irq_enable <= 1'b0; + exc_cause <= 6'b0; end else begin // update CSRs - csr <= csr_n; - + csr <= csr_n; irq_enable <= irq_enable_n; - // exception PC writes from exception controller get priority + exc_cause <= exc_cause_n; + + // exception controller gets priority over other writes if (save_pc_if_i == 1'b1) csr[`CSR_IDX_MEPC] <= curr_pc_if_i; else if (save_pc_id_i == 1'b1) csr[`CSR_IDX_MEPC] <= curr_pc_id_i; + + if (save_exc_cause_i) + exc_cause <= exc_cause_i; end end diff --git a/exc_controller.sv b/exc_controller.sv index 13b0c07c..6df2a07c 100644 --- a/exc_controller.sv +++ b/exc_controller.sv @@ -4,6 +4,7 @@ // Engineer: Andreas Traber - atraber@student.ethz.ch // // // // Additional contributions by: // +// Sven Stucki - svstucki@student.ethz.ch // // // // // // Create Date: 20/01/2015 // @@ -15,246 +16,153 @@ // Description: Exception Controller of the pipelined processor // // // // // -// Revision: // -// Revision v0.1 - File Created // -// // -// // -// // //////////////////////////////////////////////////////////////////////////////// `include "defines.sv" + module riscv_exc_controller ( - input logic clk, - input logic rst_n, + input logic clk, + input logic rst_n, - input logic fetch_enable_i, + // handshake signals to controller + output logic req_o, + input logic ack_i, - // to IF stage - output logic exc_pc_sel_o, // influences next PC, if set exception PC is used - output logic [1:0] exc_pc_mux_o, // Selector in the Fetch stage to select the rigth exception PC + // to IF stage + output logic [1:0] pc_mux_o, // selects target PC for exception + output logic [4:0] vec_pc_mux_o, // selects interrupt handler for vectorized interrupts - input logic branch_done_i, // Did we already perform a branch while waiting for the next instruction? + // interrupt lines + input logic [31:0] irq_i, // level-triggered interrupt inputs + input logic irq_enable_i, // interrupt enable bit from CSR - // hwloop signals - output logic hwloop_enable_o, // '1' if pc is valid (interrupt related signal) + // from decoder + input logic illegal_insn_i, // illegal instruction encountered + input logic ecall_insn_i, // ecall instruction encountered + input logic eret_insn_i, // eret instruction encountered - // Interrupt signals - input logic irq_i, // level-triggered IR line - input logic irq_nm_i, // level-triggered IR line for non-maskable IRQ - input logic irq_enable_i, // global interrupt enable - output logic irq_present_o, // tells the controller to start fetching instructions if asleep - - // SPR - output logic save_pc_if_o, // saves current_pc_if before entering interrupt routine - output logic save_pc_id_o, // saves current_pc_id before entering interrupt routine - - // Controller - input logic core_busy_i, // Is the controller currently in the IDLE state? - input logic [1:0] jump_in_id_i, // jump instruction in ID stage - input logic [1:0] jump_in_ex_i, // jump instruction in EX stage - input logic stall_id_i, // Stall ID stage - input logic illegal_insn_i, // Illegal instruction encountered in ID stage - input logic trap_insn_i, // Trap instruction encountered in ID stage - input logic drop_instruction_i, // If branch prediction went wrong - input logic clear_isr_running_i, // exit ISR routine - output logic exc_pipe_flush_o, // flush pipeline and go back to sleep - - // Debug Unit Signals - input logic dbg_flush_pipe_i, // Pipe flush requested - input logic dbg_st_en_i, // Single-step trace mode enabled - input logic [1:0] dbg_dsr_i, // Debug Stop Register - output logic trap_hit_o // Software Trap in ID (l.trap or similar stuff) + // to CSR + output logic [5:0] cause_o, + output logic save_cause_o ); - // Exception unit state encoding - enum logic [1:0] { ExcNone, ExcIR, ExcIRDeferred, ExcIllegalInsn } exc_reason, exc_reason_q, exc_reason_n; - // Registers - logic exc_running_p, exc_running_n; - logic new_instr_id_q; + enum logic [1:0] { IDLE, WAIT_CONTROLLER, IN_ISR } exc_ctrl_cs, exc_ctrl_ns; - // disable hardware loops when nops are inserted or the controller is not active - assign hwloop_enable_o = (~core_busy_i); + logic req_int; + logic [1:0] pc_mux_int, pc_mux_int_d; + logic [5:0] cause_int, cause_int_d; - ///////////////////////////////////////////// - // ____ _ // - // | _ \ ___ ___ ___ __| | ___ _ __ // - // | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| // - // | |_| | __/ (_| (_) | (_| | __/ | // - // |____/ \___|\___\___/ \__,_|\___|_| // - // // - ///////////////////////////////////////////// + integer i; - // a trap towards the debug unit is generated when one of the - // following conditions are true: - // - l.trap instruction encountered - // - single-stepping mode enabled (after one instruction is executed) - // - illegal instruction exception and IIE bit is set - // - IRQ and INTE bit is set and no exception is currently running - // - Debuger requests halt - assign trap_hit_o = trap_insn_i || dbg_flush_pipe_i || dbg_st_en_i || (illegal_insn_i && dbg_dsr_i[`DSR_IIE]) || (irq_present_o && dbg_dsr_i[`DSR_INTE] && (~exc_running_p)); - assign irq_present_o = (irq_i || irq_nm_i) && irq_enable_i; + assign req_int = illegal_insn_i | ecall_insn_i | (|irq_i); - // Decoder for exc_reason signal - // this signal tells the exception controller which is the exception - // with highest priority at the moment - // The decoder also takes care that no nested exceptions are performed + + // Exception cause and ISR address selection always_comb begin - exc_reason = ExcNone; - exc_pipe_flush_o = 1'b0; + cause_int = 6'b0; + pc_mux_int = 2'b0; - if (illegal_insn_i == 1'b1) + for (i = 31; i >= 0; i--) begin - // if the IIE bit in the Debug Stop Register is set, we transfer - // the control to the debug interface - // otherwise we jump to the interrupt handler, if we are not - // already in an interrupt handler - if ((dbg_dsr_i[`DSR_IIE] == 1'b0) && (exc_running_p == 1'b0)) - exc_reason = ExcIllegalInsn; - end - else if ((irq_present_o == 1'b1) && (exc_running_p == 1'b0)) - begin - // an interrupt is present, flush pipeline, execute pending delay slots - // and then call the interrupt handler - // or if the INTE bit is set, transfer the control to the debug interface - if (dbg_dsr_i[`DSR_INTE] == 1'b0) - exc_reason = ExcIR; - end - else if (clear_isr_running_i == 1'b1) - begin - // if we receive an l.rfe instruction when we are not in an - // exception handler, we jump to the illegal instruction handler - if (exc_running_p == 1'b1) - begin - // synopsys translate_off - $display("%t: Exiting exception routine.", $time); - // synopsys translate_on - - // the CPU should go back to sleep - if(fetch_enable_i == 1'b0) - exc_pipe_flush_o = 1'b1; + if (irq_i[i]) begin + cause_int[5] = 1'b1; + cause_int[4:0] = i; + pc_mux_int = `EXC_PC_IRQ; end - else - exc_reason = ExcIllegalInsn; end - if (exc_reason_q != ExcNone) - exc_reason = exc_reason_q; + if (ecall_insn_i) begin + cause_int = 6'b0_01000; + pc_mux_int = `EXC_PC_ECALL; + end + + if (illegal_insn_i) + cause_int = 6'b0_00010; + pc_mux_int = `EXC_PC_ILLINSN; end - ///////////////////////////////////////////////////////////////////// - // _____ _ _ ____ _ _ // - // | ____|_ _____ ___ _ __ | |_(_) ___ _ __ / ___| |_ _ __| | // - // | _| \ \/ / __/ _ \ '_ \| __| |/ _ \| '_ \ | | | __| '__| | // - // | |___ > < (_| __/ |_) | |_| | (_) | | | | | |___| |_| | | | // - // |_____/_/\_\___\___| .__/ \__|_|\___/|_| |_| \____|\__|_| |_| // - // |_| // - ///////////////////////////////////////////////////////////////////// + always_ff @(posedge clk, negedge rst_n) + begin + if (rst_n == 1'b0) begin + cause_int_d <= '0; + pc_mux_int_d <= '0; + end else if (exc_ctrl_cs == IDLE && req_int) begin + // save cause and ISR when new irq request is first sent to controller + cause_int_d <= cause_int; + pc_mux_int_d <= pc_mux_int; + end + end - always_comb begin - exc_running_n = exc_running_p; - save_pc_if_o = 1'b0; - save_pc_id_o = 1'b0; - exc_pc_sel_o = 1'b0; - exc_pc_mux_o = `EXC_PC_NO_INCR; - exc_reason_n = ExcNone; + // Exception cause and mux output (with bypass) + assign cause_o = (exc_ctrl_cs == IDLE && req_int)? cause_int : cause_int_d; + assign pc_mux_o = (exc_ctrl_cs == IDLE && req_int)? pc_mux_int : pc_mux_int_d; - unique case (exc_reason) - // an IRQ is present, execute pending jump and then go - // to the ISR without flushing the pipeline - ExcIR: begin + assign vec_pc_mux_o = (cause_o[5] == 1'b1)? cause_o[4:0] : 5'b0; - if (((jump_in_id_i == `BRANCH_JALR || jump_in_id_i == `BRANCH_JAL) && new_instr_id_q == 1'b0) || jump_in_ex_i == `BRANCH_COND || branch_done_i) - begin - // wait one cycle - if (~stall_id_i) - exc_reason_n = ExcIRDeferred; - end - else //don't wait - begin - exc_pc_sel_o = 1'b1; - if (irq_nm_i == 1'b1) // emergency IRQ has higher priority - exc_pc_mux_o = `EXC_PC_IRQ_NM; - else // irq_i == 1'b1 - exc_pc_mux_o = `EXC_PC_IRQ; + // Exception controller FSM + always_comb + begin + exc_ctrl_ns = exc_ctrl_cs; + req_o = 1'b0; + save_cause_o = 1'b0; - exc_running_n = 1'b1; + unique case (exc_ctrl_cs) + IDLE: + begin + req_o = req_int; - // jumps in ex stage already taken - if (jump_in_id_i != `BRANCH_NONE) - save_pc_id_o = 1'b1; - else - save_pc_if_o = 1'b1; + if (req_int) + exc_ctrl_ns = WAIT_CONTROLLER; + end + + WAIT_CONTROLLER: + begin + req_o = 1'b1; + + if (ack_i) begin + save_cause_o = 1'b1; + exc_ctrl_ns = IN_ISR; end end - ExcIRDeferred : begin - // jumps in ex stage already taken - if (jump_in_id_i != `BRANCH_NONE) - save_pc_id_o = 1'b1; - else - save_pc_if_o = 1'b1; - - exc_pc_sel_o = 1'b1; - - if (irq_nm_i == 1'b1) // emergency IRQ has higher priority - exc_pc_mux_o = `EXC_PC_IRQ_NM; - else // irq_i == 1'b1 - exc_pc_mux_o = `EXC_PC_IRQ; - - exc_running_n = 1'b1; - + IN_ISR: + begin + if (eret_insn_i) + exc_ctrl_ns = IDLE; end - // Illegal instruction encountered, we directly jump to - // the ISR without flushing the pipeline - ExcIllegalInsn: begin - exc_pc_sel_o = 1'b1; - exc_pc_mux_o = `EXC_PC_ILLINSN; - save_pc_id_o = 1'b1; // save current PC - - exc_running_n = 1'b1; + default: + begin + exc_ctrl_ns = IDLE; end - default:; // Nothing endcase end - - always_ff @(posedge clk , negedge rst_n) - begin : UPDATE_REGS - if ( rst_n == 1'b0 ) - begin - exc_running_p <= 1'b0; - new_instr_id_q <= 1'b0; - exc_reason_q <= ExcNone; - end + always_ff @(posedge clk, negedge rst_n) + begin + if (rst_n == 1'b0) + exc_ctrl_cs <= IDLE; else - begin - exc_running_p <= (clear_isr_running_i == 1'b1) ? 1'b0 : exc_running_n; - new_instr_id_q <= ~stall_id_i; - exc_reason_q <= exc_reason_n; - end + exc_ctrl_cs <= exc_ctrl_ns; end + `ifndef SYNTHESIS // synopsys translate_off - // make sure we are called later so that we do not generate messages for - // glitches + // evaluate at falling edge to avoid duplicates during glitches always_ff @(negedge clk) - begin : EXC_DISPLAY - if ( rst_n == 1'b1 ) - begin - if (exc_pc_sel_o) - $display("%t: Entering exception routine.", $time); - end + begin + if (rst_n && req_o && ack_i) + $display("%t: Entering exception routine.", $time); end // synopsys translate_on `endif -endmodule // exc_controller +endmodule diff --git a/id_stage.sv b/id_stage.sv index 13def688..417fcde7 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -56,6 +56,7 @@ module riscv_id_stage output logic pc_set_o, output logic [2:0] pc_mux_sel_o, output logic [1:0] exc_pc_mux_o, + output logic [4:0] exc_vec_pc_mux_o, input logic branch_done_i, @@ -119,9 +120,12 @@ module riscv_id_stage input logic data_misaligned_i, // Interrupt signals - input logic irq_i, - input logic irq_nm_i, + input logic [31:0] irq_i, input logic irq_enable_i, + + output logic [5:0] exc_cause_o, + input logic save_exc_cause_o, + output logic save_pc_if_o, output logic save_pc_id_o, @@ -638,22 +642,17 @@ module riscv_id_stage .branch_decision_i ( branch_decision_i ), - // Interrupt signals - .irq_present_i ( irq_present ), - // Exception Controller Signals - .exc_pc_sel_i ( exc_pc_sel ), - .exc_pipe_flush_i ( exc_pipe_flush ), + .exc_req_i ( exc_req ), + .exc_ack_o ( exc_ack ), .trap_hit_i ( trap_hit ), - .illegal_insn_o ( illegal_insn ), - .clear_isr_running_o ( clear_isr_running ), // Debug Unit Signals .dbg_stall_i ( dbg_stall_i ), .dbg_set_npc_i ( dbg_set_npc_i ), .dbg_trap_o ( dbg_trap_o ), - // Forwarding signals from regfile + // Forwarding signals from regfile .regfile_waddr_ex_i ( regfile_waddr_ex_o ), // Write address for register file from ex-wb- pipeline registers .regfile_we_ex_i ( regfile_we_ex_o ), .regfile_waddr_wb_i ( regfile_waddr_wb_i ), // Write address for register file from ex-wb- pipeline registers @@ -686,8 +685,7 @@ module riscv_id_stage .perf_branch_o ( perf_branch_o ), .perf_jr_stall_o ( perf_jr_stall_o ), .perf_ld_stall_o ( perf_ld_stall_o ) - - ); + ); /////////////////////////////////////////////////////////////////////// // _____ ____ _ _ _ // @@ -700,46 +698,26 @@ module riscv_id_stage riscv_exc_controller exc_controller_i ( - .clk ( clk ), - .rst_n ( rst_n ), + .clk ( clk ), + .rst_n ( rst_n ), - .fetch_enable_i ( fetch_enable_i ), + // to controller + .req_o ( exc_req_o ), + .ack_i ( exc_ack_i ), // to IF stage - .exc_pc_sel_o ( exc_pc_sel ), - .exc_pc_mux_o ( exc_pc_mux_o ), - - .branch_done_i ( branch_done_i ), - - // hwloop signals - .hwloop_enable_o ( hwloop_enable ), + .pc_mux_o ( exc_pc_mux_o ), + .vec_pc_mux_o ( exc_vec_pc_mux_o ), // Interrupt signals - .irq_i ( irq_i ), - .irq_nm_i ( irq_nm_i ), - .irq_enable_i ( irq_enable_i ), - .irq_present_o ( irq_present ), + .irq_i ( irq_i ), + .irq_enable_i ( irq_enable_i ), - // CSR - .save_pc_if_o ( save_pc_if_o ), - .save_pc_id_o ( save_pc_id_o ), + .illegal_insn_i ( illegal_insn ), + .ecall_insn_i ( ecall_insn ), + .eret_insn_i ( eret_insn ), - // Controller - .core_busy_i ( core_busy_o ), - .jump_in_id_i ( jump_in_id_o ), - .jump_in_ex_i ( jump_in_ex_o ), - .stall_id_i ( ~id_valid_o ), - .illegal_insn_i ( illegal_insn ), - .trap_insn_i ( trap_insn ), - .drop_instruction_i ( 1'b0 ), - .clear_isr_running_i ( clear_isr_running ), - .trap_hit_o ( trap_hit ), - .exc_pipe_flush_o ( exc_pipe_flush ), - - // Debug Unit Signals - .dbg_flush_pipe_i ( dbg_flush_pipe_i ), - .dbg_st_en_i ( dbg_st_en_i ), - .dbg_dsr_i ( dbg_dsr_i ) + .cause_o ( exc_cause_o ) ); diff --git a/if_stage.sv b/if_stage.sv index 86231521..f27978d6 100644 --- a/if_stage.sv +++ b/if_stage.sv @@ -65,7 +65,8 @@ module riscv_if_stage input logic pc_set_i, // set the program counter 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 [2:0] pc_mux_sel_i, // sel for pc multiplexer - input logic [1:0] exc_pc_mux_i, // select which exception to execute + input logic [1:0] exc_pc_mux_i, // selects ISR address + input logic [4:0] exc_vec_pc_mux_i, // selects ISR address for vectorized interrupt lines output logic branch_done_o, // we already performed a branch @@ -121,6 +122,7 @@ module riscv_if_stage logic [31:0] instr_rdata_int; logic [31:0] exc_pc; + logic [31:0] irq_pc; // output data and PC mux @@ -146,10 +148,10 @@ module riscv_if_stage always_comb begin : EXC_PC_MUX unique case (exc_pc_mux_i) - `EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:5], `EXC_OFF_ILLINSN }; - `EXC_PC_IRQ: exc_pc = { boot_addr_i[31:5], `EXC_OFF_IRQ }; - `EXC_PC_IRQ_NM: exc_pc = { boot_addr_i[31:5], `EXC_OFF_IRQ_NM }; - default: exc_pc = { boot_addr_i[31:5], `EXC_OFF_RST }; + `EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:8], `EXC_OFF_ILLINSN }; + `EXC_PC_ECALL: exc_pc = { boot_addr_i[31:8], `EXC_OFF_ECALL }; + `EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], 1'b0, exc_vec_pc_mux_i[4:0], 2'b0 }; + default: exc_pc = { boot_addr_i[31:8], `EXC_OFF_ILLINSN }; endcase end @@ -157,7 +159,7 @@ module riscv_if_stage always_comb begin unique case (pc_mux_sel_i) - `PC_BOOT: fetch_addr_n = {boot_addr_i[31:5], `EXC_OFF_RST}; + `PC_BOOT: fetch_addr_n = {boot_addr_i[31:8], `EXC_OFF_RST}; `PC_JUMP: fetch_addr_n = {jump_target_id_i[31:2], 2'b0}; `PC_BRANCH: fetch_addr_n = {jump_target_ex_i[31:2], 2'b0}; `PC_EXCEPTION: fetch_addr_n = exc_pc; // set PC to exception handler diff --git a/include/defines.sv b/include/defines.sv index 2ec59260..8de87ca7 100644 --- a/include/defines.sv +++ b/include/defines.sv @@ -305,23 +305,16 @@ `define PC_DBG_NPC 3'b111 // Exception PC mux selector defines -`define EXC_PC_NO_INCR 2'b00 -`define EXC_PC_ILLINSN 2'b01 +`define EXC_PC_ILLINSN 2'b00 +`define EXC_PC_ECALL 2'b01 `define EXC_PC_IRQ 2'b10 -`define EXC_PC_IRQ_NM 2'b11 // Exceptions offsets -// target address = {boot_addr[31:5], EXC_OFF} (boot_addr must be 32 BYTE aligned!) -`define EXC_OFF_RST 5'h10 -`define EXC_OFF_IRQ 5'h00 -`define EXC_OFF_IRQ_NM 5'h04 -`define EXC_OFF_ILLINSN 5'h08 -// unused 5'h0c - - -// Exception causes -`define EXC_CAUSE_ECALL {1'b0, 4'd11}; -`define EXC_CAUSE_EBREAK {1'b0, 4'd03}; +// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!) +// offset 00 to 7e is used for external interrupts +`define EXC_OFF_RST 8'h80 +`define EXC_OFF_ILLINSN 8'h84 +`define EXC_OFF_ECALL 8'h88 // Hardware loop registers diff --git a/riscv_core.sv b/riscv_core.sv index 3eecc609..74b5329d 100644 --- a/riscv_core.sv +++ b/riscv_core.sv @@ -61,8 +61,7 @@ module riscv_core input logic [31:0] data_rdata_i, // Interrupt inputs - input logic irq_i, // level-triggered IR line - input logic irq_nm_i, // level-triggered IR line for non-maskable IRQ + input logic [31:0] irq_i, // level sensitive IR lines // Debug Interface input logic dbginf_stall_i, @@ -175,6 +174,9 @@ module riscv_core // Interrupts logic irq_enable; logic [31:0] epcr; + + logic [5:0] exc_cause; + logic save_exc_cause; logic save_pc_if; logic save_pc_id; @@ -377,8 +379,9 @@ module riscv_core // Interrupt Signals .irq_i ( irq_i ), // incoming interrupts - .irq_nm_i ( irq_nm_i ), // incoming interrupts .irq_enable_i ( irq_enable ), // global interrupt enable + .exc_cause_o ( exc_cause ), + .save_exc_cause_o ( save_exc_cause ), .save_pc_if_o ( save_pc_if ), // control signal to save pc .save_pc_id_o ( save_pc_id ), // control signal to save pc @@ -552,14 +555,17 @@ module riscv_core .csr_op_i ( csr_op ), .csr_rdata_o ( csr_rdata ), - // Control signals for the core + // Interrupt related control signals + .irq_enable_o ( irq_enable ), + .epcr_o ( epcr ), + .curr_pc_if_i ( current_pc_if ), // from IF stage .curr_pc_id_i ( current_pc_id ), // from IF stage .save_pc_if_i ( save_pc_if ), .save_pc_id_i ( save_pc_id ), - .irq_enable_o ( irq_enable ), - .epcr_o ( epcr ), + .exc_cause_i ( exc_cause ), + .save_exc_cause_i ( save_exc_cause ), // performance counter related signals .id_valid_i ( id_valid ),