Integrate PMP, and fix a couple of PMP bugs
This commit is contained in:
parent
4878a752d6
commit
c93228d13e
|
@ -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 .
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue