PMP config: separate granularity config from hardwired region config. Give correct read value for G > 1.
This commit is contained in:
		
							parent
							
								
									e0a9fb7312
								
							
						
					
					
						commit
						ae2784d0ea
					
				| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,44 +57,37 @@ 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 (!PMP_HARDWIRED[i]) begin
 | 
			
		||||
				if (cfg_addr == PMPCFG0 + i / 4 && !pmpcfg_l[i]) begin
 | 
			
		||||
 | 
			
		||||
				if (PMPCFG_WRITE_MASK[i * 8 + 7])
 | 
			
		||||
					pmpcfg_l[i] <= cfg_wdata[i % 4 * 8 + 7];
 | 
			
		||||
 | 
			
		||||
					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];
 | 
			
		||||
					// 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] == PMP_A_NA4 && PMP_GRAIN > 0 ? 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_WRITE_MASK[i * 32 +: 30] |
 | 
			
		||||
					pmpaddr[i] & ~PMPADDR_WRITE_MASK[i * 32 +: 30];
 | 
			
		||||
					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
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
| 
						 | 
				
			
			@ -114,9 +107,17 @@ always @ (*) begin: cfg_read
 | 
			
		|||
				pmpcfg_x[i]
 | 
			
		||||
			};
 | 
			
		||||
		end else if (cfg_addr == PMPADDR0 + i) begin
 | 
			
		||||
			// 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
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue