From e0a9fb731244c9fd766ad8928ef9974481059df9 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 3 Jun 2022 01:18:33 +0100 Subject: [PATCH] Add option to hardwire PMP regions, or reduce their granularity --- hdl/hazard3_config.vh | 32 ++++++++++++++++++++++-- hdl/hazard3_config_inst.vh | 5 ++++ hdl/hazard3_pmp.v | 50 +++++++++++++++++++++++++------------- 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/hdl/hazard3_config.vh b/hdl/hazard3_config.vh index 96fcada..0159ab9 100644 --- a/hdl/hazard3_config.vh +++ b/hdl/hazard3_config.vh @@ -34,7 +34,7 @@ parameter RESET_VECTOR = 32'h0, parameter MTVEC_INIT = 32'h00000000, // ---------------------------------------------------------------------------- -// RISC-V ISA and CSR support +// RISC-V ISA support // EXTENSION_A: Support for atomic read/modify/write instructions parameter EXTENSION_A = 1, @@ -65,7 +65,11 @@ parameter EXTENSION_ZBKB = 1, // Optional, since a plain branch/jump will also flush the prefetch queue. parameter EXTENSION_ZIFENCEI = 1, -// Note the Zicsr extension is implied by any of the following CSR support: +// Note the Zicsr extension is implied by any of CSR_M_MANDATORY, CSR_M_TRAP, +// CSR_COUNTER. + +// ---------------------------------------------------------------------------- +// CSR support // CSR_M_MANDATORY: Bare minimum CSR support e.g. misa. Spec says must = 1 if // CSRs are present, but I won't tell anyone. @@ -88,6 +92,30 @@ parameter U_MODE = 0, // PMP is more useful if U mode is supported, but this is not a requirement. parameter PMP_REGIONS = 0, +// PMPADDR_WRITE_MASK: mask of which pmpaddr bits are writable. Can reduce +// region granularity, or create hardwired regions. If a register is +// partially writable, it's recommended to set PMP_NO_NA4 for that region, so +// that PMPCFG.A only permits OFF and NAPOT values. +parameter PMPADDR_WRITE_MASK = PMP_REGIONS > 0 ? {PMP_REGIONS{~32'h0}} : 1'b0, + +// PMPADDR_RESET_VAL: provide reset values for pmpaddr registers. The +// highest-numbered PMP register is listed first in this mask. Note that +// RISC-V pmpaddr registers are a right-shift by 2 of the physical address. +parameter PMPADDR_RESET_VAL = PMP_REGIONS > 0 ? {PMP_REGIONS{32'h0}} : 1'b0, + +// PMPCFG_WRITE_MASK: mask of which pmpcfg bits are writable. The reserved +// bits [6:5] are ignored, and will never be writable. +parameter PMPCFG_WRITE_MASK = PMP_REGIONS > 0 ? {PMP_REGIONS{8'hff}} : 1'b0, + +// PMPCFG_RESET_VAL: reset values for pmpcfg registers. For regions that are +// not fully hardwired, it's recommended to initialise A and L to 0. +parameter PMPCFG_RESET_VAL = PMP_REGIONS > 0 ? {PMP_REGIONS{8'h00}} : 1'b0, + +// PMP_CFG_NO_NA4: disable support for the NA4 region type on a per-region +// basis, making the minimum region size 8 bytes. Recommended if the pmpaddr +// register has had its LSBs tied off. +parameter PMPCFG_NO_NA4 = PMP_REGIONS > 0 ? {PMP_REGIONS{1'b0}} : 1'b0, + // DEBUG_SUPPORT: Support for run/halt and instruction injection from an // external Debug Module, support for Debug Mode, and Debug Mode CSRs. // Requires: CSR_M_MANDATORY, CSR_M_TRAP. diff --git a/hdl/hazard3_config_inst.vh b/hdl/hazard3_config_inst.vh index c1b2297..f321ecc 100644 --- a/hdl/hazard3_config_inst.vh +++ b/hdl/hazard3_config_inst.vh @@ -23,6 +23,11 @@ .CSR_COUNTER (CSR_COUNTER), .U_MODE (U_MODE), .PMP_REGIONS (PMP_REGIONS), +.PMPADDR_WRITE_MASK (PMPADDR_WRITE_MASK), +.PMPADDR_RESET_VAL (PMPADDR_RESET_VAL), +.PMPCFG_WRITE_MASK (PMPCFG_WRITE_MASK), +.PMPCFG_RESET_VAL (PMPCFG_RESET_VAL), +.PMPCFG_NO_NA4 (PMPCFG_NO_NA4), .DEBUG_SUPPORT (DEBUG_SUPPORT), .NUM_IRQ (NUM_IRQ), .MVENDORID_VAL (MVENDORID_VAL), diff --git a/hdl/hazard3_pmp.v b/hdl/hazard3_pmp.v index 64aa55e..ee4f9b8 100644 --- a/hdl/hazard3_pmp.v +++ b/hdl/hazard3_pmp.v @@ -57,28 +57,44 @@ always @ (posedge clk or negedge rst_n) begin: cfg_update integer i; if (!rst_n) begin for (i = 0; i < PMP_REGIONS; i = i + 1) begin - pmpcfg_l[i] <= 1'b0; - pmpcfg_a[i] <= 2'd0; - pmpcfg_r[i] <= 1'b0; - pmpcfg_w[i] <= 1'b0; - pmpcfg_x[i] <= 1'b0; - pmpaddr[i] <= {W_ADDR-2{1'b0}}; + pmpcfg_l[i] <= PMPCFG_RESET_VAL[8 * i + 7]; + pmpcfg_a[i] <= PMPCFG_RESET_VAL[8 * i + 3 +: 2]; + pmpcfg_r[i] <= PMPCFG_RESET_VAL[8 * i + 2]; + pmpcfg_w[i] <= PMPCFG_RESET_VAL[8 * i + 1]; + pmpcfg_x[i] <= PMPCFG_RESET_VAL[8 * i + 0]; + pmpaddr[i] <= PMPADDR_RESET_VAL[32 * i +: 30]; end end else if (cfg_wen) begin for (i = 0; i < PMP_REGIONS; i = i + 1) 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] && 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]; + + if (PMPCFG_WRITE_MASK[i * 8 + 7]) + pmpcfg_l[i] <= cfg_wdata[i % 4 * 8 + 7]; + + // Unsupported A values are mapped to OFF (it's a WARL field). + pmpcfg_a[i] <= + cfg_wdata[i % 4 * 8 + 3 +: 2] == PMP_A_TOR ? PMP_A_OFF : + cfg_wdata[i % 4 * 8 + 3 +: 2] == PMP_A_NA4 && PMPCFG_NO_NA4[i] ? PMP_A_OFF : + cfg_wdata[i % 4 * 8 + 3 +: 2]; + + // Suppress changes to unwritable bits. + if (!PMPCFG_WRITE_MASK[i * 8 + 4]) + pmpcfg_a[i][1] <= pmpcfg_a[i][1]; + if (!PMPCFG_WRITE_MASK[i * 8 + 3]) + pmpcfg_a[i][0] <= pmpcfg_a[i][0]; + + if (PMPCFG_WRITE_MASK[i * 8 + 2]) + pmpcfg_r[i] <= cfg_wdata[i % 4 * 8 + 2]; + if (PMPCFG_WRITE_MASK[i * 8 + 1]) + pmpcfg_w[i] <= cfg_wdata[i % 4 * 8 + 1]; + if (PMPCFG_WRITE_MASK[i * 8 + 0]) + pmpcfg_x[i] <= cfg_wdata[i % 4 * 8 + 0]; + end if (cfg_addr == PMPADDR0 + i && !pmpcfg_l[i]) begin - pmpaddr[i] <= cfg_wdata[W_ADDR-3:0]; + pmpaddr[i] <= + cfg_wdata[W_ADDR-3:0] & PMPADDR_WRITE_MASK[i * 32 +: 30] | + pmpaddr[i] & ~PMPADDR_WRITE_MASK[i * 32 +: 30]; end end end @@ -227,7 +243,7 @@ always @ (*) begin: check_i_match i_x = pmpcfg_x[i]; end end -end +end // ---------------------------------------------------------------------------- // Access rules