diff --git a/hdl/hazard3_core.v b/hdl/hazard3_core.v index 32c82f9..eb78b6e 100644 --- a/hdl/hazard3_core.v +++ b/hdl/hazard3_core.v @@ -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: diff --git a/hdl/hazard3_csr.v b/hdl/hazard3_csr.v index 0a026ee..9b1c190 100644 --- a/hdl/hazard3_csr.v +++ b/hdl/hazard3_csr.v @@ -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 diff --git a/hdl/hazard3_frontend.v b/hdl/hazard3_frontend.v index 89b37ff..ae47cbd 100644 --- a/hdl/hazard3_frontend.v +++ b/hdl/hazard3_frontend.v @@ -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 @@ -247,7 +253,7 @@ always @ (posedge clk or negedge rst_n) begin // Make sure these clear properly (have been subtle historic bugs here) assert(!unaligned_jump_aph); assert(!unaligned_jump_dph); - end + end end end `endif @@ -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