Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of mnxti #506

Merged
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
2 changes: 1 addition & 1 deletion bhv/cv32e40x_rvfi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ module cv32e40x_rvfi
// Interrupt Controller probes
input logic [31:0] irq_i,
input logic irq_wu_ctrl_i,
input logic [4:0] irq_id_ctrl_i,
input logic [9:0] irq_id_ctrl_i,

//// CSR Probes ////
input jvt_t csr_jvt_n_i,
Expand Down
33 changes: 28 additions & 5 deletions rtl/cv32e40x_clic_int_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
// 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 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
);

logic global_irq_enable;
Expand All @@ -61,7 +67,7 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;

// Flops for breaking timing path to instruction interface
logic clic_irq_q;
logic [9:0] clic_irq_id_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;
Expand All @@ -79,7 +85,7 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
end
end


// Flop all irq inputs to break timing paths through the controller.
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0) begin
Expand All @@ -89,7 +95,7 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
clic_irq_shv_q <= 1'b0;
end else begin
if (clic_irq_i) begin
clic_irq_id_q <= 10'(clic_irq_id_i); // Casting SMCLIC_ID_WIDTH into max with of 10 bits.
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_shv_q <= clic_irq_shv_i;
Expand All @@ -115,7 +121,7 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;
global_irq_enable;

// Pass on interrupt ID
assign irq_id_ctrl_o = clic_irq_id_q;
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:
Expand All @@ -134,4 +140,21 @@ module cv32e40x_clic_int_controller import cv32e40x_pkg::*;

assign irq_clic_level_o = clic_irq_level_q;

///////////////////////////
// Outputs for mnxti CSR //
///////////////////////////

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

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

endmodule // cv32e40x_clic_int_controller
37 changes: 32 additions & 5 deletions rtl/cv32e40x_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,16 @@ module cv32e40x_core import cv32e40x_pkg::*;
logic [7:0] mintthresh;
mintstatus_t mintstatus;

mcause_t mcause;

logic [31:0] csr_rdata;
logic csr_counter_read;

// CLIC signals for returning pointer addresses
// when mnxti is accessed
logic csr_clic_pa_valid; // A CSR access to mnxti has a valid ponter address
logic [31:0] csr_clic_pa; // Pointer address returned by accessing mnxti

// LSU
logic lsu_split_ex;
mpu_status_e lsu_mpu_status_wb;
Expand Down Expand Up @@ -265,8 +272,11 @@ module cv32e40x_core import cv32e40x_pkg::*;
logic irq_wu_ctrl;

// CLIC specific irq signals
logic irq_clic_shv;
logic [7:0] irq_clic_level;
logic irq_clic_shv;
logic [7:0] irq_clic_level;
logic mnxti_irq_pending;
logic [SMCLIC_ID_WIDTH-1:0] mnxti_irq_id;
logic [7:0] mnxti_irq_level;

// Used (only) by verification environment
logic irq_ack;
Expand Down Expand Up @@ -626,7 +636,11 @@ module cv32e40x_core import cv32e40x_pkg::*;
.wb_valid_o ( wb_valid ),

// eXtension interface
.xif_result_if ( xif_result_if )
.xif_result_if ( xif_result_if ),

// CSR/CLIC pointer inputs
.clic_pa_valid_i ( csr_clic_pa_valid ),
.clic_pa_i ( csr_clic_pa )
);

//////////////////////////////////////
Expand All @@ -649,6 +663,7 @@ module cv32e40x_core import cv32e40x_pkg::*;
.X_ECS_XS ( X_ECS_XS ),
.ZC_EXT ( ZC_EXT ),
.SMCLIC ( SMCLIC ),
.SMCLIC_ID_WIDTH ( SMCLIC_ID_WIDTH ),
.DBG_NUM_TRIGGERS ( DBG_NUM_TRIGGERS ),
.NUM_MHPMCOUNTERS ( NUM_MHPMCOUNTERS ),
.MTVT_ADDR_WIDTH ( MTVT_ADDR_WIDTH )
Expand Down Expand Up @@ -698,6 +713,12 @@ module cv32e40x_core import cv32e40x_pkg::*;
.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 ),
Expand Down Expand Up @@ -840,10 +861,16 @@ module cv32e40x_core import cv32e40x_pkg::*;
.irq_clic_shv_o ( irq_clic_shv ),
.irq_clic_level_o ( irq_clic_level ),

// From with cv32e40x_cs_registers
// From cv32e40x_cs_registers
.m_ie_i ( m_irq_enable ),
.mintthresh_i ( mintthresh ),
.mintstatus_i ( mintstatus )
.mintstatus_i ( mintstatus ),
.mcause_i ( mcause ),

// To cv32e40x_cs_registers
.mnxti_irq_pending_o ( mnxti_irq_pending ),
.mnxti_irq_id_o ( mnxti_irq_id ),
.mnxti_irq_level_o ( mnxti_irq_level )
);
end else begin : gen_basic_interrupt
cv32e40x_int_controller
Expand Down
85 changes: 66 additions & 19 deletions rtl/cv32e40x_cs_registers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
parameter logic [1:0] X_ECS_XS = 2'b00, // todo: implement related mstatus bitfields (but only if X_EXT = 1)
parameter bit ZC_EXT = 0, // todo: remove parameter once fully implemented
parameter bit SMCLIC = 0,
parameter int SMCLIC_ID_WIDTH = 5,
parameter int NUM_MHPMCOUNTERS = 1,
parameter int DBG_NUM_TRIGGERS = 1, // todo: implement support for DBG_NUM_TRIGGERS != 1
parameter int unsigned MTVT_ADDR_WIDTH = 26
Expand Down Expand Up @@ -83,12 +84,21 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
// To EX stage
output logic csr_illegal_o, // 1'b1 for illegal CSR access.

// To WB stage
output logic clic_pa_valid_o, // CSR read data is an address to a function pointer
output logic [31:0] clic_pa_o, // Address to CLIC function pointer

// Interrupts
output logic [31:0] mie_o,
input logic [31:0] mip_i,
output logic m_irq_enable_o,
output logic [7:0] mintthresh_o,
output mintstatus_t mintstatus_o,
output mcause_t mcause_o,

input logic mnxti_irq_pending_i,
input logic [SMCLIC_ID_WIDTH-1:0] mnxti_irq_id_i,
input logic [7:0] mnxti_irq_level_i,

output logic [31:0] mepc_o,

Expand Down Expand Up @@ -168,7 +178,6 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
mtvt_t mtvt_n, mtvt_q;
logic mtvt_we, mtvt_rd_error;

logic [31:0] mnxti_q, mnxti_n;
logic mnxti_we;

mintstatus_t mintstatus_q, mintstatus_n;
Expand Down Expand Up @@ -348,7 +357,10 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
// mnxti: Next Interrupt Handler Address and Interrupt Enable
CSR_MNXTI: begin
if (SMCLIC) begin
csr_rdata_int = mnxti_q;
// The data read here is what will be used in the read-modify-write portion of the CSR access.
// For mnxti, this is actually mstatus. The value written back to the GPR will be the address of
// the function pointer to the interrupt handler. This is muxed in the WB stage.
csr_rdata_int = mstatus_q;
end else begin
csr_rdata_int = '0;
illegal_csr_read = 1'b1;
Expand Down Expand Up @@ -564,17 +576,6 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
mie: csr_wdata_int[MSTATUS_MIE_BIT],
default: 'b0
};
// CLIC mode is assumed when SMCLIC = 1
// In CLIC mode, writes to mcause.mpp/mpie is aliased to mstatus.mpp/mpie
if (SMCLIC) begin
if (mcause_we) begin
mstatus_n = mstatus_q; // Preserve all fields

// Write mpie and mpp as aliased through mcause
mstatus_n.mpie = csr_wdata_int[MCAUSE_MPIE_BIT];
mstatus_n.mpp = PRIV_LVL_M; // todo: handle priv mode for E40S
end
end

mstatus_we = 1'b0;

Expand All @@ -592,7 +593,6 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
mtvt_n = {csr_wdata_int[31:(32-MTVT_ADDR_WIDTH)], {(32-MTVT_ADDR_WIDTH){1'b0}}};
mtvt_we = 1'b0;

mnxti_n = '0; // todo: implement
mnxti_we = 1'b0;

mintstatus_n = mintstatus_q; // All fields of mintstatus are read only
Expand Down Expand Up @@ -627,7 +627,6 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
mtvt_n = '0;
mtvt_we = 1'b0;

mnxti_n = '0;
mnxti_we = 1'b0;

mintstatus_n = '0;
Expand Down Expand Up @@ -709,6 +708,18 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
CSR_MNXTI: begin
if (SMCLIC) begin
mnxti_we = 1'b1;

// Writes to mnxti also writes to mstatus
mstatus_we = 1'b1;

// Writes to mintstatus.mil and mcause depend on the current state of
// clic interrupts AND the type of CSR instruction used.
// Side effects occur when there is an actual write to the mstatus CSR
// This is already coded into the csr_we_int/mnxti_we
if (mnxti_irq_pending_i) begin
mintstatus_we = 1'b1;
mcause_we = 1'b1;
end
end
end
CSR_MINTSTATUS: begin
Expand Down Expand Up @@ -752,6 +763,45 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
endcase
end

// CSR side effects from other CSRs
// All write enables are already calculated at this point

// CLIC mode is assumed when SMCLIC = 1
if (SMCLIC) begin
if (mnxti_we) begin
// mintstatus and mcause are updated if an actual mstatus write happens and
// a higher level non-shv interrupt is pending.
// This is already decoded into the respective _we signals below.
if (mintstatus_we) begin
mintstatus_n.mil = mnxti_irq_level_i;
end
if (mcause_we) begin
mcause_n = mcause_q;
mcause_n.irq = 1'b1;
mcause_n.exception_code = {1'b0, 10'(mnxti_irq_id_i)};
end
end else if (mcause_we) begin
// In CLIC mode, writes to mcause.mpp/mpie is aliased to mstatus.mpp/mpie
// All other mstatus bits are preserved
mstatus_n = mstatus_q; // Preserve all fields

// Write mpie and mpp as aliased through mcause
mstatus_n.mpie = csr_wdata_int[MCAUSE_MPIE_BIT];
mstatus_n.mpp = PRIV_LVL_M; // todo: handle priv mode for E40S
end
// The CLIC pointer address should always be output for an access to MNXTI,
// but will only contain a nonzero value if a CLIC interrupt is actually pending
// with a higher level. The valid below will be high also for the cases where
// no side effects occur.
clic_pa_valid_o = csr_en_gated && (csr_waddr == CSR_MNXTI);
clic_pa_o = mnxti_irq_pending_i ? {mtvt_addr_o, mnxti_irq_id_i, 2'b00} : 32'h00000000;
end else begin
clic_pa_valid_o = 1'b0;
clic_pa_o = '0;
end



// exception controller gets priority over other writes
unique case (1'b1)

Expand Down Expand Up @@ -968,7 +1018,7 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
.rd_error_o (mcause_rd_error)
);


assign mcause_o = mcause_q;



Expand Down Expand Up @@ -1002,8 +1052,6 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;

assign mtvt_addr_o = mtvt_q.addr[31:(32-MTVT_ADDR_WIDTH)];

assign mnxti_q = 32'h0; // todo: implement mnxti functionality

cv32e40x_csr #(
.WIDTH (32),
.SHADOWCOPY (1'b0),
Expand Down Expand Up @@ -1095,7 +1143,6 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
);
assign mtvt_q = 32'h0;
assign mtvt_rd_error = 1'b0;
assign mnxti_q = 32'h0;
assign mintstatus_q = 32'h0;
assign mintstatus_rd_error = 1'b0;
assign mintthresh_q = 32'h0;
Expand Down
11 changes: 9 additions & 2 deletions rtl/cv32e40x_wb_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ module cv32e40x_wb_stage import cv32e40x_pkg::*;
output logic wb_valid_o,

// eXtension interface
if_xif.cpu_result xif_result_if
if_xif.cpu_result xif_result_if,

// From cs_registers
input logic [31:0] clic_pa_i,
input logic clic_pa_valid_i
);

logic instr_valid;
Expand Down Expand Up @@ -105,7 +109,10 @@ module cv32e40x_wb_stage import cv32e40x_pkg::*;
// TODO: Could use result interface.rd into account if out of order completion is allowed.
assign rf_waddr_wb_o = ex_wb_pipe_i.rf_waddr;
// TODO: Could use result interface.rd into account if out of order completion is allowed.
assign rf_wdata_wb_o = ex_wb_pipe_i.lsu_en ? lsu_rdata_i : (ex_wb_pipe_i.xif_en ? xif_result_if.result.data : ex_wb_pipe_i.rf_wdata);
assign rf_wdata_wb_o = ex_wb_pipe_i.lsu_en ? lsu_rdata_i :
(ex_wb_pipe_i.xif_en ? xif_result_if.result.data :
clic_pa_valid_i ? clic_pa_i :
ex_wb_pipe_i.rf_wdata);

//////////////////////////////////////////////////////////////////////////////
// LSU inputs are valid when LSU is enabled; LSU outputs need to remain valid until downstream stage is ready
Expand Down