Skip to content

Commit

Permalink
Merge pull request #285 from silabs-oysteink/silabs-oysteink_merge-w34-2
Browse files Browse the repository at this point in the history
Merge from CV32E40X
  • Loading branch information
Silabs-ArjanB authored Aug 26, 2022
2 parents d002893 + 12be5b5 commit b8d1efb
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 3 deletions.
8 changes: 8 additions & 0 deletions bhv/cv32e40s_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ module cv32e40s_wrapper
.ctrl_pending_debug (core_i.controller_i.controller_fsm_i.pending_debug),
.ctrl_debug_allowed (core_i.controller_i.controller_fsm_i.debug_allowed),
.id_stage_multi_op_id_stall (core_i.id_stage_i.multi_op_id_stall),
.ctrl_pending_nmi (core_i.controller_i.controller_fsm_i.pending_nmi),
.ctrl_pending_interrupt (core_i.controller_i.controller_fsm_i.pending_interrupt),
.ctrl_interrupt_allowed (core_i.controller_i.controller_fsm_i.interrupt_allowed),

.id_stage_id_valid (core_i.id_stage_i.id_valid_o),
.priv_lvl_if (core_i.if_stage_i.prefetch_priv_lvl),
.priv_lvl_if_q (core_i.if_stage_i.prefetch_unit_i.alignment_buffer_i.instr_priv_lvl_q),
Expand All @@ -328,6 +332,10 @@ module cv32e40s_wrapper
.jumpr_self_stall_bypass (core_i.controller_i.bypass_i.jumpr_self_stall),
.last_sec_op_id_i (core_i.id_stage_i.last_sec_op),
.last_op_id (core_i.id_stage_i.last_op),
.mie_n (core_i.cs_registers_i.mie_n),
.mie_we (core_i.cs_registers_i.mie_we),
.clic_irq_q (core_i.gen_clic_interrupt.clic_int_controller_i.clic_irq_q),
.clic_irq_level_q (core_i.gen_clic_interrupt.clic_int_controller_i.clic_irq_level_q),
.*);

bind cv32e40s_sleep_unit:
Expand Down
3 changes: 3 additions & 0 deletions rtl/cv32e40s_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ module cv32e40s_controller import cv32e40s_pkg::*;
input logic csr_counter_read_i, // A performance counter is read in CSR (EX)
input logic csr_mnxti_read_i, // MNXTI is read in CSR (EX)

input logic csr_irq_enable_write_i, // An interrupt may be enabled by a write (WB)

input logic [REGFILE_NUM_READ_PORTS-1:0] rf_re_id_i,
input rf_addr_t rf_raddr_id_i[REGFILE_NUM_READ_PORTS],

Expand Down Expand Up @@ -255,6 +257,7 @@ module cv32e40s_controller import cv32e40s_pkg::*;

// From WB
.wb_ready_i ( wb_ready_i ),
.csr_irq_enable_write_i ( csr_irq_enable_write_i ),

// Outputs
.ctrl_byp_o ( ctrl_byp_o )
Expand Down
7 changes: 7 additions & 0 deletions rtl/cv32e40s_controller_bypass.sv
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ module cv32e40s_controller_bypass import cv32e40s_pkg::*;

// From WB
input logic wb_ready_i, // WB stage is ready
input logic csr_irq_enable_write_i, // WB is writing to a CSR that may enable an interrupt.

// Controller Bypass outputs
output ctrl_byp_t ctrl_byp_o
Expand Down Expand Up @@ -208,6 +209,7 @@ module cv32e40s_controller_bypass import cv32e40s_pkg::*;
ctrl_byp_o.deassert_we = 1'b0;
ctrl_byp_o.csr_stall = 1'b0;
ctrl_byp_o.minstret_stall = 1'b0;
ctrl_byp_o.irq_enable_stall = 1'b0;

// deassert WE when the core has an exception in ID (ins converted to nop and propagated to WB)
// Also deassert for trigger match, as with dcsr.timing==0 we do not execute before entering debug mode
Expand Down Expand Up @@ -250,6 +252,11 @@ module cv32e40s_controller_bypass import cv32e40s_pkg::*;
if (csr_counter_read_i && ex_wb_pipe_i.instr_valid) begin
ctrl_byp_o.minstret_stall = 1'b1;
end

// Stall EX when an interrupt may be enabled from WB while there is a LSU instruction in EX.
if (csr_irq_enable_write_i && (id_ex_pipe_i.instr_valid && id_ex_pipe_i.lsu_en)) begin
ctrl_byp_o.irq_enable_stall = 1'b1;
end
end

assign ctrl_byp_o.id_stage_abort = ctrl_byp_o.deassert_we;
Expand Down
3 changes: 2 additions & 1 deletion rtl/cv32e40s_controller_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,8 @@ module cv32e40s_controller_fsm import cv32e40s_pkg::*;
// Halting EX if minstret_stall occurs. Otherwise we would read the wrong minstret value
// Also halting EX if an offloaded instruction in WB may cause an exception, such that a following offloaded
// instruction can correctly receive commit_kill.
ctrl_fsm_o.halt_ex = ctrl_byp_i.minstret_stall || ctrl_byp_i.xif_exception_stall;
// Halting EX when an instruction in WB may cause an interrupt to become pending.
ctrl_fsm_o.halt_ex = ctrl_byp_i.minstret_stall || ctrl_byp_i.xif_exception_stall || ctrl_byp_i.irq_enable_stall;
ctrl_fsm_o.halt_wb = 1'b0;

// By default no stages are killed
Expand Down
3 changes: 3 additions & 0 deletions rtl/cv32e40s_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ module cv32e40s_core import cv32e40s_pkg::*;
logic [31:0] csr_rdata;
logic csr_counter_read;
logic csr_wr_in_wb_flush;
logic csr_irq_enable_write;

privlvl_t priv_lvl_lsu;
privlvl_t priv_lvl_clic_ptr;
Expand Down Expand Up @@ -917,6 +918,7 @@ module cv32e40s_core import cv32e40s_pkg::*;
// To controller_bypass
.csr_counter_read_o ( csr_counter_read ),
.csr_mnxti_read_o ( csr_mnxti_read ),
.csr_irq_enable_write_o ( csr_irq_enable_write ),

// Interface to CSRs (SRAM like)
.csr_rdata_o ( csr_rdata ),
Expand Down Expand Up @@ -977,6 +979,7 @@ module cv32e40s_core import cv32e40s_pkg::*;

.csr_counter_read_i ( csr_counter_read ),
.csr_mnxti_read_i ( csr_mnxti_read ),
.csr_irq_enable_write_i ( csr_irq_enable_write ),

// From EX/WB pipeline
.ex_wb_pipe_i ( ex_wb_pipe ),
Expand Down
10 changes: 10 additions & 0 deletions rtl/cv32e40s_cs_registers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*;
input logic [7:0] mnxti_irq_level_i,
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
output logic csr_irq_enable_write_o, // An irq enable write is being performed in WB

// PMP
output pmp_csr_t csr_pmp_o,
Expand Down Expand Up @@ -2468,6 +2469,15 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*;
assign csr_rdata_o = csr_rdata_int;


// Signal when an interrupt may become enabled due to a CSR write
generate
if (SMCLIC) begin : smclic_irq_en
assign csr_irq_enable_write_o = mstatus_we || priv_lvl_we || mintthresh_we || mintstatus_we;
end else begin : basic_irq_en
assign csr_irq_enable_write_o = mie_we || mstatus_we || priv_lvl_we;
end
endgenerate

////////////////////////////////////////////////////////////////////////
//
// CSR outputs
Expand Down
1 change: 1 addition & 0 deletions rtl/include/cv32e40s_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,7 @@ typedef struct packed {
logic deassert_we; // Deassert write enable and special insn bits
logic id_stage_abort; // Same signal as deassert_we, with better name for use in the controller.
logic xif_exception_stall; // Stall (EX) if xif insn in WB can cause an exception
logic irq_enable_stall; // Stall (EX) if an interrupt may be enabled by the instruction in WB.
} ctrl_byp_t;

// Controller FSM outputs
Expand Down
8 changes: 8 additions & 0 deletions sva/cv32e40s_controller_fsm_sva.sv
Original file line number Diff line number Diff line change
Expand Up @@ -756,5 +756,13 @@ end // SMCLIC
|=>
sequence_interruptible)
else `uvm_error("controller", "sequence_interruptible should be 1 after an exception has been taken.")

// No new exception may occur in WB unless wb was ready the cycle before
a_wb_ready_exception:
assert property (@(posedge clk) disable iff (!rst_n)
(!wb_ready_i)
|=>
$stable(exception_in_wb))
else `uvm_error("controller", "New exception in WB without WB being ready.")
endmodule

61 changes: 59 additions & 2 deletions sva/cv32e40s_core_sva.sv
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ module cv32e40s_core_sva
input ctrl_fsm_t ctrl_fsm,
input logic [10:0] exc_cause,
input logic [31:0] mie,
input logic [31:0] mie_n,
input logic mie_we,
input logic [31:0] mip,
input dcsr_t dcsr,
input if_id_pipe_t if_id_pipe,
Expand All @@ -44,6 +46,7 @@ module cv32e40s_core_sva
input logic ex_ready,
input logic irq_ack, // irq ack output
input logic irq_clic_shv, // ack'ed irq is a CLIC SHV
input logic irq_req_ctrl, // Interrupt controller request an interrupt
input ex_wb_pipe_t ex_wb_pipe,
input id_ex_pipe_t id_ex_pipe,
input logic sys_en_id,
Expand Down Expand Up @@ -105,8 +108,11 @@ module cv32e40s_core_sva
input logic ctrl_debug_mode_n,
input logic ctrl_pending_debug,
input logic ctrl_debug_allowed,
input logic ctrl_interrupt_allowed,
input logic ctrl_pending_interrupt,
input ctrl_state_e ctrl_fsm_ns,
input ctrl_byp_t ctrl_byp,
input logic ctrl_pending_nmi,
// probed cs_registers signals
input logic [31:0] cs_registers_mie_q,
input logic [31:0] cs_registers_mepc_n,
Expand All @@ -123,8 +129,10 @@ module cv32e40s_core_sva
input logic mret_self_stall_bypass,
input logic jumpr_self_stall_bypass,
input logic last_sec_op_id_i, // todo: liekely not needed when using last_op_id.
input logic last_op_id
);
input logic last_op_id,

input logic clic_irq_q,
input logic [7:0] clic_irq_level_q);

if (SMCLIC) begin
property p_clic_mie_tieoff;
Expand Down Expand Up @@ -677,5 +685,54 @@ a_jumpr_self_stall_qual:
a_tbljmp_stall: assert property(p_tbljmp_stall)
else `uvm_error("core", "Table jump not stalled while CSR is written");

if (SMCLIC) begin
// Check that a pending interrupt is taken as soon as possible after being enabled
property p_clic_enable;
@(posedge clk) disable iff (!rst_ni)
( !irq_req_ctrl
##1
irq_req_ctrl && $stable(clic_irq_q) && $stable(clic_irq_level_q) && !(ctrl_fsm.debug_mode || (dcsr.step && !dcsr.stepie))
|-> (ctrl_pending_interrupt && ctrl_interrupt_allowed));
endproperty;

a_clic_enable: assert property(p_clic_enable)
else `uvm_error("core", "Interrupt not taken soon enough after enabling");

// Check a pending interrupt that is disabled is actually not taken
property p_clic_disable;
@(posedge clk) disable iff (!rst_ni)
( irq_req_ctrl
##1
!irq_req_ctrl && $stable(clic_irq_q) && $stable(clic_irq_level_q)
|-> !(ctrl_pending_interrupt && ctrl_interrupt_allowed));
endproperty;

a_clic_disable: assert property(p_clic_disable)
else `uvm_error("core", "Interrupt taken after disabling");
end else begin
// Check that a pending interrupt is taken as soon as possible after being enabled
property p_mip_mie_write_enable;
@(posedge clk) disable iff (!rst_ni)
( !irq_req_ctrl
##1
irq_req_ctrl && $stable(mip) && !(ctrl_fsm.debug_mode || (dcsr.step && !dcsr.stepie))
|-> (ctrl_pending_interrupt && ctrl_interrupt_allowed));
endproperty;

a_mip_mie_write_enable: assert property(p_mip_mie_write_enable)
else `uvm_error("core", "Interrupt not taken soon enough after enabling");

// Check a pending interrupt that is disabled is actually not taken
property p_mip_mie_write_disable;
@(posedge clk) disable iff (!rst_ni)
( irq_req_ctrl
##1
!irq_req_ctrl && $stable(mip)
|-> !(ctrl_pending_interrupt && ctrl_interrupt_allowed));
endproperty;

a_mip_mie_write_disable: assert property(p_mip_mie_write_disable)
else `uvm_error("core", "Interrupt taken after disabling");
end
endmodule

0 comments on commit b8d1efb

Please sign in to comment.