mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Switch to RISC-V spec compliant trap handling
For exceptions, the Ibex always jumps to the trap vector base address specified in `mtvec`. The exception cause is specified in `mcause` with possibly additional information in `mtval`. Interrupts are handled in vectored mode as before.
This commit is contained in:
parent
e9bdbaddd6
commit
07214f626d
7 changed files with 92 additions and 119 deletions
|
@ -3,28 +3,17 @@
|
|||
Exceptions and Interrupts
|
||||
=========================
|
||||
|
||||
Ibex currently implements a free-form vectored trap handler mechanism for interrupts and exceptions.
|
||||
The base address of the interrupt vector table is given by the boot address (must be aligned to 256 bytes, i.e., its least significant byte must be 0x00).
|
||||
Ibex implements trap handling for interrupts and exceptions according to the RISC-V Privileged Specification, version 1.11.
|
||||
|
||||
All exceptions cause the core to jump to the base address of the vector table in the ``mtvec`` CSR.
|
||||
Interrupts are handled in vectored mode, i.e., the core jumps to the base address plus four times the interrupt cause number.
|
||||
|
||||
The base address of the vector table is given by the boot address (must be aligned to 256 bytes, i.e., its least significant byte must be 0x00).
|
||||
The most significant 3 bytes of the boot address given to the core are used for the first instruction fetch of the core and as the basis of the interrupt vector table.
|
||||
The core starts fetching at the address made by concatenating the most significant 3 bytes of the boot address and the reset value (0x80) as the least significant byte.
|
||||
The boot address can be changed after the first instruction was fetched to change the interrupt vector table address.
|
||||
It is assumed that the boot address is supplied via a register to avoid long paths to the instruction fetch unit.
|
||||
The table below lists the supported interrupts and exceptions and the corresponding address offset in the interrupt vector table.
|
||||
|
||||
+------------+-----------------------------+
|
||||
| Address | Description |
|
||||
+============+=============================+
|
||||
| **0x00** - | Interrupts 0 – 31 |
|
||||
| **0x7C** | |
|
||||
+------------+-----------------------------+
|
||||
| **0x80** | Reset |
|
||||
+------------+-----------------------------+
|
||||
| **0x84** | Illegal Instruction |
|
||||
+------------+-----------------------------+
|
||||
| **0x88** | ECALL Instruction Executed |
|
||||
+------------+-----------------------------+
|
||||
| **0x8C** | LSU Error |
|
||||
+------------+-----------------------------+
|
||||
|
||||
Interrupts
|
||||
----------
|
||||
|
@ -36,9 +25,26 @@ It is assumed that there is a separate event/interrupt controller outside of the
|
|||
When an interrupt is taken, the core gives an acknowledge signal to the external event/interrupt controller as well as the interrupt ID taken.
|
||||
Check :ref:`interrupts` for more details.
|
||||
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
Ibex can trigger an exception due to the following exception causes:
|
||||
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| Exception Code | Description |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 2 | Illegal instruction |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 3 | Breakpoint |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 5 | Load access fault |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 7 | Store access fault |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 11 | Environment call from M-mode (ECALL) |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
|
||||
The illegal instruction exception, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
|
||||
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ module ibex_controller (
|
|||
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
|
||||
|
@ -160,15 +159,14 @@ module ibex_controller (
|
|||
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;
|
||||
|
||||
pc_mux_o = PC_BOOT;
|
||||
pc_set_o = 1'b0;
|
||||
|
||||
exc_pc_mux_o = EXC_PC_IRQ;
|
||||
exc_cause_o = EXC_CAUSE_INSN_ADDR_MISA; // = 6'h00
|
||||
|
||||
ctrl_fsm_ns = ctrl_fsm_cs;
|
||||
|
||||
ctrl_busy_o = 1'b1;
|
||||
|
@ -319,15 +317,13 @@ module ibex_controller (
|
|||
end
|
||||
|
||||
IRQ_TAKEN: begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
|
||||
exc_pc_mux_o = EXC_PC_IRQ;
|
||||
exc_cause_o = exc_cause_e'({1'b0, irq_id_ctrl_i});
|
||||
exc_cause_o = exc_cause_e'({1'b1, irq_id_ctrl_i});
|
||||
|
||||
csr_save_cause_o = 1'b1;
|
||||
csr_cause_o = exc_cause_e'({1'b1, irq_id_ctrl_i});
|
||||
|
||||
csr_save_if_o = 1'b1;
|
||||
|
||||
irq_ack_o = 1'b1;
|
||||
|
@ -340,7 +336,7 @@ module ibex_controller (
|
|||
DBG_TAKEN_IF:
|
||||
begin
|
||||
// Jump to debug exception handler in debug memory
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_DBD;
|
||||
|
||||
|
@ -372,7 +368,7 @@ module ibex_controller (
|
|||
// not to the next instruction's (which is why we save the pc in id).
|
||||
DBG_TAKEN_ID: begin
|
||||
// Jump to debug exception handler in debug memory
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_DBD;
|
||||
|
||||
|
@ -414,27 +410,25 @@ module ibex_controller (
|
|||
unique case(1'b1)
|
||||
ecall_insn_i: begin
|
||||
//ecall
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_EXC;
|
||||
exc_cause_o = EXC_CAUSE_ECALL_MMODE;
|
||||
csr_save_id_o = 1'b1;
|
||||
csr_save_cause_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_ECALL;
|
||||
exc_cause_o = EXC_CAUSE_ECALL_MMODE;
|
||||
csr_cause_o = EXC_CAUSE_ECALL_MMODE;
|
||||
end
|
||||
illegal_insn_i: begin
|
||||
//exceptions
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
csr_save_id_o = 1'b1;
|
||||
csr_save_cause_o = 1'b1;
|
||||
if (debug_mode_q) begin
|
||||
exc_pc_mux_o = EXC_PC_DBGEXC;
|
||||
exc_pc_mux_o = EXC_PC_DBG_EXC;
|
||||
end else begin
|
||||
exc_pc_mux_o = EXC_PC_ILLINSN;
|
||||
exc_pc_mux_o = EXC_PC_EXC;
|
||||
end
|
||||
exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
|
||||
csr_cause_o = EXC_CAUSE_ILLEGAL_INSN;
|
||||
csr_save_id_o = 1'b1;
|
||||
csr_save_cause_o = 1'b1;
|
||||
csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i;
|
||||
end
|
||||
mret_insn_i: begin
|
||||
|
@ -478,33 +472,30 @@ module ibex_controller (
|
|||
* ECALL or EBREAK instruction itself, not the address of the
|
||||
* following instruction." (Privileged Spec, p. 40)
|
||||
*/
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_EXC;
|
||||
exc_cause_o = EXC_CAUSE_BREAKPOINT;
|
||||
csr_save_id_o = 1'b1;
|
||||
csr_save_cause_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_BREAKPOINT;
|
||||
exc_cause_o = EXC_CAUSE_BREAKPOINT;
|
||||
csr_cause_o = EXC_CAUSE_BREAKPOINT;
|
||||
end
|
||||
end
|
||||
load_err_q: begin
|
||||
pc_mux_o = PC_EXCEPTION;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_EXC;
|
||||
exc_cause_o = EXC_CAUSE_LOAD_ACCESS_FAULT;
|
||||
csr_save_id_o = 1'b1;
|
||||
csr_save_cause_o = 1'b1;
|
||||
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;
|
||||
pc_mux_o = PC_EXC;
|
||||
pc_set_o = 1'b1;
|
||||
exc_pc_mux_o = EXC_PC_EXC;
|
||||
exc_cause_o = EXC_CAUSE_STORE_ACCESS_FAULT;
|
||||
csr_save_id_o = 1'b1;
|
||||
csr_save_cause_o = 1'b1;
|
||||
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
|
||||
|
||||
|
|
|
@ -119,7 +119,6 @@ module ibex_core #(
|
|||
|
||||
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
|
||||
|
@ -197,16 +196,15 @@ module ibex_core #(
|
|||
|
||||
// Interrupts
|
||||
logic m_irq_enable;
|
||||
logic [31:0] mepc, depc;
|
||||
logic [31:0] csr_mepc, csr_depc;
|
||||
|
||||
logic csr_save_if;
|
||||
logic csr_save_id;
|
||||
logic csr_restore_mret_id;
|
||||
logic csr_restore_dret_id;
|
||||
logic csr_save_cause;
|
||||
exc_cause_e csr_cause;
|
||||
logic [31:0] csr_mtval;
|
||||
logic [31:0] csr_mtvec;
|
||||
logic [31:0] csr_mtval;
|
||||
|
||||
// debug mode and dcsr configuration
|
||||
dbg_cause_e debug_cause;
|
||||
|
@ -325,15 +323,16 @@ module ibex_core #(
|
|||
// 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
|
||||
.pc_mux_i ( pc_mux_id ),
|
||||
.exc_pc_mux_i ( exc_pc_mux_id ),
|
||||
.exc_vec_pc_mux_i ( exc_cause ),
|
||||
.exc_cause ( exc_cause ),
|
||||
|
||||
// Jump targets
|
||||
// jump targets
|
||||
.jump_target_ex_i ( jump_target_ex ),
|
||||
|
||||
// CSRs
|
||||
.csr_mepc_i ( csr_mepc ), // exception return address
|
||||
.csr_depc_i ( csr_depc ), // debug return address
|
||||
.csr_mtvec_o ( csr_mtvec ), // trap-vector base address
|
||||
|
||||
// pipeline stalls
|
||||
|
@ -414,7 +413,6 @@ module ibex_core #(
|
|||
.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 ),
|
||||
|
||||
|
@ -583,12 +581,12 @@ module ibex_core #(
|
|||
|
||||
// Interrupt related control signals
|
||||
.m_irq_enable_o ( m_irq_enable ),
|
||||
.mepc_o ( mepc ),
|
||||
.csr_mepc_o ( csr_mepc ),
|
||||
|
||||
// debug
|
||||
.csr_depc_o ( csr_depc ),
|
||||
.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 ),
|
||||
|
||||
|
@ -600,9 +598,9 @@ module ibex_core #(
|
|||
.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 ),
|
||||
.csr_mtvec_i ( csr_mtvec ),
|
||||
.csr_mcause_i ( exc_cause ),
|
||||
.csr_mtval_i ( csr_mtval ),
|
||||
.illegal_csr_insn_o ( illegal_csr_insn_id ),
|
||||
|
||||
// performance counter related signals
|
||||
|
|
|
@ -48,12 +48,12 @@ module ibex_cs_registers #(
|
|||
|
||||
// Interrupts
|
||||
output logic m_irq_enable_o,
|
||||
output logic [31:0] mepc_o,
|
||||
output logic [31:0] csr_mepc_o,
|
||||
|
||||
// debug
|
||||
input ibex_defines::dbg_cause_e debug_cause_i,
|
||||
input logic debug_csr_save_i,
|
||||
output logic [31:0] depc_o,
|
||||
output logic [31:0] csr_depc_o,
|
||||
output logic debug_single_step_o,
|
||||
output logic debug_ebreakm_o,
|
||||
|
||||
|
@ -65,9 +65,9 @@ module ibex_cs_registers #(
|
|||
input logic csr_restore_mret_i,
|
||||
input logic csr_restore_dret_i,
|
||||
input logic csr_save_cause_i,
|
||||
input logic [31:0] csr_mtval_i,
|
||||
input logic [31:0] csr_mtvec_i,
|
||||
input ibex_defines::exc_cause_e csr_cause_i,
|
||||
input ibex_defines::exc_cause_e csr_mcause_i,
|
||||
input logic [31:0] csr_mtval_i,
|
||||
|
||||
output logic illegal_csr_insn_o, // access to non-existent CSR,
|
||||
// with wrong priviledge level, or
|
||||
|
@ -421,7 +421,7 @@ module ibex_cs_registers #(
|
|||
mstatus_n.mie = 1'b0;
|
||||
mstatus_n.mpp = PRIV_LVL_M;
|
||||
mepc_n = exception_pc;
|
||||
mcause_n = {csr_cause_i};
|
||||
mcause_n = {csr_mcause_i};
|
||||
mtval_n = csr_mtval_i;
|
||||
end
|
||||
end //csr_save_cause_i
|
||||
|
@ -465,9 +465,9 @@ module ibex_cs_registers #(
|
|||
assign csr_rdata_o = csr_rdata_int;
|
||||
|
||||
// directly output some registers
|
||||
assign m_irq_enable_o = mstatus_q.mie;
|
||||
assign mepc_o = mepc_q;
|
||||
assign depc_o = depc_q;
|
||||
assign m_irq_enable_o = mstatus_q.mie;
|
||||
assign csr_mepc_o = mepc_q;
|
||||
assign csr_depc_o = depc_q;
|
||||
|
||||
assign debug_single_step_o = dcsr_q.step;
|
||||
assign debug_ebreakm_o = dcsr_q.ebreakm;
|
||||
|
|
|
@ -162,21 +162,17 @@ typedef enum logic [2:0] {
|
|||
typedef enum logic [2:0] {
|
||||
PC_BOOT,
|
||||
PC_JUMP,
|
||||
PC_EXCEPTION,
|
||||
PC_EXC,
|
||||
PC_ERET,
|
||||
PC_DRET
|
||||
} pc_sel_e;
|
||||
|
||||
// Exception PC mux selection
|
||||
typedef enum logic [2:0] {
|
||||
EXC_PC_ILLINSN,
|
||||
EXC_PC_ECALL,
|
||||
EXC_PC_LOAD,
|
||||
EXC_PC_STORE,
|
||||
typedef enum logic [1:0] {
|
||||
EXC_PC_EXC,
|
||||
EXC_PC_IRQ,
|
||||
EXC_PC_DBD,
|
||||
EXC_PC_DBGEXC, // Exception while in debug mode
|
||||
EXC_PC_BREAKPOINT
|
||||
EXC_PC_DBG_EXC // Exception while in debug mode
|
||||
} exc_pc_sel_e;
|
||||
|
||||
// Exception cause
|
||||
|
@ -189,21 +185,6 @@ typedef enum logic [5:0] {
|
|||
EXC_CAUSE_ECALL_MMODE = 6'h0B
|
||||
} exc_cause_e;
|
||||
|
||||
// Exceptions offsets
|
||||
// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
|
||||
// offset 00 to 7e is used for external interrupts
|
||||
|
||||
// TODO: The behavior below follows an outdated (pre-1.10) RISC-V Privileged
|
||||
// Spec to implement a "free-form" vectored trap handler.
|
||||
// We need to update this code and crt0.S to follow the new mtvec spec.
|
||||
typedef enum logic [7:0] {
|
||||
EXC_OFF_RST = 8'h80,
|
||||
EXC_OFF_ILLINSN = 8'h84,
|
||||
EXC_OFF_ECALL = 8'h88,
|
||||
EXC_OFF_LSUERR = 8'h8c,
|
||||
EXC_OFF_BREAKPOINT = 8'h90
|
||||
} exc_off_e;
|
||||
|
||||
// Debug cause
|
||||
typedef enum logic [2:0] {
|
||||
DBG_CAUSE_NONE = 3'h0,
|
||||
|
|
|
@ -98,7 +98,6 @@ module ibex_id_stage #(
|
|||
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,
|
||||
|
||||
|
@ -528,7 +527,6 @@ module ibex_id_stage #(
|
|||
.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
|
||||
|
|
|
@ -63,13 +63,13 @@ module ibex_if_stage #(
|
|||
// 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, // PC to restore after handling
|
||||
input logic [31:0] csr_mepc_i, // PC to restore after handling
|
||||
// the interrupt/exception
|
||||
input logic [31:0] depc_i, // PC to restore after handling
|
||||
input logic [31:0] csr_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
|
||||
input ibex_defines::exc_cause_e exc_cause, // selects ISR address for
|
||||
// vectorized interrupt lines
|
||||
|
||||
// jump and branch target and decision
|
||||
|
@ -105,37 +105,36 @@ module ibex_if_stage #(
|
|||
|
||||
logic [31:0] exc_pc;
|
||||
|
||||
logic [5:0] irq_id;
|
||||
logic unused_irq_bit;
|
||||
|
||||
// extract interrupt ID from exception cause
|
||||
assign irq_id = {exc_cause};
|
||||
assign unused_irq_bit = irq_id[5]; // MSB distinguishes interrupts from exceptions
|
||||
|
||||
// trap-vector base address, mtvec.MODE set to vectored
|
||||
assign csr_mtvec_o = {boot_addr_i[31:8], 6'b0, 2'b01};
|
||||
|
||||
// exception PC selection mux
|
||||
always_comb begin : exc_pc_mux
|
||||
// TODO: The behavior below follows an outdated (pre-1.10) RISC-V Privileged
|
||||
// Spec to implement a "free-form" vectored trap handler.
|
||||
// We need to update this code and crt0.S to follow the new mtvec spec.
|
||||
unique case (exc_pc_mux_i)
|
||||
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_LOAD: exc_pc = { boot_addr_i[31:8], {EXC_OFF_LSUERR} };
|
||||
EXC_PC_STORE: exc_pc = { boot_addr_i[31:8], {EXC_OFF_LSUERR} };
|
||||
EXC_PC_BREAKPOINT: exc_pc = { boot_addr_i[31:8], {EXC_OFF_BREAKPOINT} };
|
||||
EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], {exc_vec_pc_mux_i}, 2'b0 };
|
||||
EXC_PC_DBD: exc_pc = DmHaltAddr;
|
||||
EXC_PC_DBGEXC: exc_pc = DmExceptionAddr;
|
||||
default: exc_pc = 'X;
|
||||
EXC_PC_EXC: exc_pc = { boot_addr_i[31:8], 8'h00 };
|
||||
EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], 1'b0, irq_id[4:0], 2'b00 };
|
||||
EXC_PC_DBD: exc_pc = DmHaltAddr;
|
||||
EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr;
|
||||
default: exc_pc = 'X;
|
||||
endcase
|
||||
end
|
||||
|
||||
// fetch address selection mux
|
||||
always_comb begin : fetch_addr_mux
|
||||
unique case (pc_mux_i)
|
||||
PC_BOOT: fetch_addr_n = {boot_addr_i[31:8], {EXC_OFF_RST}};
|
||||
PC_JUMP: fetch_addr_n = jump_target_ex_i;
|
||||
PC_EXCEPTION: fetch_addr_n = exc_pc; // set PC to exception handler
|
||||
PC_ERET: fetch_addr_n = exception_pc_reg_i; // PC is restored when returning
|
||||
// from IRQ/exception
|
||||
PC_DRET: fetch_addr_n = depc_i;
|
||||
default: fetch_addr_n = 'X;
|
||||
PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
|
||||
PC_JUMP: fetch_addr_n = jump_target_ex_i;
|
||||
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
|
||||
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
|
||||
PC_DRET: fetch_addr_n = csr_depc_i;
|
||||
default: fetch_addr_n = 'X;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue