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

Implemented custom WFE instruction #669

Merged
merged 7 commits into from
Sep 28, 2022
3 changes: 3 additions & 0 deletions bhv/cv32e40x_wrapper.sv
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ module cv32e40x_wrapper
// Interrupt inputs
input logic [31:0] irq_i, // CLINT interrupts + CLINT extension interrupts

// WFE input
input logic wu_wfe_i,

// CLIC Interface
input logic clic_irq_i,
input logic [SMCLIC_ID_WIDTH-1:0] clic_irq_id_i,
Expand Down
17 changes: 14 additions & 3 deletions constraints/cv32e40x_core.sdc
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@ set clock_period 5.0
# Input delays for interrupts
set in_delay_irq [expr $clock_period * 0.50]

# Input delay for wu_wfe_i
set in_delay_wfe [expr $clock_period * 0.50]

# Delay for CLIC
# todo: set final constraints for CLIC signals
set in_delay_clic [expr $clock_period * 0.50]
set out_delay_clic [expr $clock_period * 0.50]

# Input delays for early signals

set in_delay_early [expr $clock_period * 0.10]
set in_delay_early [expr $clock_period * 0.10]

# Input delay for fencei handshake
set in_delay_fencei [expr $clock_period * 0.80]
Expand Down Expand Up @@ -123,6 +126,11 @@ set irq_input_ports [list \
irq_i* \
]

# WFE Input ports
set wfe_input_ports [list \
wu_wfe_i \
]

# CLIC Input ports
set clic_input_ports [list \
clic_irq*_i* \
Expand Down Expand Up @@ -255,14 +263,14 @@ set xif_mem_result_if_valid [list \
create_clock \
-name clk_i \
-period $clock_period \
[get_ports clk_i]
[get_ports clk_i]


########### Defining Default I/O constraints ###################

set all_clock_ports $clock_ports

set all_other_input_ports [remove_from_collection [all_inputs] [get_ports [list $all_clock_ports $obi_input_ports $irq_input_ports $clic_input_ports $early_input_ports $fencei_input_ports $xif_input_ports $xif_input_ports_result_data $xif_mem_if_input_ports]]]
set all_other_input_ports [remove_from_collection [all_inputs] [get_ports [list $all_clock_ports $obi_input_ports $irq_input_ports $wfe_input_ports $clic_input_ports $early_input_ports $fencei_input_ports $xif_input_ports $xif_input_ports_result_data $xif_mem_if_input_ports]]]

set all_other_output_ports [remove_from_collection [all_outputs] [get_ports [list $all_clock_ports $obi_output_ports $clic_output_ports $sleep_output_ports $fencei_output_ports $xif_output_ports $xif_output_ports_data_late $xif_output_ports_control_late $xif_mem_result_if_rdata $xif_mem_result_if_valid]]]

Expand All @@ -271,6 +279,9 @@ set_input_delay $in_delay_irq [get_ports $irq_input_ports ] -cl
set_input_delay $in_delay_clic [get_ports $clic_input_ports ] -clock clk_i
set_output_delay $out_delay_clic [get_ports $clic_output_ports ] -clock clk_i

# WFE
set_input_delay $in_delay_wfe [get_ports $wfe_input_ports ] -clock clk_i

# OBI input/output delays
set_input_delay $in_delay_instr_gnt [ get_ports instr_gnt_i ] -clock clk_i
set_input_delay $in_delay_instr_rvalid [ get_ports instr_rvalid_i ] -clock clk_i
Expand Down
4 changes: 4 additions & 0 deletions rtl/cv32e40x_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ module cv32e40x_controller import cv32e40x_pkg::*;
input logic [7:0] irq_clic_level_i,
input logic [1:0] irq_clic_priv_i,

input logic wu_wfe_i,

input logic [1:0] mtvec_mode_i,
input mcause_t mcause_i,

Expand Down Expand Up @@ -200,6 +202,8 @@ module cv32e40x_controller import cv32e40x_pkg::*;
.irq_clic_level_i ( irq_clic_level_i ),
.irq_clic_priv_i ( irq_clic_priv_i ),

.wu_wfe_i ( wu_wfe_i ),

.mtvec_mode_i ( mtvec_mode_i ),

// Debug Signal
Expand Down
6 changes: 3 additions & 3 deletions rtl/cv32e40x_controller_bypass.sv
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ module cv32e40x_controller_bypass import cv32e40x_pkg::*;
(ex_wb_pipe_i.instr_valid && (ex_wb_pipe_i.csr_en || (ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_mret_insn)))
);

// Stall ID when WFI is active in EX.
// Prevent load/store following a WFI in the pipeline
assign ctrl_byp_o.wfi_stall = (id_ex_pipe_i.sys_en && id_ex_pipe_i.sys_wfi_insn && id_ex_pipe_i.instr_valid);
// Stall ID when WFI or WFE is active in EX.
// Prevent load/store following a WFI or WFE in the pipeline
assign ctrl_byp_o.wfi_wfe_stall = (id_ex_pipe_i.sys_en && (id_ex_pipe_i.sys_wfi_insn || id_ex_pipe_i.sys_wfe_insn) && id_ex_pipe_i.instr_valid);

// Stall ID when mnxti CSR is accessed in EX
// This is needed because the data bypass from EX uses csr_rdata, and for mnxti this is actually mstatus and not the result
Expand Down
17 changes: 12 additions & 5 deletions rtl/cv32e40x_controller_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
input logic [7:0] irq_clic_level_i, // CLIC mode current interrupt level
input logic [1:0] irq_clic_priv_i, // CLIC mode current interrupt privilege

// Wakeup signal for WFE (from toplevel input)
input logic wu_wfe_i,

// From cs_registers
input logic [1:0] mtvec_mode_i,
input dcsr_t dcsr_i,
Expand Down Expand Up @@ -162,6 +165,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
logic exception_in_wb;
logic [10:0] exception_cause_wb;
logic wfi_in_wb;
logic wfe_in_wb;
logic fencei_in_wb;
logic mret_in_wb;
logic dret_in_wb;
Expand Down Expand Up @@ -323,6 +327,9 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
// wfi in wb
assign wfi_in_wb = ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_wfi_insn && ex_wb_pipe_i.instr_valid;

// wfe in wb
assign wfe_in_wb = ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_wfe_insn && ex_wb_pipe_i.instr_valid;

// fencei in wb
assign fencei_in_wb = ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_fencei_insn && ex_wb_pipe_i.instr_valid;

Expand Down Expand Up @@ -528,7 +535,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
// Sequences: If we need to halt for debug or interrupt not allowed due to a sequence, we must check if we can
// actually halt the ID stage or not. Halting the same sequence that causes *_allowed to go to 0
// may cause a deadlock.
ctrl_fsm_o.halt_id = ctrl_byp_i.jalr_stall || ctrl_byp_i.load_stall || ctrl_byp_i.csr_stall || ctrl_byp_i.wfi_stall || ctrl_byp_i.mnxti_id_stall ||
ctrl_fsm_o.halt_id = ctrl_byp_i.jalr_stall || ctrl_byp_i.load_stall || ctrl_byp_i.csr_stall || ctrl_byp_i.wfi_wfe_stall || ctrl_byp_i.mnxti_id_stall ||
(((pending_interrupt && !interrupt_allowed) || (pending_nmi && !nmi_allowed) || (pending_nmi_early)) && debug_interruptible && id_stage_haltable) ||
(pending_debug && !debug_allowed && id_stage_haltable);

Expand Down Expand Up @@ -693,9 +700,9 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
ctrl_fsm_o.csr_save_cause = !debug_mode_q; // Do not update CSRs if in debug mode
ctrl_fsm_o.csr_cause.exception_code = exception_cause_wb;
// Special insn
end else if (wfi_in_wb) begin
end else if (wfi_in_wb || wfe_in_wb) begin
// Halt the entire pipeline
// WFI will stay in WB until we exit sleep mode
// WFI/WFE will stay in WB until we exit sleep mode
ctrl_fsm_o.halt_wb = 1'b1;
ctrl_fsm_o.instr_req = 1'b0;
ctrl_fsm_ns = SLEEP;
Expand Down Expand Up @@ -1000,8 +1007,8 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
end

// Wakeup from sleep
assign ctrl_fsm_o.wake_from_sleep = irq_wu_ctrl_i || pending_debug || debug_mode_q;
assign ctrl_fsm_o.debug_wfi_no_sleep = debug_mode_q || dcsr_i.step || trigger_match_in_wb;
assign ctrl_fsm_o.wake_from_sleep = irq_wu_ctrl_i || pending_debug || debug_mode_q || (wfe_in_wb && wu_wfe_i); // Only WFE wakes up for wfe_wu_i
assign ctrl_fsm_o.debug_wfi_wfe_no_sleep = debug_mode_q || dcsr_i.step;

////////////////////
// Flops //
Expand Down
5 changes: 5 additions & 0 deletions rtl/cv32e40x_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ module cv32e40x_core import cv32e40x_pkg::*;
// Basic interrupt architecture
input logic [31:0] irq_i,

// Event wakeup signal
input logic wu_wfe_i,

// Smclic interrupt architecture
input logic clic_irq_i,
input logic [SMCLIC_ID_WIDTH-1:0] clic_irq_id_i,
Expand Down Expand Up @@ -864,6 +867,8 @@ module cv32e40x_core import cv32e40x_pkg::*;
.irq_clic_level_i ( irq_clic_level ),
.irq_clic_priv_i ( irq_clic_priv ),

.wu_wfe_i ( wu_wfe_i ),

// From CSR registers
.mtvec_mode_i ( mtvec_mode ),
.mcause_i ( mcause ),
Expand Down
2 changes: 1 addition & 1 deletion rtl/cv32e40x_cs_registers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
(32'(1) << 8) | // I - RV32I/64I/128I base ISA
(32'(M_EXT == M) << 12) | // M - Integer Multiply/Divide extension
(32'(0) << 20) | // U - User mode implemented
(32'(0) << 23) | // X - Non-standard extensions present
(32'(1) << 23) | // X - Non-standard extensions present
(32'(MXL) << 30); // M-XLEN

localparam logic [31:0] MISA_VALUE = CORE_MISA | (X_EXT ? X_MISA : 32'h0000_0000);
Expand Down
17 changes: 9 additions & 8 deletions rtl/cv32e40x_decoder.sv
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ module cv32e40x_decoder import cv32e40x_pkg::*;
output logic sys_mret_insn_o, // Return from exception instruction encountered (M)
output logic sys_dret_insn_o, // Return from debug (M)
output logic sys_ecall_insn_o, // Environment call (syscall) instruction encountered
output logic sys_wfi_insn_o, // Pipeline flush is requested
output logic sys_wfi_insn_o,
output logic sys_wfe_insn_o,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove above flush comment (not accurate)

output logic sys_fencei_insn_o, // fence.i instruction

// from IF/ID pipeline
Expand Down Expand Up @@ -127,7 +128,6 @@ module cv32e40x_decoder import cv32e40x_pkg::*;
.decoder_ctrl_o ( decoder_i_ctrl )
);


generate
if (A_EXT) begin: a_decoder
// RV32A extension decoder
Expand Down Expand Up @@ -220,12 +220,13 @@ module cv32e40x_decoder import cv32e40x_pkg::*;
assign lsu_sext_o = decoder_ctrl_mux.lsu_sext;
assign lsu_atop_o = decoder_a_ctrl.lsu_atop; // Only A decoder handles atomics
assign sys_en = decoder_i_ctrl.sys_en; // Only I decoder handles SYS
assign sys_mret_insn_o = decoder_i_ctrl.sys_mret_insn; // Only I decoder handles SYS
assign sys_dret_insn_o = decoder_i_ctrl.sys_dret_insn; // Only I decoder handles SYS
assign sys_ebrk_insn_o = decoder_i_ctrl.sys_ebrk_insn; // Only I decoder handles SYS
assign sys_ecall_insn_o = decoder_i_ctrl.sys_ecall_insn; // Only I decoder handles SYS
assign sys_wfi_insn_o = decoder_i_ctrl.sys_wfi_insn; // Only I decoder handles SYS
assign sys_fencei_insn_o = decoder_i_ctrl.sys_fencei_insn; // Only I decoder handles SYS
assign sys_mret_insn_o = decoder_i_ctrl.sys_mret_insn; // Only I decoder handles MRET
assign sys_dret_insn_o = decoder_i_ctrl.sys_dret_insn; // Only I decoder handles DRET
assign sys_ebrk_insn_o = decoder_i_ctrl.sys_ebrk_insn; // Only I decoder handles EBREAK
assign sys_ecall_insn_o = decoder_i_ctrl.sys_ecall_insn; // Only I decoder handles ECALL
assign sys_wfi_insn_o = decoder_i_ctrl.sys_wfi_insn; // Only I decoder handles WFI
assign sys_wfe_insn_o = decoder_i_ctrl.sys_wfe_insn; // Only I decoder handles WFE
assign sys_fencei_insn_o = decoder_i_ctrl.sys_fencei_insn; // Only I decoder handles FENCE.I

// Suppress control signals
assign alu_en_o = deassert_we_i ? 1'b0 : alu_en;
Expand Down
2 changes: 2 additions & 0 deletions rtl/cv32e40x_ex_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ module cv32e40x_ex_stage import cv32e40x_pkg::*;
ex_wb_pipe_o.sys_fencei_insn <= 1'b0;
ex_wb_pipe_o.sys_mret_insn <= 1'b0;
ex_wb_pipe_o.sys_wfi_insn <= 1'b0;
ex_wb_pipe_o.sys_wfe_insn <= 1'b0;

ex_wb_pipe_o.trigger_match <= 1'b0;

Expand Down Expand Up @@ -405,6 +406,7 @@ module cv32e40x_ex_stage import cv32e40x_pkg::*;
ex_wb_pipe_o.sys_fencei_insn <= id_ex_pipe_i.sys_fencei_insn;
ex_wb_pipe_o.sys_mret_insn <= id_ex_pipe_i.sys_mret_insn;
ex_wb_pipe_o.sys_wfi_insn <= id_ex_pipe_i.sys_wfi_insn;
ex_wb_pipe_o.sys_wfe_insn <= id_ex_pipe_i.sys_wfe_insn;
end

// CSR illegal instruction detected in this stage, OR'ing in the status
Expand Down
14 changes: 13 additions & 1 deletion rtl/cv32e40x_i_decoder.sv
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
// Language: SystemVerilog //
// //
// Description: Decoder for the RV32I Base Instruction set //
// Custom instruction WFE is also decoded in the I decoder //
// //
////////////////////////////////////////////////////////////////////////////////

Expand All @@ -38,6 +39,8 @@ module cv32e40x_i_decoder import cv32e40x_pkg::*;
output decoder_ctrl_t decoder_ctrl_o
);

localparam CUSTOM_EXT = 1;

always_comb
begin

Expand Down Expand Up @@ -322,7 +325,16 @@ module cv32e40x_i_decoder import cv32e40x_pkg::*;

12'h105: begin // wfi
// Suppressing WFI in case of ctrl_fsm_i.debug_wfi_no_sleep to prevent sleeping when not allowed.
decoder_ctrl_o.sys_wfi_insn = ctrl_fsm_i.debug_wfi_no_sleep ? 1'b0 : 1'b1;
decoder_ctrl_o.sys_wfi_insn = ctrl_fsm_i.debug_wfi_wfe_no_sleep ? 1'b0 : 1'b1;
end

12'h8C0: begin // wfe
if (CUSTOM_EXT == 1) begin
// Suppressing WFE in case of ctrl_fsm_i.debug_wfi_no_sleep to prevent sleeping when not allowed.
decoder_ctrl_o.sys_wfe_insn = ctrl_fsm_i.debug_wfi_wfe_no_sleep ? 1'b0 : 1'b1;
end else begin
decoder_ctrl_o = DECODER_CTRL_ILLEGAL_INSN;
end
end

default: begin
Expand Down
4 changes: 4 additions & 0 deletions rtl/cv32e40x_id_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ module cv32e40x_id_stage import cv32e40x_pkg::*;
logic sys_mret_insn;
logic sys_dret_insn;
logic sys_wfi_insn;
logic sys_wfe_insn;

// Operands and forwarding
logic [31:0] operand_a;
Expand Down Expand Up @@ -420,6 +421,7 @@ module cv32e40x_id_stage import cv32e40x_pkg::*;
.sys_dret_insn_o ( sys_dret_insn ),
.sys_ecall_insn_o ( sys_ecall_insn ),
.sys_wfi_insn_o ( sys_wfi_insn ),
.sys_wfe_insn_o ( sys_wfe_insn ),
.sys_fencei_insn_o ( sys_fencei_insn ),

// from IF/ID pipeline
Expand Down Expand Up @@ -533,6 +535,7 @@ module cv32e40x_id_stage import cv32e40x_pkg::*;
id_ex_pipe_o.sys_fencei_insn <= 1'b0;
id_ex_pipe_o.sys_mret_insn <= 1'b0;
id_ex_pipe_o.sys_wfi_insn <= 1'b0;
id_ex_pipe_o.sys_wfe_insn <= 1'b0;

id_ex_pipe_o.xif_en <= 1'b0;
id_ex_pipe_o.xif_meta <= '0;
Expand Down Expand Up @@ -619,6 +622,7 @@ module cv32e40x_id_stage import cv32e40x_pkg::*;
id_ex_pipe_o.sys_fencei_insn <= sys_fencei_insn;
id_ex_pipe_o.sys_mret_insn <= sys_mret_insn;
id_ex_pipe_o.sys_wfi_insn <= sys_wfi_insn;
id_ex_pipe_o.sys_wfe_insn <= sys_wfe_insn;
end

id_ex_pipe_o.illegal_insn <= illegal_insn && !xif_insn_accept;
Expand Down
24 changes: 14 additions & 10 deletions rtl/include/cv32e40x_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ typedef struct packed {
logic sys_fencei_insn;
logic sys_mret_insn;
logic sys_wfi_insn;
logic sys_wfe_insn;
} decoder_ctrl_t;

parameter decoder_ctrl_t DECODER_CTRL_ILLEGAL_INSN = '{
Expand Down Expand Up @@ -831,7 +832,8 @@ typedef struct packed {
sys_ecall_insn : 1'b0,
sys_fencei_insn : 1'b0,
sys_mret_insn : 1'b0,
sys_wfi_insn : 1'b0
sys_wfi_insn : 1'b0,
sys_wfe_insn : 1'b0
};

///////////////////////////////////////////////
Expand Down Expand Up @@ -1101,6 +1103,7 @@ typedef struct packed {
logic sys_fencei_insn;
logic sys_mret_insn;
logic sys_wfi_insn;
logic sys_wfe_insn;

logic illegal_insn;

Expand Down Expand Up @@ -1165,6 +1168,7 @@ typedef struct packed {
logic sys_fencei_insn;
logic sys_mret_insn;
logic sys_wfi_insn;
logic sys_wfe_insn;

// eXtension interface
logic xif_en; // Instruction has been offloaded via eXtension interface
Expand Down Expand Up @@ -1203,7 +1207,7 @@ typedef struct packed {
logic jalr_stall; // Stall due to JALR hazard (JALR used result from EX or LSU result in WB)
logic load_stall; // Stall due to load operation
logic csr_stall;
logic wfi_stall;
logic wfi_wfe_stall;
logic mnxti_id_stall; // Stall ID due to mnxti CSR access in EX
logic mnxti_ex_stall; // Stall EX due to LSU instruction in WB
logic minstret_stall; // Stall due to minstret/h read in EX
Expand Down Expand Up @@ -1239,14 +1243,14 @@ typedef struct packed {
logic dbg_ack; // Debug has been taken

// Debug outputs
logic debug_mode_if; // Flag signalling we are in debug mode, valid for IF
logic debug_mode; // Flag signalling we are in debug mode, valid for ID, EX and WB
logic [2:0] debug_cause; // cause of debug entry
logic debug_csr_save; // Update debug CSRs
logic debug_wfi_no_sleep; // Debug prevents core from sleeping after WFI
logic debug_havereset; // Signal to external debugger that we have reset
logic debug_running; // Signal to external debugger that we are running (not in debug)
logic debug_halted; // Signal to external debugger that we are halted (in debug mode)
logic debug_mode_if; // Flag signalling we are in debug mode, valid for IF
logic debug_mode; // Flag signalling we are in debug mode, valid for ID, EX and WB
logic [2:0] debug_cause; // cause of debug entry
logic debug_csr_save; // Update debug CSRs
logic debug_wfi_wfe_no_sleep; // Debug prevents core from sleeping after WFI
logic debug_havereset; // Signal to external debugger that we have reset
logic debug_running; // Signal to external debugger that we are running (not in debug)
logic debug_halted; // Signal to external debugger that we are halted (in debug mode)


// Wakeup Signal to sleep unit
Expand Down
Loading