Plumb privilege state through to the bus ports

This commit is contained in:
Luke Wren 2022-05-24 18:24:34 +01:00
parent cfed35b3da
commit 4878a752d6
3 changed files with 63 additions and 6 deletions

View File

@ -81,14 +81,12 @@ wire debug_mode;
assign dbg_halted = DEBUG_SUPPORT && debug_mode;
assign dbg_running = DEBUG_SUPPORT && !debug_mode;
assign bus_priv_i = 1'b1;
always @ (*) bus_priv_d = 1'b1;
// ----------------------------------------------------------------------------
// Pipe Stage F
wire f_jump_req;
wire [W_ADDR-1:0] f_jump_target;
wire f_jump_priv;
wire f_jump_rdy;
wire f_jump_now = f_jump_req && f_jump_rdy;
@ -118,6 +116,7 @@ hazard3_frontend #(
.mem_size (f_mem_size),
.mem_addr (bus_haddr_i),
.mem_priv (bus_priv_i),
.mem_addr_vld (bus_aph_req_i),
.mem_addr_rdy (bus_aph_ready_i),
@ -126,6 +125,7 @@ hazard3_frontend #(
.mem_data_vld (bus_dph_ready_i),
.jump_target (f_jump_target),
.jump_priv (f_jump_priv),
.jump_target_vld (f_jump_req),
.jump_target_rdy (f_jump_rdy),
@ -257,6 +257,11 @@ 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;
reg [W_REGADDR-1:0] xm_rs1;
reg [W_REGADDR-1:0] xm_rs2;
reg [W_REGADDR-1:0] xm_rd;
@ -554,6 +559,7 @@ always @ (*) begin
// Need to be careful not to use anything hready-sourced to gate htrans!
bus_haddr_d = x_addr_sum;
bus_hwrite_d = x_memop_write;
bus_priv_d = x_mmode_loadstore;
case (d_memop)
MEMOP_LW: bus_hsize_d = HSIZE_WORD;
MEMOP_SW: bus_hsize_d = HSIZE_WORD;
@ -804,6 +810,10 @@ hazard3_csr #(
.mepc_in (m_exception_return_addr),
.wfi_stall_clear (m_wfi_stall_clear),
.m_mode_execution (x_mmode_execution),
.m_mode_loadstore (x_mmode_loadstore),
.m_mode_trap_entry (m_mmode_trap_entry),
// IRQ and exception requests
.delay_irq_entry (xm_delay_irq_entry),
.irq (irq),
@ -887,6 +897,7 @@ reg [W_DATA-1:0] m_result;
assign f_jump_req = x_jump_req || m_trap_enter_vld;
assign f_jump_target = m_trap_enter_vld ? m_trap_addr : x_jump_target;
assign f_jump_priv = m_trap_enter_vld ? m_mmode_trap_entry : x_mmode_execution;
assign x_jump_not_except = !m_trap_enter_vld;
// EXCEPT_NONE clause is needed in the following sequence:

View File

@ -81,6 +81,11 @@ module hazard3_csr #(
input wire [XLEN-1:0] mepc_in,
output wire wfi_stall_clear,
// Each of these may be performed at a different privilege level from the others:
output wire m_mode_execution,
output wire m_mode_trap_entry,
output wire m_mode_loadstore,
// Exceptions must *not* be a function of bus stall.
input wire [W_EXCEPT-1:0] except,
@ -90,6 +95,7 @@ module hazard3_csr #(
input wire irq_software,
input wire irq_timer,
// Other CSR-specific signalling
input wire instr_ret
);
@ -1027,6 +1033,32 @@ assign trap_enter_soon = trap_enter_vld || (
assign mcause_irq_next = !exception_req_any;
assign mcause_code_next = exception_req_any ? {2'h0, except} : mcause_irq_num;
// ----------------------------------------------------------------------------
// Privilege state outputs
// Effective privilege for execution. Used for:
// - Privilege level of branch target fetches (frontend keeps fetch privilege
// constant during sequential fetch)
// - Checking PC against PMP execute permission
assign m_mode_execution = !U_MODE || debug_mode || m_mode;
// Effective privilege for trap entry. Used for:
// - Privilege level of trap target fetches (frontend keeps fetch privilege
// constant during sequential fetch)
assign m_mode_trap_entry = !U_MODE || (
except == EXCEPT_MRET ? mstatus_mpp : 1'b1
);
// Effective privilege for load/stores. Used for:
// - Privilege level of load/stores on the bus
// - Checking load/stores against PMP read/write permission
assign m_mode_loadstore = !U_MODE || debug_mode || ( // FIXME how does this interact with load/store racing against debug entry?
mstatus_mprv ? mstatus_mpp : m_mode
);
// ----------------------------------------------------------------------------
// Properties

View File

@ -21,6 +21,7 @@ module hazard3_frontend #(
// may not be used to compute combinational outputs.
output wire mem_size, // 1'b1 -> 32 bit access
output wire [W_ADDR-1:0] mem_addr,
output wire mem_priv,
output wire mem_addr_vld,
input wire mem_addr_rdy,
input wire [W_DATA-1:0] mem_data,
@ -32,6 +33,7 @@ module hazard3_frontend #(
// unless rdy is high. Processor *may* alter request during this time.
// Inputs must not be a function of hready.
input wire [W_ADDR-1:0] jump_target,
input wire jump_priv,
input wire jump_target_vld,
output wire jump_target_rdy,
@ -179,14 +181,18 @@ end
// Fetch addr runs ahead of the PC, in word increments.
reg [W_ADDR-1:0] fetch_addr;
reg fetch_priv;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
fetch_addr <= RESET_VECTOR;
// M-mode at reset:
fetch_priv <= 1'b1;
end else begin
if (jump_now) begin
// Post-increment if jump request is going straight through
fetch_addr <= {jump_target[W_ADDR-1:2] + (mem_addr_rdy && !mem_addr_hold), 2'b00};
fetch_priv <= jump_priv || !U_MODE;
end else if (mem_addr_vld && mem_addr_rdy) begin
fetch_addr <= fetch_addr + 32'h4;
end
@ -263,19 +269,25 @@ always @ (posedge clk or negedge rst_n)
reset_holdoff <= 1'b0;
reg [W_ADDR-1:0] mem_addr_r;
reg mem_addr_vld_r;
reg mem_priv_r;
reg mem_addr_vld_r;
// Downstream accesses are always word-sized word-aligned.
assign mem_addr = mem_addr_r;
assign mem_priv = mem_addr_r;
assign mem_addr_vld = mem_addr_vld_r && !reset_holdoff;
assign mem_size = 1'b1;
always @ (*) begin
mem_addr_r = {W_ADDR{1'b0}};
mem_priv_r = fetch_priv;
mem_addr_vld_r = 1'b1;
case (1'b1)
mem_addr_hold : begin mem_addr_r = fetch_addr; end
jump_target_vld : begin mem_addr_r = {jump_target[W_ADDR-1:2], 2'b00}; end
jump_target_vld : begin
mem_addr_r = {jump_target[W_ADDR-1:2], 2'b00};
mem_priv_r = jump_priv || !U_MODE;
end
DEBUG_SUPPORT && debug_mode : begin mem_addr_vld_r = 1'b0; end
!fetch_stall : begin mem_addr_r = fetch_addr; end
default : begin mem_addr_vld_r = 1'b0; end
@ -443,4 +455,6 @@ end
endmodule
`ifndef YOSYS
`default_nettype wire
`endif