Add mstatus.tw to control U-mode WFI, and prevent mret execution in U-mode.

This commit is contained in:
Luke Wren 2022-05-24 21:12:44 +01:00
parent 10ca3aec80
commit 51750eb81d
3 changed files with 45 additions and 32 deletions

View File

@ -187,11 +187,13 @@ wire d_csr_wen;
wire [1:0] d_csr_wtype; wire [1:0] d_csr_wtype;
wire d_csr_w_imm; 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 #( hazard3_decode #(
`include "hazard3_config_inst.vh" `include "hazard3_config_inst.vh"
) inst_hazard3_decode ( ) decode_u (
.clk (clk), .clk (clk),
.rst_n (rst_n), .rst_n (rst_n),
@ -204,6 +206,8 @@ hazard3_decode #(
.x_jump_not_except (x_jump_not_except), .x_jump_not_except (x_jump_not_except),
.debug_mode (debug_mode), .debug_mode (debug_mode),
.m_mode (x_mmode_execution),
.permit_wfi (x_permit_wfi),
.d_starved (d_starved), .d_starved (d_starved),
.x_stall (x_stall), .x_stall (x_stall),
@ -257,8 +261,6 @@ wire m_trap_enter_vld;
wire m_trap_enter_soon; wire m_trap_enter_soon;
wire m_trap_enter_rdy = f_jump_rdy; wire m_trap_enter_rdy = f_jump_rdy;
// Privilege state outputs from CSR block
wire x_mmode_execution;
wire x_mmode_loadstore; wire x_mmode_loadstore;
wire m_mmode_trap_entry; wire m_mmode_trap_entry;
@ -821,7 +823,7 @@ wire m_dphase_in_flight = xm_memop != MEMOP_NONE && xm_memop != MEMOP_AMO;
hazard3_csr #( hazard3_csr #(
.XLEN (W_DATA), .XLEN (W_DATA),
`include "hazard3_config_inst.vh" `include "hazard3_config_inst.vh"
) inst_hazard3_csr ( ) csr_u (
.clk (clk), .clk (clk),
.rst_n (rst_n), .rst_n (rst_n),
@ -878,6 +880,7 @@ hazard3_csr #(
.pmp_cfg_rdata (x_pmp_cfg_rdata), .pmp_cfg_rdata (x_pmp_cfg_rdata),
// Other CSR-specific signalling // Other CSR-specific signalling
.permit_wfi (x_permit_wfi),
.instr_ret (|x_instr_ret) .instr_ret (|x_instr_ret)
); );

View File

@ -102,6 +102,7 @@ module hazard3_csr #(
input wire [W_DATA-1:0] pmp_cfg_rdata, input wire [W_DATA-1:0] pmp_cfg_rdata,
// Other CSR-specific signalling // Other CSR-specific signalling
output wire permit_wfi,
input wire instr_ret input wire instr_ret
); );
@ -146,13 +147,14 @@ end
wire debug_suppresses_trap_update = DEBUG_SUPPORT && (debug_mode || enter_debug_mode); wire debug_suppresses_trap_update = DEBUG_SUPPORT && (debug_mode || enter_debug_mode);
// Core execution state, 1 -> M-mode, 0 -> U-mode (if implemented)
// Two-level interrupt enable stack, shuffled on entry/exit:
reg m_mode; reg m_mode;
reg mstatus_mpie; reg mstatus_mpie;
reg mstatus_mie; reg mstatus_mie;
reg mstatus_mpp; // only MSB is implemented reg mstatus_mpp; // only MSB is implemented
reg mstatus_mprv; reg mstatus_mprv;
reg mstatus_tw;
wire wen_m_mode = wen && (m_mode || debug_mode); 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_mie <= 1'b0;
mstatus_mpp <= 1'b1; mstatus_mpp <= 1'b1;
mstatus_mprv <= 1'b0; mstatus_mprv <= 1'b0;
mstatus_tw <= 1'b0;
end else if (CSR_M_TRAP) begin end else if (CSR_M_TRAP) begin
if (trap_enter_vld && trap_enter_rdy && !debug_suppresses_trap_update) begin if (trap_enter_vld && trap_enter_rdy && !debug_suppresses_trap_update) begin
if (except == EXCEPT_MRET) begin if (except == EXCEPT_MRET) begin
@ -184,7 +187,8 @@ always @ (posedge clk or negedge rst_n) begin
mstatus_mie <= wdata_update[3]; mstatus_mie <= wdata_update[3];
mstatus_mprv <= wdata_update[17]; mstatus_mprv <= wdata_update[17];
// Note only the MSB of MPP is implemented. It reads back as 11 or 00. // 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 end else if (wen && debug_mode && addr == DCSR && U_MODE && DEBUG_SUPPORT) begin
// Debugger can change/observe core state directly through // Debugger can change/observe core state directly through
// dcsr.prv (this doesn't affect debugger operation, as all // dcsr.prv (this doesn't affect debugger operation, as all
@ -195,6 +199,9 @@ always @ (posedge clk or negedge rst_n) begin
end end
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; reg [XLEN-1:0] mscratch;
always @ (posedge clk or negedge rst_n) begin always @ (posedge clk or negedge rst_n) begin
@ -510,10 +517,10 @@ always @ (*) begin
1'b0, // Never any dirty state besides GPRs 1'b0, // Never any dirty state besides GPRs
8'd0, // (WPRI) 8'd0, // (WPRI)
1'b0, // TSR (Trap SRET), tied 0 if no S mode. 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, // TVM (trap virtual memory), tied 0 if no S mode.
1'b0, // MXR (Make eXecutable Readable), tied 0 if not S mode. 1'b0, // MXR (Make eXecutable Readable), tied 0 if no S mode.
1'b0, // SUM, tied 0, we have no S or U mode 1'b0, // SUM, tied 0 if no S mode
mstatus_mprv, // MPRV (modify privilege) mstatus_mprv, // MPRV (modify privilege)
4'd0, // XS, FS always "off" (no extension state to clear!) 4'd0, // XS, FS always "off" (no extension state to clear!)
{2{mstatus_mpp}}, // MPP (M-mode previous privilege), only M and U supported {2{mstatus_mpp}}, // MPP (M-mode previous privilege), only M and U supported

View File

@ -10,23 +10,25 @@ module hazard3_decode #(
, ,
`include "hazard3_width_const.vh" `include "hazard3_width_const.vh"
) ( ) (
input wire clk, input wire clk,
input wire rst_n, input wire rst_n,
input wire [31:0] fd_cir, input wire [31:0] fd_cir,
input wire [1:0] fd_cir_err, input wire [1:0] fd_cir_err,
input wire [1:0] fd_cir_vld, input wire [1:0] fd_cir_vld,
output wire [1:0] df_cir_use, output wire [1:0] df_cir_use,
output wire df_cir_lock, output wire df_cir_lock,
output wire [W_ADDR-1:0] d_pc, 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, output wire d_starved,
input wire x_stall, input wire x_stall,
input wire f_jump_now, input wire f_jump_now,
input wire [W_ADDR-1:0] f_jump_target, input wire [W_ADDR-1:0] f_jump_target,
input wire x_jump_not_except, input wire x_jump_not_except,
output reg [W_DATA-1:0] d_imm, output reg [W_DATA-1:0] d_imm,
output reg [W_REGADDR-1:0] d_rs1, 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_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: 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_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_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_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_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_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_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_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_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_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_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) begin d_wfi = 1'b1; 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 default: begin d_invalid_32bit = 1'b1; end
endcase endcase