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

Unifying code with CV32E40S #626

Merged
merged 1 commit into from
Jul 26, 2022
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: 5 additions & 1 deletion rtl/cv32e40x_controller_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
// Detect if there is a live CLIC pointer in the pipeline
// This should block debug
generate
if(SMCLIC) begin : gen_clic_pointer_flag
if (SMCLIC) begin : gen_clic_pointer_flag
// We only need to check EX and WB, as the FSM will only be in FUNCTIONAL state
// one cycle after the target CLIC jump has been performed from ID
assign clic_ptr_in_pipeline = (id_ex_pipe_i.instr_valid && id_ex_pipe_i.instr_meta.clic_ptr) ||
Expand Down Expand Up @@ -558,6 +558,8 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
ctrl_fsm_o.kill_wb = 1'b0;

ctrl_fsm_o.csr_restore_mret = 1'b0;
ctrl_fsm_o.csr_restore_dret = 1'b0;

ctrl_fsm_o.csr_save_cause = 1'b0;
ctrl_fsm_o.csr_cause = 32'h0;
ctrl_fsm_o.csr_clear_minhv = 1'b0;
Expand Down Expand Up @@ -752,6 +754,8 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
ctrl_fsm_o.pc_mux = PC_DRET;
ctrl_fsm_o.pc_set = 1'b1;

ctrl_fsm_o.csr_restore_dret = 1'b1;

single_step_halt_if_n = 1'b0;
debug_mode_n = 1'b0;
end else if (csr_wr_in_wb_flush_i) begin
Expand Down
108 changes: 65 additions & 43 deletions rtl/cv32e40x_cs_registers.sv
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
logic [31:0] mtval_n, mtval_rdata; // No CSR module instance
logic mtval_we; // Not used in RTL (used by RVFI)

privlvl_t priv_lvl_rdata;
privlvl_t priv_lvl_n, priv_lvl_q, priv_lvl_rdata; // todo: Use the priv_* signals as much as possible as in the 40S
logic priv_lvl_we;
logic [1:0] priv_lvl_q_int;

// Detect JVT writes (requires pipeline flush)
logic csr_wr_in_wb;
Expand Down Expand Up @@ -557,7 +559,7 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
ebreakm : csr_wdata_int[15],
stepie : csr_wdata_int[11],
step : csr_wdata_int[2],
prv : PRIV_LVL_M,
prv : dcsr_prv_resolve(dcsr_rdata.prv, csr_wdata_int[1:0]),
cause : dcsr_rdata.cause,
default : 'd0
};
Expand Down Expand Up @@ -609,7 +611,7 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
mstatus_n = '{
tw: 1'b0,
mprv: 1'b0,
mpp: PRIV_LVL_M,
mpp: mstatus_mpp_resolve(mstatus_rdata.mpp, csr_wdata_int[MSTATUS_MPP_BIT_HIGH:MSTATUS_MPP_BIT_LOW]),
mpie: csr_wdata_int[MSTATUS_MPIE_BIT],
mie: csr_wdata_int[MSTATUS_MIE_BIT],
default: 'b0
Expand All @@ -622,6 +624,9 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
misa_n = misa_rdata; // Read only
misa_we = 1'b0;

priv_lvl_n = priv_lvl_rdata;
priv_lvl_we = 1'b0;

mtvec_n.addr = csr_mtvec_init_i ? mtvec_addr_i[31:7] : csr_wdata_int[31:7];
mtvec_n.zero0 = mtvec_rdata.zero0;
mtvec_we = csr_mtvec_init_i;
Expand Down Expand Up @@ -910,7 +915,7 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;

// 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
mstatus_n.mpp = mstatus_mpp_resolve(mstatus_rdata.mpp, csr_wdata_int[MSTATUS_MPP_BIT_HIGH:MSTATUS_MPP_BIT_LOW]);
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
Expand All @@ -923,67 +928,84 @@ module cv32e40x_cs_registers import cv32e40x_pkg::*;
clic_pa_o = '0;
end

// exception controller gets priority over other writes
// Exception controller gets priority over other writes
unique case (1'b1)
ctrl_fsm_i.csr_save_cause: begin
if (ctrl_fsm_i.debug_csr_save) begin
// all interrupts are masked, don't update cause, epc, tval dpc and
// mpstatus
// dcsr.nmip is not a flop, but comes directly from the controller
dcsr_n = '{
xdebugver : dcsr_rdata.xdebugver,
ebreakm : dcsr_rdata.ebreakm,
stepie : dcsr_rdata.stepie,
step : dcsr_rdata.step,
prv : PRIV_LVL_M,
cause : ctrl_fsm_i.debug_cause,
default : 'd0
};
dcsr_we = 1'b1;

dpc_n = ctrl_fsm_i.pipe_pc;
dpc_we = 1'b1;
// All interrupts are masked, don't update mcause, mepc, mtval, dpc and mstatus
// dcsr.nmip is not a flop, but comes directly from the controller
dcsr_n = '{
xdebugver : dcsr_rdata.xdebugver,
ebreakm : dcsr_rdata.ebreakm,
stepie : dcsr_rdata.stepie,
step : dcsr_rdata.step,
prv : priv_lvl_rdata, // Privilege level at time of debug entry
cause : ctrl_fsm_i.debug_cause,
default : 'd0
};
dcsr_we = 1'b1;

dpc_n = ctrl_fsm_i.pipe_pc;
dpc_we = 1'b1;

priv_lvl_n = PRIV_LVL_M; // Execute with machine mode privilege in debug mode
priv_lvl_we = 1'b1;
end else begin
mstatus_n.mpie = mstatus_rdata.mie;
mstatus_n.mie = 1'b0;
mstatus_n.mpp = PRIV_LVL_M;
mstatus_we = 1'b1;
priv_lvl_n = PRIV_LVL_M; // Trap into machine mode
priv_lvl_we = 1'b1;

mepc_n = ctrl_fsm_i.pipe_pc;
mepc_we = 1'b1;
mstatus_n = mstatus_rdata;
mstatus_n.mie = 1'b0;
mstatus_n.mpie = mstatus_rdata.mie;
mstatus_n.mpp = priv_lvl_rdata;
mstatus_we = 1'b1;

// Set mcause from controller
mcause_n = ctrl_fsm_i.csr_cause;
mepc_n = ctrl_fsm_i.pipe_pc;
mepc_we = 1'b1;

if (SMCLIC) begin
// mpil is saved from mintstatus
mcause_n.mpil = mintstatus_rdata.mil;
mcause_n = ctrl_fsm_i.csr_cause;

// todo: handle exception vs interrupt
// Save new interrupt level to mintstatus
mintstatus_n.mil = ctrl_fsm_i.irq_level;
mintstatus_we = 1'b1;
end else begin
mcause_n.mpil = '0;
end
if (SMCLIC) begin
// mpil is saved from mintstatus
mcause_n.mpil = mintstatus_rdata.mil;

mcause_we = 1'b1;
// todo: handle exception vs interrupt
// Save new interrupt level to mintstatus
mintstatus_n.mil = ctrl_fsm_i.irq_level;
mintstatus_we = 1'b1;
end else begin
mcause_n.mpil = '0;
end

mcause_we = 1'b1;

end
end //ctrl_fsm_i.csr_save_cause

ctrl_fsm_i.csr_restore_mret: begin //MRET
ctrl_fsm_i.csr_restore_mret: begin // MRET
priv_lvl_n = privlvl_t'(mstatus_rdata.mpp);
priv_lvl_we = 1'b1;

mstatus_n = mstatus_rdata;
mstatus_n.mie = mstatus_rdata.mpie;
mstatus_n.mpie = 1'b1;
mstatus_n.mpp = PRIV_LVL_M;
mstatus_we = 1'b1;
mstatus_n.mpp = PRIV_LVL_LOWEST;
mstatus_we = 1'b1;

if (SMCLIC) begin
mintstatus_n.mil = mcause_rdata.mpil;
mintstatus_we = 1'b1;
end
end //ctrl_fsm_i.csr_restore_mret

ctrl_fsm_i.csr_restore_dret: begin // DRET
// Restore to the recorded privilege level
priv_lvl_n = dcsr_rdata.prv;
priv_lvl_we = 1'b1;

// todo: Section 4.6 of debug spec: If the new privilege mode is less privileged than M-mode, MPRV in mstatus is cleared.
end //ctrl_fsm_i.csr_restore_dret

// mcause.minhv shall be cleared if vector fetch is successful
ctrl_fsm_i.csr_clear_minhv: begin
if (SMCLIC) begin
Expand Down
26 changes: 26 additions & 0 deletions rtl/include/cv32e40x_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ typedef enum logic[1:0] {
PRIV_LVL_U = 2'b00
} privlvl_t;

parameter privlvl_t PRIV_LVL_LOWEST = PRIV_LVL_M;

// Machine Vendor ID - OpenHW JEDEC ID is '2 decimal (bank 13)'
parameter MVENDORID_OFFSET = 7'h2; // Final byte without parity bit
parameter MVENDORID_BANK = 25'hC; // Number of continuation codes
Expand All @@ -474,6 +476,8 @@ parameter NUM_HPM_EVENTS = 16;

parameter MSTATUS_MIE_BIT = 3;
parameter MSTATUS_MPIE_BIT = 7;
parameter MSTATUS_MPP_BIT_LOW = 11;
parameter MSTATUS_MPP_BIT_HIGH = 12;

parameter MCAUSE_MPIE_BIT = 27;

Expand Down Expand Up @@ -1244,6 +1248,7 @@ typedef struct packed {
logic [31:0] pipe_pc; // PC from pipeline
mcause_t csr_cause; // CSR cause (saves to mcause CSR)
logic csr_restore_mret; // Restore CSR due to mret
logic csr_restore_dret; // Restore CSR due to dret
logic csr_save_cause; // Update CSRs
logic csr_clear_minhv; // Clear the mcause.minhv field
logic pending_nmi; // An NMI is pending (for dcsr.nmip)
Expand All @@ -1267,6 +1272,27 @@ typedef struct packed {
logic kill_xif; // Kill (attempted) offloaded instruction
} ctrl_fsm_t;

////////////////////////////////////////
// Resolution functions

function automatic privlvl_t dcsr_prv_resolve
(
privlvl_t current_value,
logic [1:0] next_value
);
// dcsr.prv is WARL(0x3)
return PRIV_LVL_M;
endfunction

function automatic logic [1:0] mstatus_mpp_resolve
(
logic [1:0] current_value,
logic [1:0] next_value
);
// mstatus.mpp is WARL(0x3)
return PRIV_LVL_M;
endfunction

///////////////////////////
// //
// /\/\ (_)___ ___ //
Expand Down