mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
Initial commit of updated exception controller
Largely untested, but should be wired up correctly.
This commit is contained in:
parent
b957c6f682
commit
c68a098059
7 changed files with 194 additions and 289 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
68
id_stage.sv
68
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 )
|
||||
);
|
||||
|
||||
|
||||
|
|
14
if_stage.sv
14
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue