diff --git a/config/rv32e/config.vh b/config/rv32e/config.vh index 7b0f43913..f178c7468 100644 --- a/config/rv32e/config.vh +++ b/config/rv32e/config.vh @@ -137,6 +137,7 @@ localparam logic IDIV_ON_FPU = 0; // Legal number of PMP entries are 0, 16, or 64 localparam PMP_ENTRIES = 32'd0; +localparam PMP_G = 32'b0; // grain of 4 bytes is supported for uncached RV32 // Address space localparam logic [63:0] RESET_VECTOR = 64'h80000000; diff --git a/config/rv32gc/config.vh b/config/rv32gc/config.vh index 14c100a49..9bb7b26f3 100644 --- a/config/rv32gc/config.vh +++ b/config/rv32gc/config.vh @@ -137,6 +137,9 @@ localparam logic IDIV_ON_FPU = 0; // Legal number of PMP entries are 0, 16, or 64 localparam PMP_ENTRIES = 32'd16; +// grain size should be a full cache line to avoid problems with accesses within a cache line +// that span grain boundaries but are handled without a spill +localparam PMP_G = 32'd4; // 64 bytes for 512-bit cache line // Address space localparam logic [63:0] RESET_VECTOR = 64'h80000000; diff --git a/config/rv32gc/imperas.ic b/config/rv32gc/imperas.ic index 254c32858..12cd358aa 100644 --- a/config/rv32gc/imperas.ic +++ b/config/rv32gc/imperas.ic @@ -45,7 +45,9 @@ # PMP Configuration --override cpu/PMP_registers=16 ---override cpu/PMP_undefined=T +--override cpu/PMP_grain=4 # 64-byte grains to match cache line width +--override cpu/PMP_decompose=T # unaligned accesses are decomposed into separate aligned accesses +--override cpu/PMP_undefined=T # access to unimplemented PMP registers cause illegal instruction exception # PMA Settings # 'r': read access allowed diff --git a/config/rv32i/config.vh b/config/rv32i/config.vh index 2eb40c8d4..2fe6fbeaf 100644 --- a/config/rv32i/config.vh +++ b/config/rv32i/config.vh @@ -137,6 +137,7 @@ localparam logic IDIV_ON_FPU = 0; // Legal number of PMP entries are 0, 16, or 64 localparam PMP_ENTRIES = 32'd0; +localparam PMP_G = 32'b0; // grain of 4 bytes is supported for uncached RV32 // Address space localparam logic [63:0] RESET_VECTOR = 64'h80000000; diff --git a/config/rv32imc/config.vh b/config/rv32imc/config.vh index 6ec9d9ace..22a9a3abb 100644 --- a/config/rv32imc/config.vh +++ b/config/rv32imc/config.vh @@ -137,6 +137,7 @@ localparam logic IDIV_ON_FPU = 0; // Legal number of PMP entries are 0, 16, or 64 localparam PMP_ENTRIES = 32'd0; +localparam PMP_G = 32'b0; // grain of 4 bytes is supported for uncached RV32 // Address space localparam logic [63:0] RESET_VECTOR = 64'h80000000; diff --git a/config/rv64gc/config.vh b/config/rv64gc/config.vh index 9c0bef1a1..d4fb6cdbe 100644 --- a/config/rv64gc/config.vh +++ b/config/rv64gc/config.vh @@ -138,6 +138,10 @@ localparam logic IDIV_ON_FPU = 1; // Legal number of PMP entries are 0, 16, or 64 localparam PMP_ENTRIES = 32'd16; +// grain size should be a full cache line to avoid problems with accesses within a cache line +// that span grain boundaries but are handled without a spill +localparam PMP_G = 32'd4; //e.g. 4 for 64-byte grains (512-bit cache lines) + // Address space localparam logic [63:0] RESET_VECTOR = 64'h0000000080000000; diff --git a/config/rv64gc/imperas.ic b/config/rv64gc/imperas.ic index 2e2a74478..5751c0990 100644 --- a/config/rv64gc/imperas.ic +++ b/config/rv64gc/imperas.ic @@ -48,7 +48,9 @@ # PMP Configuration --override cpu/PMP_registers=16 ---override cpu/PMP_undefined=T +--override cpu/PMP_grain=4 # 64-byte grains to match cache line width +--override cpu/PMP_decompose=T # unaligned accesses are decomposed into separate aligned accesses +--override cpu/PMP_undefined=T # access to unimplemented PMP registers cause illegal instruction exception # PMA Settings # 'r': read access allowed diff --git a/config/rv64i/config.vh b/config/rv64i/config.vh index 1779d764d..d6e312408 100644 --- a/config/rv64i/config.vh +++ b/config/rv64i/config.vh @@ -137,6 +137,7 @@ localparam logic IDIV_ON_FPU = 0; // Legal number of PMP entries are 0, 16, or 64 localparam PMP_ENTRIES = 32'd0; +localparam PMP_G = 32'b0; // grain of 8 bytes is supported for uncached RV64 // Address space localparam logic [63:0] RESET_VECTOR = 64'h0000000080000000; diff --git a/config/shared/parameter-defs.vh b/config/shared/parameter-defs.vh index 88de34afc..3f25d6230 100644 --- a/config/shared/parameter-defs.vh +++ b/config/shared/parameter-defs.vh @@ -48,6 +48,7 @@ localparam cvw_t P = '{ IDIV_BITSPERCYCLE : IDIV_BITSPERCYCLE, IDIV_ON_FPU : IDIV_ON_FPU, PMP_ENTRIES : PMP_ENTRIES, + PMP_G : PMP_G, RESET_VECTOR : RESET_VECTOR, WFI_TIMEOUT_BIT : WFI_TIMEOUT_BIT, DTIM_SUPPORTED : DTIM_SUPPORTED, diff --git a/src/cvw.sv b/src/cvw.sv index ed0493484..fd7227306 100644 --- a/src/cvw.sv +++ b/src/cvw.sv @@ -95,6 +95,7 @@ typedef struct packed { // Legal number of PMP entries are 0, 16, or 64 int PMP_ENTRIES; + int PMP_G; // grain // Address space logic [63:0] RESET_VECTOR; diff --git a/testbench/common/riscvassertions.sv b/testbench/common/riscvassertions.sv index 4481d3f96..e756a7b6d 100644 --- a/testbench/common/riscvassertions.sv +++ b/testbench/common/riscvassertions.sv @@ -22,12 +22,14 @@ module riscvassertions import cvw::*; #(parameter cvw_t P); initial begin assert (P.PMP_ENTRIES == 0 | P.PMP_ENTRIES==16 | P.PMP_ENTRIES==64) else $fatal(1, "Illegal number of PMP entries: PMP_ENTRIES must be 0, 16, or 64"); - assert (P.S_SUPPORTED | P.VIRTMEM_SUPPORTED == 0) else $fatal(1, "Virtual memory requires S mode support"); + assert (P.PMP_G > 0 | P.XLEN == 32) else $fatal(1, "RV64 requires PMP_G at least 1 to avoid checking for 8-byte accesses to 4-byte region"); + assert (P.PMP_G >= $clog2(P.DCACHE_LINELENINBITS)-2 | !P.ZICCLSM_SUPPORTED | P.PMP_ENTRIES == 0) else $fatal(1, "Systems that support misaligned data with PMP must have grain size of at least one cache line so accesses that span grains will also cause spills"); + assert (P.PMP_G >= $clog2(P.ICACHE_LINELENINBITS)-2 | !P.ZCA_SUPPORTED | P.PMP_ENTRIES == 0 | !P.ICACHE_SUPPORTED) else $fatal(1, "Systems that support compressed instructions with PMP must have grain size of at least one cache line so fetches that span grains will also cause spills"); assert (P.IDIV_BITSPERCYCLE == 1 | P.IDIV_BITSPERCYCLE==2 | P.IDIV_BITSPERCYCLE==4) else $fatal(1, "Illegal number of divider bits/cycle: IDIV_BITSPERCYCLE must be 1, 2, or 4"); - assert (P.F_SUPPORTED | ~P.D_SUPPORTED) else $fatal(1, "Can't support double fp (D) without supporting float (F)"); - assert (P.D_SUPPORTED | ~P.Q_SUPPORTED) else $fatal(1, "Can't support quad fp (Q) without supporting double (D)"); - assert (P.F_SUPPORTED | ~P.ZFH_SUPPORTED) else $fatal(1, "Can't support half-precision fp (ZFH) without supporting float (F)"); - assert (P.DCACHE_SUPPORTED | ~P.F_SUPPORTED | P.FLEN <= P.XLEN) else $fatal(1, "Data cache required to support FLEN > XLEN because AHB/DTIM bus width is XLEN"); + assert (P.F_SUPPORTED | !P.D_SUPPORTED) else $fatal(1, "Can't support double fp (D) without supporting float (F)"); + assert (P.D_SUPPORTED | !P.Q_SUPPORTED) else $fatal(1, "Can't support quad fp (Q) without supporting double (D)"); + assert (P.F_SUPPORTED | !P.ZFH_SUPPORTED) else $fatal(1, "Can't support half-precision fp (ZFH) without supporting float (F)"); + assert (P.DCACHE_SUPPORTED | !P.F_SUPPORTED | P.FLEN <= P.XLEN) else $fatal(1, "Data cache required to support FLEN > XLEN because AHB/DTIM bus width is XLEN"); assert (P.I_SUPPORTED ^ P.E_SUPPORTED) else $fatal(1, "Exactly one of I and E must be supported"); assert (P.DCACHE_WAYSIZEINBYTES <= 4096 | (!P.DCACHE_SUPPORTED) | P.VIRTMEM_SUPPORTED == 0) else $fatal(1, "DCACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)"); assert (P.DCACHE_LINELENINBITS >= 128 | (!P.DCACHE_SUPPORTED)) else $fatal(1, "DCACHE_LINELENINBITS must be at least 128 when caches are enabled");