From 51750eb81d59dd746a2bc9bf0d93979f62ecee52 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Tue, 24 May 2022 21:12:44 +0100 Subject: [PATCH] Add mstatus.tw to control U-mode WFI, and prevent mret execution in U-mode. --- hdl/hazard3_core.v | 13 ++++++++----- hdl/hazard3_csr.v | 19 +++++++++++++------ hdl/hazard3_decode.v | 45 +++++++++++++++++++++++--------------------- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/hdl/hazard3_core.v b/hdl/hazard3_core.v index 108d64d..f035323 100644 --- a/hdl/hazard3_core.v +++ b/hdl/hazard3_core.v @@ -187,11 +187,13 @@ wire d_csr_wen; wire [1:0] d_csr_wtype; wire d_csr_w_imm; -wire x_jump_not_except; +wire x_jump_not_except; +wire x_mmode_execution; +wire x_permit_wfi; hazard3_decode #( `include "hazard3_config_inst.vh" -) inst_hazard3_decode ( +) decode_u ( .clk (clk), .rst_n (rst_n), @@ -204,6 +206,8 @@ hazard3_decode #( .x_jump_not_except (x_jump_not_except), .debug_mode (debug_mode), + .m_mode (x_mmode_execution), + .permit_wfi (x_permit_wfi), .d_starved (d_starved), .x_stall (x_stall), @@ -257,8 +261,6 @@ wire m_trap_enter_vld; wire m_trap_enter_soon; wire m_trap_enter_rdy = f_jump_rdy; -// Privilege state outputs from CSR block -wire x_mmode_execution; wire x_mmode_loadstore; wire m_mmode_trap_entry; @@ -821,7 +823,7 @@ wire m_dphase_in_flight = xm_memop != MEMOP_NONE && xm_memop != MEMOP_AMO; hazard3_csr #( .XLEN (W_DATA), `include "hazard3_config_inst.vh" -) inst_hazard3_csr ( +) csr_u ( .clk (clk), .rst_n (rst_n), @@ -878,6 +880,7 @@ hazard3_csr #( .pmp_cfg_rdata (x_pmp_cfg_rdata), // Other CSR-specific signalling + .permit_wfi (x_permit_wfi), .instr_ret (|x_instr_ret) ); diff --git a/hdl/hazard3_csr.v b/hdl/hazard3_csr.v index e49a5d7..27c93e9 100644 --- a/hdl/hazard3_csr.v +++ b/hdl/hazard3_csr.v @@ -102,6 +102,7 @@ module hazard3_csr #( input wire [W_DATA-1:0] pmp_cfg_rdata, // Other CSR-specific signalling + output wire permit_wfi, input wire instr_ret ); @@ -146,13 +147,14 @@ end wire debug_suppresses_trap_update = DEBUG_SUPPORT && (debug_mode || enter_debug_mode); - -// Two-level interrupt enable stack, shuffled on entry/exit: +// Core execution state, 1 -> M-mode, 0 -> U-mode (if implemented) reg m_mode; + reg mstatus_mpie; reg mstatus_mie; reg mstatus_mpp; // only MSB is implemented reg mstatus_mprv; +reg mstatus_tw; wire wen_m_mode = wen && (m_mode || debug_mode); @@ -163,6 +165,7 @@ always @ (posedge clk or negedge rst_n) begin mstatus_mie <= 1'b0; mstatus_mpp <= 1'b1; mstatus_mprv <= 1'b0; + mstatus_tw <= 1'b0; end else if (CSR_M_TRAP) begin if (trap_enter_vld && trap_enter_rdy && !debug_suppresses_trap_update) begin if (except == EXCEPT_MRET) begin @@ -184,7 +187,8 @@ always @ (posedge clk or negedge rst_n) begin mstatus_mie <= wdata_update[3]; mstatus_mprv <= wdata_update[17]; // Note only the MSB of MPP is implemented. It reads back as 11 or 00. - mstatus_mpp <= wdata_update[12]; + mstatus_mpp <= wdata_update[12] || !U_MODE; + mstatus_tw <= wdata_update[21] && U_MODE; end else if (wen && debug_mode && addr == DCSR && U_MODE && DEBUG_SUPPORT) begin // Debugger can change/observe core state directly through // dcsr.prv (this doesn't affect debugger operation, as all @@ -195,6 +199,9 @@ always @ (posedge clk or negedge rst_n) begin end end +// Simply trap all U-mode WFIs if timeout bit is set +assign permit_wfi = m_mode || !mstatus_tw; + reg [XLEN-1:0] mscratch; always @ (posedge clk or negedge rst_n) begin @@ -510,10 +517,10 @@ always @ (*) begin 1'b0, // Never any dirty state besides GPRs 8'd0, // (WPRI) 1'b0, // TSR (Trap SRET), tied 0 if no S mode. - 1'b0, // TW (Timeout Wait), tied 0 if only M mode. + mstatus_tw, // TW (Timeout Wait) 1'b0, // TVM (trap virtual memory), tied 0 if no S mode. - 1'b0, // MXR (Make eXecutable Readable), tied 0 if not S mode. - 1'b0, // SUM, tied 0, we have no S or U mode + 1'b0, // MXR (Make eXecutable Readable), tied 0 if no S mode. + 1'b0, // SUM, tied 0 if no S mode mstatus_mprv, // MPRV (modify privilege) 4'd0, // XS, FS always "off" (no extension state to clear!) {2{mstatus_mpp}}, // MPP (M-mode previous privilege), only M and U supported diff --git a/hdl/hazard3_decode.v b/hdl/hazard3_decode.v index 4b88443..d82d8a3 100644 --- a/hdl/hazard3_decode.v +++ b/hdl/hazard3_decode.v @@ -10,23 +10,25 @@ module hazard3_decode #( , `include "hazard3_width_const.vh" ) ( - input wire clk, - input wire rst_n, + input wire clk, + input wire rst_n, - input wire [31:0] fd_cir, - input wire [1:0] fd_cir_err, - input wire [1:0] fd_cir_vld, + input wire [31:0] fd_cir, + input wire [1:0] fd_cir_err, + input wire [1:0] fd_cir_vld, output wire [1:0] df_cir_use, output wire df_cir_lock, output wire [W_ADDR-1:0] d_pc, - input wire debug_mode, + input wire debug_mode, + input wire m_mode, + input wire permit_wfi, output wire d_starved, - input wire x_stall, - input wire f_jump_now, - input wire [W_ADDR-1:0] f_jump_target, - input wire x_jump_not_except, + input wire x_stall, + input wire f_jump_now, + input wire [W_ADDR-1:0] f_jump_target, + input wire x_jump_not_except, output reg [W_DATA-1:0] d_imm, output reg [W_REGADDR-1:0] d_rs1, @@ -290,17 +292,18 @@ always @ (*) begin RV_ZIP: if (EXTENSION_ZBKB) begin d_aluop = ALUOP_ZIP; d_rs2 = X0; end else begin d_invalid_32bit = 1'b1; end RV_FENCE: begin d_rs2 = X0; end // NOP, note rs1/rd are zero in instruction - RV_FENCE_I: if (EXTENSION_ZIFENCEI) begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_branchcond = BCOND_ALWAYS; end else begin d_invalid_32bit = 1'b1; end // note rs1/rs2/rd are zero in instruction - RV_CSRRW: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; end else begin d_invalid_32bit = 1'b1; end - RV_CSRRS: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_S; end else begin d_invalid_32bit = 1'b1; end - RV_CSRRC: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_C; end else begin d_invalid_32bit = 1'b1; end - RV_CSRRWI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end - RV_CSRRSI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_S; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end - RV_CSRRCI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_C; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end - RV_ECALL: if (HAVE_CSR) begin d_except = EXCEPT_ECALL; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end - RV_EBREAK: if (HAVE_CSR) begin d_except = EXCEPT_EBREAK; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end - RV_MRET: if (HAVE_CSR) begin d_except = EXCEPT_MRET; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end - RV_WFI: if (HAVE_CSR) begin d_wfi = 1'b1; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end + RV_FENCE_I: if (EXTENSION_ZIFENCEI) begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_branchcond = BCOND_ALWAYS; end else begin d_invalid_32bit = 1'b1; end // note rs1/rs2/rd are zero in instruction + RV_CSRRW: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; end else begin d_invalid_32bit = 1'b1; end + RV_CSRRS: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_S; end else begin d_invalid_32bit = 1'b1; end + RV_CSRRC: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_C; end else begin d_invalid_32bit = 1'b1; end + RV_CSRRWI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end + RV_CSRRSI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_S; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end + RV_CSRRCI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_C; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end + RV_ECALL: if (HAVE_CSR) begin d_except = EXCEPT_ECALL; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end + RV_EBREAK: if (HAVE_CSR) begin d_except = EXCEPT_EBREAK; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end + RV_MRET: if (HAVE_CSR && m_mode) begin d_except = EXCEPT_MRET; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end + RV_WFI: if (HAVE_CSR && permit_wfi) begin d_wfi = 1'b1; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end + default: begin d_invalid_32bit = 1'b1; end endcase