Initial commit of updated exception controller

Largely untested, but should be wired up correctly.
This commit is contained in:
Sven Stucki 2015-10-16 00:21:20 +02:00
parent b957c6f682
commit c68a098059
7 changed files with 194 additions and 289 deletions

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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 )
);

View file

@ -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

View file

@ -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

View file

@ -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 ),