diff --git a/rtl/cv32e40s_cs_registers.sv b/rtl/cv32e40s_cs_registers.sv index 49dc932ee..b4e900124 100644 --- a/rtl/cv32e40s_cs_registers.sv +++ b/rtl/cv32e40s_cs_registers.sv @@ -616,7 +616,7 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; // mscratchcsw: Scratch Swap for Multiple Privilege Modes CSR_MSCRATCHCSW: begin - if (CLIC) begin + if (CLIC && USER) begin // CLIC spec 13.2 // Depending on mstatus.MPP, we return either mscratch_rdata or rs1 to rd. // Safe to use mstatus_rdata here (EX timing), as there is a generic stall of the ID stage @@ -1032,7 +1032,7 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; tinfo_we = 1'b0; mstatus_n = csr_next_value(mstatus_t'{ - tw: csr_wdata_int[MSTATUS_TW_BIT], + tw: mstatus_tw_resolve(mstatus_rdata.tw, csr_wdata_int[MSTATUS_TW_BIT]), mprv: mstatus_mprv_resolve(mstatus_rdata.mprv, csr_wdata_int[MSTATUS_MPRV_BIT]), 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], @@ -1322,7 +1322,7 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; end CSR_MSCRATCHCSW: begin - if (CLIC) begin + if (CLIC && USER) begin // mscratchcsw operates on mscratch // Writing only when mstatus.mpp != PRIV_LVL_M if (mstatus_rdata.mpp != PRIV_LVL_M) begin @@ -2218,6 +2218,7 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; assign csr_wr_in_wb_flush_o = xsecure_csr_wr_in_wb || pmp_csr_wr_in_wb || jvt_wr_in_wb; + if (USER) begin : privlvl_user // Privilege level register cv32e40s_csr #( @@ -2280,6 +2281,18 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; end end + + end else begin : no_privlvl_user + assign priv_lvl_q = PRIV_LVL_M; + assign priv_lvl_rd_error = 1'b0; + + assign priv_lvl_if_ctrl_o.priv_lvl = PRIV_LVL_M; + assign priv_lvl_if_ctrl_o.priv_lvl_set = 1'b0; + + assign priv_lvl_lsu_o = PRIV_LVL_M; + end + + generate if (PMP_NUM_REGIONS > 0) begin: csr_pmp diff --git a/rtl/cv32e40s_debug_triggers.sv b/rtl/cv32e40s_debug_triggers.sv index 30f1f2caa..ee1a606f4 100644 --- a/rtl/cv32e40s_debug_triggers.sv +++ b/rtl/cv32e40s_debug_triggers.sv @@ -78,7 +78,7 @@ import cv32e40s_pkg::*; ); // Set mask for supported exception codes for exception triggers. - localparam logic [31:0] ETRIGGER_TDATA2_MASK = (1 << EXC_CAUSE_INSTR_BUS_FAULT) | (1 << EXC_CAUSE_INSTR_INTEGRITY_FAULT) | (1 << EXC_CAUSE_ECALL_MMODE) | (1 << EXC_CAUSE_ECALL_UMODE) | (1 << EXC_CAUSE_STORE_FAULT) | + localparam logic [31:0] ETRIGGER_TDATA2_MASK = (1 << EXC_CAUSE_INSTR_BUS_FAULT) | (1 << EXC_CAUSE_INSTR_INTEGRITY_FAULT) | (1 << EXC_CAUSE_ECALL_MMODE) | ((USER) << EXC_CAUSE_ECALL_UMODE) | (1 << EXC_CAUSE_STORE_FAULT) | (1 << EXC_CAUSE_LOAD_FAULT) | (1 << EXC_CAUSE_BREAKPOINT) | (1 << EXC_CAUSE_ILLEGAL_INSN) | (1 << EXC_CAUSE_INSTR_FAULT); diff --git a/rtl/cv32e40s_i_decoder.sv b/rtl/cv32e40s_i_decoder.sv index fe27f5233..91211ae0d 100644 --- a/rtl/cv32e40s_i_decoder.sv +++ b/rtl/cv32e40s_i_decoder.sv @@ -412,7 +412,7 @@ module cv32e40s_i_decoder import cv32e40s_pkg::*; if (CLIC) begin // The mscratchcsw[l] CSRs are only accessible using CSRRW with neither rd nor rs1 set to x0 - if ((instr_rdata_i[31:20] == CSR_MSCRATCHCSW) || (instr_rdata_i[31:20] == CSR_MSCRATCHCSWL)) begin + if (((instr_rdata_i[31:20] == CSR_MSCRATCHCSW) && (USER)) || (instr_rdata_i[31:20] == CSR_MSCRATCHCSWL)) begin if (instr_rdata_i[14:12] == 3'b001) begin // CSRRW if ((instr_rdata_i[11:7] == 5'b0) || (instr_rdata_i[19:15] == 5'b0)) begin // rd or rs1 is zero, flag instruction as illegal diff --git a/rtl/include/cv32e40s_pkg.sv b/rtl/include/cv32e40s_pkg.sv index 9e7db1670..5b33f285f 100644 --- a/rtl/include/cv32e40s_pkg.sv +++ b/rtl/include/cv32e40s_pkg.sv @@ -541,7 +541,7 @@ typedef enum logic[1:0] { PRIV_LVL_U = 2'b00 } privlvl_t; -parameter privlvl_t PRIV_LVL_LOWEST = PRIV_LVL_U; +parameter privlvl_t PRIV_LVL_LOWEST = (USER) ? PRIV_LVL_U : PRIV_LVL_M; // Struct used for setting privilege lelve typedef struct packed { @@ -822,6 +822,9 @@ parameter logic [31:0] TDATA1_RST_VAL = { // Enable Security Features parameter SECURE = 1; +// Enable User Mode +parameter bit USER = SECURE; + // Register file read/write ports parameter REGFILE_NUM_WRITE_PORTS = 1; @@ -1525,8 +1528,13 @@ typedef struct packed { privlvl_t current_value, logic [1:0] next_value ); - // dcsr.prv is WARL(0x0, 0x3) - return ((next_value != PRIV_LVL_M) && (next_value != PRIV_LVL_U)) ? current_value : privlvl_t'(next_value); + if (USER) begin + // dcsr.prv is WARL(0x0, 0x3) + return ((next_value != PRIV_LVL_M) && (next_value != PRIV_LVL_U)) ? current_value : privlvl_t'(next_value); + end else begin + // dcsr.prv is WARL(0x3) + return PRIV_LVL_M; + end endfunction function automatic logic dcsr_ebreaku_resolve @@ -1534,8 +1542,14 @@ typedef struct packed { logic current_value, logic next_value ); - // dcsr.ebreaku is WARL - return next_value; + if (USER) begin + // dcsr.ebreaku is WARL + return next_value; + end else begin + // dcsr.ebreaku is WARL(0x0) + return 1'b0; + end + endfunction function automatic logic [1:0] mstatus_mpp_resolve @@ -1543,8 +1557,14 @@ typedef struct packed { logic [1:0] current_value, logic [1:0] next_value ); - // mstatus.mpp is WARL(0x0, 0x3) - return ((next_value != PRIV_LVL_M) && (next_value != PRIV_LVL_U)) ? current_value : next_value; + if (USER) begin + // mstatus.mpp is WARL(0x0, 0x3) + return ((next_value != PRIV_LVL_M) && (next_value != PRIV_LVL_U)) ? current_value : next_value; + end else begin + // mstatus.mpp is WARL(0x3) + return PRIV_LVL_M; + end + endfunction function automatic logic [1:0] mcause_mpp_resolve @@ -1552,8 +1572,14 @@ typedef struct packed { logic [1:0] current_value, logic [1:0] next_value ); - // mcause.mpp is WARL(0x0, 0x3) - return ((next_value != PRIV_LVL_M) && (next_value != PRIV_LVL_U)) ? current_value : next_value; + if (USER) begin + // mcause.mpp is WARL(0x0, 0x3) + return ((next_value != PRIV_LVL_M) && (next_value != PRIV_LVL_U)) ? current_value : next_value; + end else begin + // mcause.mpp is WARL(0x3) + return PRIV_LVL_M; + end + endfunction function automatic logic mstatus_mprv_resolve @@ -1561,8 +1587,26 @@ typedef struct packed { logic current_value, logic next_value ); - // mstatus.mprv is is RW - return next_value; + if (USER) begin + // mstatus.mprv is is RW + return next_value; + end else begin + // mstatus.mprv is WARL(0x0) + return 1'b0; + end + endfunction + + function automatic logic mstatus_tw_resolve + ( + logic current_value, + logic next_value + ); + if (USER) begin + // mstatus.tw is is RW + return next_value; + end else begin + return 1'b0; + end endfunction function automatic logic [3:0] mcontrol2_6_match_resolve @@ -1576,8 +1620,13 @@ typedef struct packed { ( logic next_value ); - // mcontrol6.u is WARL - return next_value; + if (USER) begin + // mcontrol6.u is WARL + return next_value; + end else begin + // mcontrol2/6.u is WARL(0x0) + return 1'b0; + end endfunction function automatic logic mcontrol6_uncertain_resolve @@ -1609,8 +1658,13 @@ typedef struct packed { ( logic next_value ); - // etrigger.u is WARL - return next_value; + if (USER) begin + // etrigger.u is WARL + return next_value; + end else begin + // etrigger.u is WARL(0x0) + return 1'b0; + end endfunction function automatic logic[1:0] mtvec_mode_clint_resolve