Integrate PMP, and fix a couple of PMP bugs

This commit is contained in:
Luke Wren 2022-05-24 19:57:45 +01:00
parent 4878a752d6
commit c93228d13e
5 changed files with 193 additions and 18 deletions

View File

@ -12,4 +12,5 @@ file hazard3_instr_decompress.v
file hazard3_decode.v
file hazard3_csr.v
file hazard3_regfile_1w2r.v
file hazard3_pmp.v
include .

View File

@ -434,7 +434,9 @@ hazard3_alu #(
.cmp (x_alu_cmp)
);
// AHB transaction request
// Load/store bus request
wire x_loadstore_pmp_fail;
wire x_unaligned_addr = d_memop != MEMOP_NONE && (
bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] ||
@ -574,6 +576,7 @@ always @ (*) begin
bus_aph_req_d = x_memop_vld && !(
x_stall_on_raw ||
x_stall_on_exclusive_overlap ||
x_loadstore_pmp_fail ||
x_unaligned_addr ||
m_trap_enter_soon ||
(xm_wfi && !m_wfi_stall_clear) // FIXME will cause a timing issue, better to stall til *after* clear
@ -713,6 +716,51 @@ wire x_jump_req_if_aligned = !x_stall_on_raw && (
assign x_jump_req = x_jump_req_if_aligned && !x_jump_misaligned;
// Memory protection
wire [11:0] x_pmp_cfg_addr;
wire x_pmp_cfg_wen;
wire [W_DATA-1:0] x_pmp_cfg_wdata;
wire [W_DATA-1:0] x_pmp_cfg_rdata;
wire x_exec_pmp_fail;
generate
if (PMP_REGIONS > 0) begin: have_pmp
hazard3_pmp #(
`include "hazard3_config_inst.vh"
) pmp (
.clk (clk),
.rst_n (rst_n),
.mstatus_mxr (1'b0), // Only used when S mode present
.cfg_addr (x_pmp_cfg_addr),
.cfg_wen (x_pmp_cfg_wen),
.cfg_wdata (x_pmp_cfg_wdata),
.cfg_rdata (x_pmp_cfg_rdata),
.i_addr (d_pc),
.i_instr_is_32bit (&fd_cir[1:0]),
.i_m_mode (x_mmode_execution),
.i_kill (x_exec_pmp_fail),
.d_addr (bus_haddr_d),
.d_m_mode (x_mmode_loadstore),
.d_write (bus_hwrite_d),
.d_kill (x_loadstore_pmp_fail)
);
end else begin: no_pmp
assign x_pmp_cfg_rdata = 1'b0;
assign x_loadstore_pmp_fail = 1'b0;
assign x_exec_pmp_fail = 1'b0;
end
endgenerate
// CSRs and Trap Handling
wire [W_DATA-1:0] x_csr_wdata = d_csr_w_imm ?
@ -754,13 +802,16 @@ end
wire [W_ADDR-1:0] m_exception_return_addr;
wire [W_EXCEPT-1:0] x_except =
x_jump_req_if_aligned && x_jump_misaligned ? EXCEPT_INSTR_MISALIGN :
x_csr_illegal_access ? EXCEPT_INSTR_ILLEGAL :
|EXTENSION_A && x_unaligned_addr && d_memop_is_amo ? EXCEPT_STORE_ALIGN :
|EXTENSION_A && x_amo_phase == 3'h4 && x_unaligned_addr? EXCEPT_STORE_ALIGN :
|EXTENSION_A && x_amo_phase == 3'h4 ? EXCEPT_STORE_FAULT :
x_unaligned_addr && x_memop_write ? EXCEPT_STORE_ALIGN :
x_unaligned_addr && !x_memop_write ? EXCEPT_LOAD_ALIGN : d_except;
x_jump_req_if_aligned && x_jump_misaligned ? EXCEPT_INSTR_MISALIGN :
x_exec_pmp_fail ? EXCEPT_INSTR_FAULT :
x_csr_illegal_access ? EXCEPT_INSTR_ILLEGAL :
|EXTENSION_A && x_unaligned_addr && d_memop_is_amo ? EXCEPT_STORE_ALIGN :
|EXTENSION_A && x_amo_phase == 3'h4 && x_unaligned_addr ? EXCEPT_STORE_ALIGN :
|EXTENSION_A && x_amo_phase == 3'h4 ? EXCEPT_STORE_FAULT :
x_unaligned_addr && x_memop_write ? EXCEPT_STORE_ALIGN :
x_unaligned_addr && !x_memop_write ? EXCEPT_LOAD_ALIGN :
x_loadstore_pmp_fail && (d_memop_is_amo || bus_hwrite_d) ? EXCEPT_STORE_FAULT :
x_loadstore_pmp_fail ? EXCEPT_LOAD_FAULT : d_except;
// If an instruction causes an exceptional condition we do not consider it to have retired.
wire x_except_counts_as_retire = x_except == EXCEPT_EBREAK || x_except == EXCEPT_MRET || x_except == EXCEPT_ECALL;
@ -821,6 +872,11 @@ hazard3_csr #(
.irq_timer (timer_irq),
.except (xm_except),
.pmp_cfg_addr (x_pmp_cfg_addr),
.pmp_cfg_wen (x_pmp_cfg_wen),
.pmp_cfg_wdata (x_pmp_cfg_wdata),
.pmp_cfg_rdata (x_pmp_cfg_rdata),
// Other CSR-specific signalling
.instr_ret (|x_instr_ret)
);
@ -1080,4 +1136,6 @@ hazard3_regfile_1w2r #(
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

View File

@ -82,9 +82,9 @@ module hazard3_csr #(
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,
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,
@ -95,6 +95,11 @@ module hazard3_csr #(
input wire irq_software,
input wire irq_timer,
// PMP config interface
output wire [11:0] pmp_cfg_addr,
output reg pmp_cfg_wen,
output wire [W_DATA-1:0] pmp_cfg_wdata,
input wire [W_DATA-1:0] pmp_cfg_rdata,
// Other CSR-specific signalling
input wire instr_ret
@ -451,6 +456,7 @@ wire match_uro = U_MODE && !wen_soon;
always @ (*) begin
decode_match = 1'b0;
rdata = {XLEN{1'b0}};
pmp_cfg_wen = 1'b0;
case (addr)
// ------------------------------------------------------------------------
@ -712,6 +718,112 @@ always @ (*) begin
};
end
// ------------------------------------------------------------------------
// PMP CSRs (bridge to PMP config interface)
// If PMP is present, all 16 registers are present, but some may be WARL'd
// to 0 depending on how many regions are actually implemented.
PMPCFG0: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPCFG1: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPCFG2: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPCFG3: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR0: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR1: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR2: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR3: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR4: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR5: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR6: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR7: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR8: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR9: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR10: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR11: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR12: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR13: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR14: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
PMPADDR15: if (PMP_REGIONS > 0) begin
decode_match = match_mrw;
pmp_cfg_wen = match_mrw && wen;
rdata = pmp_cfg_rdata;
end
// ------------------------------------------------------------------------
// U-mode CSRs
@ -1036,6 +1148,9 @@ assign mcause_code_next = exception_req_any ? {2'h0, except} : mcause_irq_num;
// ----------------------------------------------------------------------------
// Privilege state outputs
assign pmp_cfg_addr = addr;
assign pmp_cfg_wdata = wdata_update;
// Effective privilege for execution. Used for:
// - Privilege level of branch target fetches (frontend keeps fetch privilege
// constant during sequential fetch)

View File

@ -274,7 +274,7 @@ 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_priv = mem_priv_r;
assign mem_addr_vld = mem_addr_vld_r && !reset_holdoff;
assign mem_size = 1'b1;

View File

@ -12,7 +12,6 @@ module hazard3_pmp #(
) (
input wire clk,
input wire rst_n,
input wire m_mode,
input wire mstatus_mxr, // make executable readable
// Config interface passed through CSR block
@ -67,18 +66,18 @@ always @ (posedge clk or negedge rst_n) begin: cfg_update
end
end else if (cfg_wen) begin
for (i = 0; i < PMP_REGIONS; i = i + 1) begin
if (cfg_addr == PMPCFG0 + i / 4) begin
if (cfg_addr == PMPCFG0 + i / 4 && !pmpcfg_l[i]) begin
pmpcfg_l[i] <= cfg_wdata[i % 4 * 8 + 7];
// TOR is not supported, gets mapped to OFF:
pmpcfg_a[i] <= {
cfg_wdata[i % 4 * 8 + 4],
cfg_wdata[i % 4 * 8 + 3] && csr[i % 4 * 8 + 4]
cfg_wdata[i % 4 * 8 + 3] && cfg_wdata[i % 4 * 8 + 4]
};
pmpcfg_r[i] <= cfg_wdata[i % 4 * 8 + 2];
pmpcfg_w[i] <= cfg_wdata[i % 4 * 8 + 1];
pmpcfg_x[i] <= cfg_wdata[i % 4 * 8 + 0];
end
if (cfg_addr == PMPADDR0 + i) begin
if (cfg_addr == PMPADDR0 + i && !pmpcfg_l[i]) begin
pmpaddr[i] <= cfg_wdata[W_ADDR-3:0];
end
end
@ -218,7 +217,7 @@ always @ (*) begin: check_i_match
i_partial_match = 1'b0;
i_l = 1'b0;
i_x = 1'b0;
for (i = PMP_REGIONS - 1; i >= 0; i = i -q 1) begin
for (i = PMP_REGIONS - 1; i >= 0; i = i - 1) begin
match_hw0 = |pmpcfg_a[i] && (i_addr & match_mask[i]) == match_addr[i];
match_hw1 = |pmpcfg_a[i] && (i_addr_hw1 & match_mask[i]) == match_addr[i];
if (match_hw0 || match_hw1) begin
@ -248,4 +247,6 @@ assign i_kill = i_partial_match || (
endmodule
`default_nettype wire
`ifndef YOSYS
`default_nettype wire
`endif