Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bhv/cv32e40x_rvfi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ module cv32e40x_rvfi
// performance counters
// cycle, instret, hpcounter, cycleh, instreth, hpcounterh
// mcycle, minstret, mhpcounter, mcycleh, minstreth, mhpcounterh
input logic [31:0] [MHPMCOUNTER_WIDTH-1:0] csr_mhpmcounter_n_i,
input logic [31:0] [MHPMCOUNTER_WIDTH-1:0] csr_mhpmcounter_q_i,
input logic [31:0] [MHPMCOUNTER_WORDS-1:0] csr_mhpmcounter_we_i,
input logic [31:0] [63:0] csr_mhpmcounter_n_i,
input logic [31:0] [63:0] csr_mhpmcounter_q_i,
input logic [31:0] [1:0] csr_mhpmcounter_we_i,

input logic [31:0] csr_mvendorid_i,
input logic [31:0] csr_marchid_i,
Expand Down
3 changes: 0 additions & 3 deletions bhv/include/cv32e40x_rvfi_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
package cv32e40x_rvfi_pkg;
import cv32e40x_pkg::*;

// RVFI only supports MHPMCOUNTER_WIDTH == 64
parameter MHPMCOUNTER_WORDS = MHPMCOUNTER_WIDTH/32;

parameter STAGE_IF = 0;
parameter STAGE_ID = 1;
parameter STAGE_EX = 2;
Expand Down
106 changes: 58 additions & 48 deletions rtl/cv32e40x_clic_int_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -28,50 +28,50 @@

module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
#(
parameter int SMCLIC_ID_WIDTH = 5
parameter int SMCLIC_ID_WIDTH
)
(
input logic clk,
input logic rst_n,

// CLIC interface
input logic clic_irq_i, // CLIC interrupt pending
input logic [SMCLIC_ID_WIDTH-1:0] clic_irq_id_i, // ID of pending interrupt
input logic [7:0] clic_irq_level_i, // Level of pending interrupt
input logic [1:0] clic_irq_priv_i, // Privilege level of pending interrupt
input logic clic_irq_shv_i, // Is pending interrupt vectored?
input logic clic_irq_i, // CLIC interrupt pending
input logic [SMCLIC_ID_WIDTH-1:0] clic_irq_id_i, // ID of pending interrupt
input logic [7:0] clic_irq_level_i, // Level of pending interrupt
input logic [1:0] clic_irq_priv_i, // Privilege level of pending interrupt (always machine mode) (not used)
input logic clic_irq_shv_i, // Is pending interrupt vectored?


// To cv32e40x_controller
// To controller
output logic irq_req_ctrl_o,
output logic [9:0] irq_id_ctrl_o, // Max width - unused bits are tied off
output logic [9:0] irq_id_ctrl_o, // Max width - unused bits are tied off
output logic irq_wu_ctrl_o,
output logic irq_clic_shv_o,
output logic [7:0] irq_clic_level_o,

// From cv32e40x_cs_registers
input logic m_ie_i, // Interrupt enable bit from CSR (M mode)
input logic [7:0] mintthresh_i, // Current interrupt threshold from CSR
input mintstatus_t mintstatus_i, // Current mintstatus from CSR
input mcause_t mcause_i, // Current mcause from CSR

// To cv32e40x_cs_registers
output logic mnxti_irq_pending_o,// An interrupt is available to the mnxti CSR read
output logic [SMCLIC_ID_WIDTH-1:0] mnxti_irq_id_o, // The id of the availble mnxti interrupt
output logic [7:0] mnxti_irq_level_o // Level of the available interrupt
// From cs_registers
input mstatus_t mstatus_i, // Current mstatus from CSR
input logic [7:0] mintthresh_i, // Current interrupt threshold from CSR
input mintstatus_t mintstatus_i, // Current mintstatus from CSR
input mcause_t mcause_i, // Current mcause from CSR
input privlvl_t priv_lvl_i, // Current privilege level of core

// To cs_registers
output logic mnxti_irq_pending_o, // An interrupt is available to the mnxti CSR read
output logic [SMCLIC_ID_WIDTH-1:0] mnxti_irq_id_o, // The id of the availble mnxti interrupt
output logic [7:0] mnxti_irq_level_o // Level of the available interrupt
);

logic global_irq_enable;
logic [7:0] effective_irq_level; // Calculate effective interrupt level

logic [7:0] effective_irq_level; // Effective interrupt level

// Flops for breaking timing path to instruction interface
logic clic_irq_q;
logic [SMCLIC_ID_WIDTH-1:0] clic_irq_id_q;
logic [7:0] clic_irq_level_q;
logic [1:0] clic_irq_priv_q;
logic clic_irq_shv_q;

logic unused_signals;

// Register interrupt input (on gated clock). The wake-up logic will
// observe clic_irq_i as well, but in all other places clic_irq_q will be used to
// avoid timing paths from clic_irq_i to instr_*_o
Expand All @@ -91,50 +91,52 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
if (rst_n == 1'b0) begin
clic_irq_id_q <= '0;
clic_irq_level_q <= '0;
clic_irq_priv_q <= PRIV_LVL_M;
clic_irq_shv_q <= 1'b0;
end else begin
if (clic_irq_i) begin
clic_irq_id_q <= clic_irq_id_i;
clic_irq_level_q <= clic_irq_level_i; // Will always be PRIV_LVL_M todo: add assertion
clic_irq_priv_q <= clic_irq_priv_i;
clic_irq_level_q <= clic_irq_level_i;
clic_irq_shv_q <= clic_irq_shv_i;
end
end
end

// Global interrupt enable
// todo: move logic for m_ie_i from cs_registers to here.
assign global_irq_enable = m_ie_i;
//
// Machine mode interrupts are always enabled when in a lower privilege mode.

assign global_irq_enable = mstatus_i.mie || (priv_lvl_i < PRIV_LVL_M);

// Effective interrupt level
//
// The interrupt-level threshold is only valid when running in the associated privilege mode.

assign effective_irq_level = (mintthresh_i > mintstatus_i.mil) ? mintthresh_i : mintstatus_i.mil;

///////////////////////////
// Outputs to controller //
///////////////////////////

// Request to take interrupt if:
// There is a pending-and-enabled interrupt and interrupts are enabled globally
// AND the incoming irq level is above the core's current effective interrupt level.
// todo: In user mode, machine threshold should not mask interrupts to machine mode
assign irq_req_ctrl_o = clic_irq_q &&
(clic_irq_level_q > effective_irq_level) &&
global_irq_enable;
// Request to take interrupt if there is a pending-and-enabled interrupt, interrupts are enabled globally,
// and the incoming irq level is above the core's current effective interrupt level. Machine mode interrupts
// during user mode shall always be taken if their level is > 0

assign irq_req_ctrl_o = clic_irq_q && global_irq_enable &&
((priv_lvl_i == PRIV_LVL_M) ? (clic_irq_level_q > effective_irq_level) : (clic_irq_level_q > '0));

// Pass on interrupt ID
assign irq_id_ctrl_o = 10'(clic_irq_id_q); // Casting into max with of 10 bits.

// Wake-up signal based on unregistered IRQ such that wake-up can be caused if no clock is present
// SMCLIC spec states three scenarios for wakeup:
// 1: priv mode > current, irq i is max (done in external CLIC), level != 0
// 2: priv mode == current, irq i is max (done in external CLIC), level > max(mintstatus.mil, mintthresh.th)
// 3: priv mode < current, irq_i is max (done in external CLIC), level != 0
//
// 1 is applicable for E40S only as E40X only runs in machine mode
// 2 is applicable for both E40S and E40X
// 3 is not applicable, we support machine mode interrupts only.
// todo: implement (2) for E40S.
// Wakeup scenarios:
//
// - priv mode == current, irq i is max (done in external CLIC), level > max(mintstatus.mil, mintthresh.th)
// - priv mode > current, irq i is max (done in external CLIC), level != 0

// todo: can we share the comparator below and flop the result for irq_req_ctrl_o?
assign irq_wu_ctrl_o = clic_irq_i && (clic_irq_level_i > effective_irq_level);
assign irq_wu_ctrl_o = clic_irq_i &&
((priv_lvl_i == PRIV_LVL_M) ? (clic_irq_level_i > effective_irq_level) : (clic_irq_level_i > '0));

assign irq_clic_shv_o = clic_irq_shv_q;

Expand All @@ -145,16 +147,24 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
///////////////////////////

// The outputs for mnxti will only be used within cs_registers when a CSR instruction is accessing mnxti
assign mnxti_irq_pending_o = (clic_irq_priv_q == PRIV_LVL_M) &&
(clic_irq_level_q > mcause_i.mpil) &&
(clic_irq_level_q > mintthresh_i) &&
!clic_irq_shv_q &&
clic_irq_q;

assign mnxti_irq_pending_o = clic_irq_q &&
(clic_irq_level_q > mcause_i.mpil) &&
(clic_irq_level_q > mintthresh_i) &&
!clic_irq_shv_q;

// If mnxti_irq_pending is true, the currently flopped ID and level will be sent to cs_registers
// for use in the function pointer and CSR side effects.
// Using native SMCLIC_ID_WIDTH for cleaner pointer concatenation in cs_registers.

assign mnxti_irq_id_o = clic_irq_id_q;
assign mnxti_irq_level_o = clic_irq_level_q;

// Unused signals
//
// clic_irq_priv_i is not used on purpose. It is required to be tied to machine mode.
// All interrupts are taken into machine mode.

assign unused_signals = |clic_irq_priv_i;

endmodule
80 changes: 41 additions & 39 deletions rtl/cv32e40x_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ module cv32e40x_core import cv32e40x_pkg::*;

logic [31:0] csr_rdata;
logic csr_counter_read;
logic csr_mnxti_read;

privlvl_t priv_lvl;

logic csr_mnxti_read;

// CLIC signals for returning pointer addresses
// when mnxti is accessed
Expand Down Expand Up @@ -245,10 +248,10 @@ module cv32e40x_core import cv32e40x_pkg::*;
logic wb_valid;

// Interrupts
logic m_irq_enable; // interrupt_controller
logic [31:0] mepc, dpc; // from cs_registers
logic [31:0] mie; // from cs_registers
logic [31:0] mip; // from cs_registers
mstatus_t mstatus;
logic [31:0] mepc, dpc;
logic [31:0] mie;
logic [31:0] mip;

// Signal from IF to init mtvec at boot time
logic csr_mtvec_init_if;
Expand Down Expand Up @@ -685,61 +688,56 @@ module cv32e40x_core import cv32e40x_pkg::*;
.clk ( clk ),
.rst_n ( rst_ni ),

// Hart ID from outside
.mhartid_i ( mhartid_i ),
.mimpid_patch_i ( mimpid_patch_i ),

// Cycle Count
.mcycle_o ( mcycle_o ),
// Configuration
.mhartid_i ( mhartid_i ),
.mimpid_patch_i ( mimpid_patch_i ),
.mtvec_addr_i ( mtvec_addr_i[31:0] ),
.csr_mtvec_init_i ( csr_mtvec_init_if ),

// CSRs
.dcsr_o ( dcsr ),
.dpc_o ( dpc ),
.jvt_addr_o ( jvt_addr ),
.mcause_o ( mcause ),
.mcycle_o ( mcycle_o ),
.mepc_o ( mepc ),
.mie_o ( mie ),
.mintstatus_o ( mintstatus ),
.mintthresh_o ( mintthresh ),
.mstatus_o ( mstatus ),
.mtvec_addr_o ( mtvec_addr ),
.mtvec_mode_o ( mtvec_mode ),

.mtvt_addr_o ( mtvt_addr ),

// mtvec address
.mtvec_addr_i ( mtvec_addr_i[31:0] ),
.csr_mtvec_init_i ( csr_mtvec_init_if ),

.jvt_addr_o ( jvt_addr ),
.priv_lvl_o ( priv_lvl ),

// ID/EX pipeline
.id_ex_pipe_i ( id_ex_pipe ),
.csr_illegal_o ( csr_illegal ),

// EX/WB pipeline
.ex_wb_pipe_i ( ex_wb_pipe ),

// From controller FSM
// From controller_fsm
.ctrl_fsm_i ( ctrl_fsm ),

// Interface to CSRs (SRAM like)
.csr_rdata_o ( csr_rdata ),

.csr_illegal_o (csr_illegal ),

// Raddr from first stage (EX)
// To controller_bypass
.csr_counter_read_o ( csr_counter_read ),
.csr_mnxti_read_o ( csr_mnxti_read ),

// Interrupt related control signals
.mie_o ( mie ),
// Interface to CSRs (SRAM like)
.csr_rdata_o ( csr_rdata ),

// Interrupts
.mip_i ( mip ),
.m_irq_enable_o ( m_irq_enable ),
.mepc_o ( mepc ),
.mintthresh_o ( mintthresh ),
.mintstatus_o ( mintstatus ),
.mcause_o ( mcause ),
.mnxti_irq_pending_i ( mnxti_irq_pending ),
.mnxti_irq_id_i ( mnxti_irq_id ),
.mnxti_irq_level_i ( mnxti_irq_level ),
.clic_pa_valid_o ( csr_clic_pa_valid ),
.clic_pa_o ( csr_clic_pa ),

// debug
.dpc_o ( dpc ),
.dcsr_o ( dcsr ),
// Debug
.trigger_match_o ( trigger_match_if ),

.pc_if_i ( pc_if ),
.ptr_in_if_i ( ptr_in_if )
);
Expand Down Expand Up @@ -882,10 +880,11 @@ module cv32e40x_core import cv32e40x_pkg::*;
.irq_clic_level_o ( irq_clic_level ),

// From cs_registers
.m_ie_i ( m_irq_enable ),
.mstatus_i ( mstatus ),
.mintthresh_i ( mintthresh ),
.mintstatus_i ( mintstatus ),
.mcause_i ( mcause ),
.priv_lvl_i ( priv_lvl ),

// To cs_registers
.mnxti_irq_pending_o ( mnxti_irq_pending ),
Expand All @@ -907,10 +906,13 @@ module cv32e40x_core import cv32e40x_pkg::*;
.irq_id_ctrl_o ( irq_id_ctrl[4:0] ),
.irq_wu_ctrl_o ( irq_wu_ctrl ),

// To/from with cs_registers
// To with cs_registers
.mie_i ( mie ),
.mip_o ( mip ),
.m_ie_i ( m_irq_enable )
.mstatus_i ( mstatus ),
.priv_lvl_i ( priv_lvl ),

// To/from with cs_registers
.mip_o ( mip )
);

// Tie off unused irq_id_ctrl bits
Expand Down
Loading