diff --git a/hdl/hazard3_config.vh b/hdl/hazard3_config.vh index 0159ab9..07f4107 100644 --- a/hdl/hazard3_config.vh +++ b/hdl/hazard3_config.vh @@ -92,29 +92,25 @@ 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, +// PMP_GRAIN: This is the "G" parameter in the privileged spec. Minimum PMP +// region size is 1 << (G + 2) bytes. If G > 0, PMCFG.A can not be set to +// NA4 (will get set to OFF instead). If G > 1, the G - 1 LSBs of pmpaddr are +// read-only-0 when PMPCFG.A is OFF, and read-only-1 when PMPCFG.A is NAPOT. +parameter PMP_GRAIN = 0, -// 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, +// PMPADDR_HARDWIRED: If a bit is 1, the corresponding region's pmpaddr and +// pmpcfg registers are read-only. PMP_GRAIN is ignored on hardwired regions. +// It's recommended to make hardwired regions the highest-numbered, so they +// can be overridden by lower-numbered regions. +parameter PMP_HARDWIRED = PMP_REGIONS > 0 ? {PMP_REGIONS{1'b0}} : 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, +// PMPADDR_HARDWIRED_ADDR: Values of pmpaddr registers whose PMP_HARDWIRED +// bits are set to 1. Non-hardwired regions reset to all-zeroes. +parameter PMP_HARDWIRED_ADDR = PMP_REGIONS > 0 ? {PMP_REGIONS{32'h0}} : 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, +// PMPCFG_RESET_VAL: Values of pmpcfg registers whose PMP_HARDWIRED bits are +// set to 1. Non-hardwired regions reset to all zeroes. +parameter PMP_HARDWIRED_CFG = PMP_REGIONS > 0 ? {PMP_REGIONS{8'h00}} : 1'b0, // DEBUG_SUPPORT: Support for run/halt and instruction injection from an // external Debug Module, support for Debug Mode, and Debug Mode CSRs. diff --git a/hdl/hazard3_config_inst.vh b/hdl/hazard3_config_inst.vh index f321ecc..dca5c71 100644 --- a/hdl/hazard3_config_inst.vh +++ b/hdl/hazard3_config_inst.vh @@ -23,11 +23,10 @@ .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), +.PMP_GRAIN (PMP_GRAIN), +.PMP_HARDWIRED (PMP_HARDWIRED), +.PMP_HARDWIRED_ADDR (PMP_HARDWIRED_ADDR), +.PMP_HARDWIRED_CFG (PMP_HARDWIRED_CFG), .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 ee4f9b8..b6697a1 100644 --- a/hdl/hazard3_pmp.v +++ b/hdl/hazard3_pmp.v @@ -57,45 +57,38 @@ 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] <= 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]; + pmpcfg_l[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_CFG[8 * i + 7] : 1'b0; + pmpcfg_a[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_CFG[8 * i + 3 +: 2] : 2'h0; + pmpcfg_r[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_CFG[8 * i + 2] : 1'b0; + pmpcfg_w[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_CFG[8 * i + 1] : 1'b0; + pmpcfg_x[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_CFG[8 * i + 0] : 1'b0; + + pmpaddr[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_ADDR[32 * i +: 30] : + PMP_GRAIN > 1 ? ~(~30'h0 << (PMP_GRAIN - 1)) : 30'h0; 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 - - if (PMPCFG_WRITE_MASK[i * 8 + 7]) + if (!PMP_HARDWIRED[i]) begin + if (cfg_addr == PMPCFG0 + i / 4 && !pmpcfg_l[i]) begin 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]; + // 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 && PMP_GRAIN > 0 ? PMP_A_OFF : + cfg_wdata[i % 4 * 8 + 3 +: 2]; + end + if (cfg_addr == PMPADDR0 + i && !pmpcfg_l[i]) begin + if (PMP_GRAIN > 1) begin + pmpaddr[i] <= cfg_wdata[W_ADDR-3:0] | ~(~30'h0 << (PMP_GRAIN - 1)); + end else begin + pmpaddr[i] <= cfg_wdata[W_ADDR-3:0]; + end + end end - if (cfg_addr == PMPADDR0 + i && !pmpcfg_l[i]) begin - 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 end @@ -114,7 +107,15 @@ always @ (*) begin: cfg_read pmpcfg_x[i] }; end else if (cfg_addr == PMPADDR0 + i) begin - cfg_rdata[W_ADDR-3:0] = pmpaddr[i]; + // If G > 1, the G-1 LSBs of pmpaddr_i are read-only-zero when + // region is OFF, and read-only-one when region is NAPOT. + if (PMP_GRAIN > 1 && !PMP_HARDWIRED[i]) begin + cfg_rdata[W_ADDR-3:0] = pmpaddr[i] & ~( + {30{pmpcfg_a[i] != PMP_A_OFF}} & ~(~30'h0 << (PMP_GRAIN - 1)) + ); + end else begin + cfg_rdata[W_ADDR-3:0] = pmpaddr[i]; + end end end end