Skip to content

Commit 4de2bff

Browse files
Timmmmben-fletcher-codasip
authored andcommitted
Improve PMP support
This implements a lot of missing functionality for PMPs. * Support 64 PMPs as well as 0 and 16. * Support setting PMP grain * Return correct address bits on read (some read as 0 or 1 depending on the grain and match type) * Unlock PMPs on reset * Implement pmpcfg WARL legalisation Co-authored-by: Ben Fletcher <[email protected]>
1 parent d5e89a7 commit 4de2bff

17 files changed

+275
-297
lines changed

c_emulator/riscv_platform.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ bool sys_enable_vext(unit u)
4747
return rv_enable_vext;
4848
}
4949

50+
uint64_t sys_pmp_count(unit u)
51+
{
52+
return rv_pmp_count;
53+
}
54+
55+
uint64_t sys_pmp_grain(unit u)
56+
{
57+
return rv_pmp_grain;
58+
}
59+
5060
bool sys_enable_writable_misa(unit u)
5161
{
5262
return rv_enable_writable_misa;
@@ -67,11 +77,6 @@ bool plat_mtval_has_illegal_inst_bits(unit u)
6777
return rv_mtval_has_illegal_inst_bits;
6878
}
6979

70-
bool plat_enable_pmp(unit u)
71-
{
72-
return rv_enable_pmp;
73-
}
74-
7580
mach_bits plat_ram_base(unit u)
7681
{
7782
return rv_ram_base;

c_emulator/riscv_platform.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ bool sys_enable_writable_misa(unit);
99
bool sys_enable_writable_fiom(unit);
1010
bool sys_enable_vext(unit);
1111

12+
uint64_t sys_pmp_count(unit);
13+
uint64_t sys_pmp_grain(unit);
14+
1215
bool plat_enable_dirty_update(unit);
1316
bool plat_enable_misaligned_access(unit);
1417
bool plat_mtval_has_illegal_inst_bits(unit);
15-
bool plat_enable_pmp(unit);
1618

1719
mach_bits plat_ram_base(unit);
1820
mach_bits plat_ram_size(unit);

c_emulator/riscv_platform_impl.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#include <stdio.h>
44

55
/* Settings of the platform implementation, with common defaults. */
6-
bool rv_enable_pmp = false;
6+
uint64_t rv_pmp_count = 0;
7+
uint64_t rv_pmp_grain = 0;
8+
79
bool rv_enable_zfinx = false;
810
bool rv_enable_rvc = true;
911
bool rv_enable_next = false;

c_emulator/riscv_platform_impl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
#define DEFAULT_RSTVEC 0x00001000
1010

11-
extern bool rv_enable_pmp;
11+
extern uint64_t rv_pmp_count;
12+
extern uint64_t rv_pmp_grain;
13+
1214
extern bool rv_enable_zfinx;
1315
extern bool rv_enable_rvc;
1416
extern bool rv_enable_next;

c_emulator/riscv_sim.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ const char *RV32ISA = "RV32IMAC";
5151

5252
#define OPT_TRACE_OUTPUT 1000
5353
#define OPT_ENABLE_WRITABLE_FIOM 1001
54+
#define OPT_PMP_COUNT 1002
55+
#define OPT_PMP_GRAIN 1003
5456

5557
static bool do_dump_dts = false;
5658
static bool do_show_times = false;
@@ -119,7 +121,8 @@ char *sailcov_file = NULL;
119121
static struct option options[] = {
120122
{"enable-dirty-update", no_argument, 0, 'd' },
121123
{"enable-misaligned", no_argument, 0, 'm' },
122-
{"enable-pmp", no_argument, 0, 'P' },
124+
{"pmp-count", required_argument, 0, OPT_PMP_COUNT },
125+
{"pmp-grain", required_argument, 0, OPT_PMP_GRAIN },
123126
{"enable-next", no_argument, 0, 'N' },
124127
{"ram-size", required_argument, 0, 'z' },
125128
{"disable-compressed", no_argument, 0, 'C' },
@@ -236,6 +239,8 @@ static int process_args(int argc, char **argv)
236239
{
237240
int c;
238241
uint64_t ram_size = 0;
242+
uint64_t pmp_count = 0;
243+
uint64_t pmp_grain = 0;
239244
while (true) {
240245
c = getopt_long(argc, argv,
241246
"a"
@@ -281,9 +286,23 @@ static int process_args(int argc, char **argv)
281286
fprintf(stderr, "enabling misaligned access.\n");
282287
rv_enable_misaligned = true;
283288
break;
284-
case 'P':
285-
fprintf(stderr, "enabling PMP support.\n");
286-
rv_enable_pmp = true;
289+
case OPT_PMP_COUNT:
290+
pmp_count = atol(optarg);
291+
fprintf(stderr, "PMP count: %lld\n", pmp_count);
292+
if (pmp_count != 0 && pmp_count != 16 && pmp_count != 64) {
293+
fprintf(stderr, "invalid PMP count: must be 0, 16 or 64");
294+
exit(1);
295+
}
296+
rv_pmp_count = pmp_count;
297+
break;
298+
case OPT_PMP_GRAIN:
299+
pmp_grain = atol(optarg);
300+
fprintf(stderr, "PMP grain: %lld\n", pmp_grain);
301+
if (pmp_grain >= 64) {
302+
fprintf(stderr, "invalid PMP grain: must less than 64");
303+
exit(1);
304+
}
305+
rv_pmp_grain = pmp_grain;
287306
break;
288307
case 'C':
289308
fprintf(stderr, "disabling RVC compressed instructions.\n");

handwritten_support/riscv_extras.lem

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,6 @@ val plat_enable_misaligned_access : unit -> bool
201201
let plat_enable_misaligned_access () = false
202202
declare ocaml target_rep function plat_enable_misaligned_access = `Platform.enable_misaligned_access`
203203

204-
val plat_enable_pmp : unit -> bool
205-
let plat_enable_pmp () = false
206-
declare ocaml target_rep function plat_enable_pmp = `Platform.enable_pmp`
207-
208204
val plat_mtval_has_illegal_inst_bits : unit -> bool
209205
let plat_mtval_has_illegal_inst_bits () = false
210206
declare ocaml target_rep function plat_mtval_has_illegal_inst_bits = `Platform.mtval_has_illegal_inst_bits`

handwritten_support/riscv_extras_sequential.lem

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,6 @@ val plat_enable_misaligned_access : unit -> bool
189189
let plat_enable_misaligned_access () = false
190190
declare ocaml target_rep function plat_enable_misaligned_access = `Platform.enable_misaligned_access`
191191

192-
val plat_enable_pmp : unit -> bool
193-
let plat_enable_pmp () = false
194-
declare ocaml target_rep function plat_enable_pmp = `Platform.enable_pmp`
195-
196192
val plat_mtval_has_illegal_inst_bits : unit -> bool
197193
let plat_mtval_has_illegal_inst_bits () = false
198194
declare ocaml target_rep function plat_mtval_has_illegal_inst_bits = `Platform.mtval_has_illegal_inst_bits`

model/riscv_csr_map.sail

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,18 @@ mapping clause csr_name_map = 0x3A0 <-> "pmpcfg0"
138138
mapping clause csr_name_map = 0x3A1 <-> "pmpcfg1"
139139
mapping clause csr_name_map = 0x3A2 <-> "pmpcfg2"
140140
mapping clause csr_name_map = 0x3A3 <-> "pmpcfg3"
141+
mapping clause csr_name_map = 0x3A4 <-> "pmpcfg4"
142+
mapping clause csr_name_map = 0x3A5 <-> "pmpcfg5"
143+
mapping clause csr_name_map = 0x3A6 <-> "pmpcfg6"
144+
mapping clause csr_name_map = 0x3A7 <-> "pmpcfg7"
145+
mapping clause csr_name_map = 0x3A8 <-> "pmpcfg8"
146+
mapping clause csr_name_map = 0x3A9 <-> "pmpcfg9"
147+
mapping clause csr_name_map = 0x3AA <-> "pmpcfg10"
148+
mapping clause csr_name_map = 0x3AB <-> "pmpcfg11"
149+
mapping clause csr_name_map = 0x3AC <-> "pmpcfg12"
150+
mapping clause csr_name_map = 0x3AD <-> "pmpcfg13"
151+
mapping clause csr_name_map = 0x3AE <-> "pmpcfg14"
152+
mapping clause csr_name_map = 0x3AF <-> "pmpcfg15"
141153
mapping clause csr_name_map = 0x3B0 <-> "pmpaddr0"
142154
mapping clause csr_name_map = 0x3B1 <-> "pmpaddr1"
143155
mapping clause csr_name_map = 0x3B2 <-> "pmpaddr2"
@@ -154,6 +166,54 @@ mapping clause csr_name_map = 0x3BC <-> "pmpaddr12"
154166
mapping clause csr_name_map = 0x3BD <-> "pmpaddr13"
155167
mapping clause csr_name_map = 0x3BE <-> "pmpaddr14"
156168
mapping clause csr_name_map = 0x3BF <-> "pmpaddr15"
169+
mapping clause csr_name_map = 0x3C0 <-> "pmpaddr16"
170+
mapping clause csr_name_map = 0x3C1 <-> "pmpaddr17"
171+
mapping clause csr_name_map = 0x3C2 <-> "pmpaddr18"
172+
mapping clause csr_name_map = 0x3C3 <-> "pmpaddr19"
173+
mapping clause csr_name_map = 0x3C4 <-> "pmpaddr20"
174+
mapping clause csr_name_map = 0x3C5 <-> "pmpaddr21"
175+
mapping clause csr_name_map = 0x3C6 <-> "pmpaddr22"
176+
mapping clause csr_name_map = 0x3C7 <-> "pmpaddr23"
177+
mapping clause csr_name_map = 0x3C8 <-> "pmpaddr24"
178+
mapping clause csr_name_map = 0x3C9 <-> "pmpaddr25"
179+
mapping clause csr_name_map = 0x3CA <-> "pmpaddr26"
180+
mapping clause csr_name_map = 0x3CB <-> "pmpaddr27"
181+
mapping clause csr_name_map = 0x3CC <-> "pmpaddr28"
182+
mapping clause csr_name_map = 0x3CD <-> "pmpaddr29"
183+
mapping clause csr_name_map = 0x3CE <-> "pmpaddr30"
184+
mapping clause csr_name_map = 0x3CF <-> "pmpaddr31"
185+
mapping clause csr_name_map = 0x3D0 <-> "pmpaddr32"
186+
mapping clause csr_name_map = 0x3D1 <-> "pmpaddr33"
187+
mapping clause csr_name_map = 0x3D2 <-> "pmpaddr34"
188+
mapping clause csr_name_map = 0x3D3 <-> "pmpaddr35"
189+
mapping clause csr_name_map = 0x3D4 <-> "pmpaddr36"
190+
mapping clause csr_name_map = 0x3D5 <-> "pmpaddr37"
191+
mapping clause csr_name_map = 0x3D6 <-> "pmpaddr38"
192+
mapping clause csr_name_map = 0x3D7 <-> "pmpaddr39"
193+
mapping clause csr_name_map = 0x3D8 <-> "pmpaddr40"
194+
mapping clause csr_name_map = 0x3D9 <-> "pmpaddr41"
195+
mapping clause csr_name_map = 0x3DA <-> "pmpaddr42"
196+
mapping clause csr_name_map = 0x3DB <-> "pmpaddr43"
197+
mapping clause csr_name_map = 0x3DC <-> "pmpaddr44"
198+
mapping clause csr_name_map = 0x3DD <-> "pmpaddr45"
199+
mapping clause csr_name_map = 0x3DE <-> "pmpaddr46"
200+
mapping clause csr_name_map = 0x3DF <-> "pmpaddr47"
201+
mapping clause csr_name_map = 0x3E0 <-> "pmpaddr48"
202+
mapping clause csr_name_map = 0x3E1 <-> "pmpaddr49"
203+
mapping clause csr_name_map = 0x3E2 <-> "pmpaddr50"
204+
mapping clause csr_name_map = 0x3E3 <-> "pmpaddr51"
205+
mapping clause csr_name_map = 0x3E4 <-> "pmpaddr52"
206+
mapping clause csr_name_map = 0x3E5 <-> "pmpaddr53"
207+
mapping clause csr_name_map = 0x3E6 <-> "pmpaddr54"
208+
mapping clause csr_name_map = 0x3E7 <-> "pmpaddr55"
209+
mapping clause csr_name_map = 0x3E8 <-> "pmpaddr56"
210+
mapping clause csr_name_map = 0x3E9 <-> "pmpaddr57"
211+
mapping clause csr_name_map = 0x3EA <-> "pmpaddr58"
212+
mapping clause csr_name_map = 0x3EB <-> "pmpaddr59"
213+
mapping clause csr_name_map = 0x3EC <-> "pmpaddr60"
214+
mapping clause csr_name_map = 0x3ED <-> "pmpaddr61"
215+
mapping clause csr_name_map = 0x3EE <-> "pmpaddr62"
216+
mapping clause csr_name_map = 0x3EF <-> "pmpaddr63"
157217
/* machine counters/timers */
158218
mapping clause csr_name_map = 0xB00 <-> "mcycle"
159219
mapping clause csr_name_map = 0xB02 <-> "minstret"

model/riscv_insts_zicsr.sail

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -109,27 +109,13 @@ function readCSR csr : csreg -> xlenbits = {
109109
(0x343, _) => mtval,
110110
(0x344, _) => mip.bits,
111111

112-
(0x3A0, _) => pmpReadCfgReg(0), // pmpcfg0
113-
(0x3A1, 32) => pmpReadCfgReg(1), // pmpcfg1
114-
(0x3A2, _) => pmpReadCfgReg(2), // pmpcfg2
115-
(0x3A3, 32) => pmpReadCfgReg(3), // pmpcfg3
116-
117-
(0x3B0, _) => pmpaddr0,
118-
(0x3B1, _) => pmpaddr1,
119-
(0x3B2, _) => pmpaddr2,
120-
(0x3B3, _) => pmpaddr3,
121-
(0x3B4, _) => pmpaddr4,
122-
(0x3B5, _) => pmpaddr5,
123-
(0x3B6, _) => pmpaddr6,
124-
(0x3B7, _) => pmpaddr7,
125-
(0x3B8, _) => pmpaddr8,
126-
(0x3B9, _) => pmpaddr9,
127-
(0x3BA, _) => pmpaddr10,
128-
(0x3BB, _) => pmpaddr11,
129-
(0x3BC, _) => pmpaddr12,
130-
(0x3BD, _) => pmpaddr13,
131-
(0x3BE, _) => pmpaddr14,
132-
(0x3BF, _) => pmpaddr15,
112+
// pmpcfgN
113+
(0x3A @ idx : bits(4), _) if idx[0] == bitzero | sizeof(xlen) == 32 => pmpReadCfgReg(unsigned(idx)),
114+
// pmpaddrN. Unfortunately the PMP index does not nicely align with the CSR index bits.
115+
(0x3B @ idx : bits(4), _) => pmpReadAddrReg(unsigned(0b00 @ idx)),
116+
(0x3C @ idx : bits(4), _) => pmpReadAddrReg(unsigned(0b01 @ idx)),
117+
(0x3D @ idx : bits(4), _) => pmpReadAddrReg(unsigned(0b10 @ idx)),
118+
(0x3E @ idx : bits(4), _) => pmpReadAddrReg(unsigned(0b11 @ idx)),
133119

134120
/* machine mode counters */
135121
(0xB00, _) => mcycle[(sizeof(xlen) - 1) .. 0],
@@ -209,28 +195,17 @@ function writeCSR (csr : csreg, value : xlenbits) -> unit = {
209195
(0x343, _) => { mtval = value; Some(mtval) },
210196
(0x344, _) => { mip = legalize_mip(mip, value); Some(mip.bits) },
211197

212-
// Note: Some(value) returned below is not the legalized value due to locked entries
213-
(0x3A0, _) => { pmpWriteCfgReg(0, value); Some(pmpReadCfgReg(0)) }, // pmpcfg0
214-
(0x3A1, 32) => { pmpWriteCfgReg(1, value); Some(pmpReadCfgReg(1)) }, // pmpcfg1
215-
(0x3A2, _) => { pmpWriteCfgReg(2, value); Some(pmpReadCfgReg(2)) }, // pmpcfg2
216-
(0x3A3, 32) => { pmpWriteCfgReg(3, value); Some(pmpReadCfgReg(3)) }, // pmpcfg3
198+
// pmpcfgN
199+
(0x3A @ idx : bits(4), _) if idx[0] == bitzero | sizeof(xlen) == 32 => {
200+
let idx = unsigned(idx);
201+
pmpWriteCfgReg(idx, value); Some(pmpReadCfgReg(idx))
202+
},
217203

218-
(0x3B0, _) => { pmpaddr0 = pmpWriteAddr(pmpLocked(pmp0cfg), pmpTORLocked(pmp1cfg), pmpaddr0, value); Some(pmpaddr0) },
219-
(0x3B1, _) => { pmpaddr1 = pmpWriteAddr(pmpLocked(pmp1cfg), pmpTORLocked(pmp2cfg), pmpaddr1, value); Some(pmpaddr1) },
220-
(0x3B2, _) => { pmpaddr2 = pmpWriteAddr(pmpLocked(pmp2cfg), pmpTORLocked(pmp3cfg), pmpaddr2, value); Some(pmpaddr2) },
221-
(0x3B3, _) => { pmpaddr3 = pmpWriteAddr(pmpLocked(pmp3cfg), pmpTORLocked(pmp4cfg), pmpaddr3, value); Some(pmpaddr3) },
222-
(0x3B4, _) => { pmpaddr4 = pmpWriteAddr(pmpLocked(pmp4cfg), pmpTORLocked(pmp5cfg), pmpaddr4, value); Some(pmpaddr4) },
223-
(0x3B5, _) => { pmpaddr5 = pmpWriteAddr(pmpLocked(pmp5cfg), pmpTORLocked(pmp6cfg), pmpaddr5, value); Some(pmpaddr5) },
224-
(0x3B6, _) => { pmpaddr6 = pmpWriteAddr(pmpLocked(pmp6cfg), pmpTORLocked(pmp7cfg), pmpaddr6, value); Some(pmpaddr6) },
225-
(0x3B7, _) => { pmpaddr7 = pmpWriteAddr(pmpLocked(pmp7cfg), pmpTORLocked(pmp8cfg), pmpaddr7, value); Some(pmpaddr7) },
226-
(0x3B8, _) => { pmpaddr8 = pmpWriteAddr(pmpLocked(pmp8cfg), pmpTORLocked(pmp9cfg), pmpaddr8, value); Some(pmpaddr8) },
227-
(0x3B9, _) => { pmpaddr9 = pmpWriteAddr(pmpLocked(pmp9cfg), pmpTORLocked(pmp10cfg), pmpaddr9, value); Some(pmpaddr9) },
228-
(0x3BA, _) => { pmpaddr10 = pmpWriteAddr(pmpLocked(pmp10cfg), pmpTORLocked(pmp11cfg), pmpaddr10, value); Some(pmpaddr10) },
229-
(0x3BB, _) => { pmpaddr11 = pmpWriteAddr(pmpLocked(pmp11cfg), pmpTORLocked(pmp12cfg), pmpaddr11, value); Some(pmpaddr11) },
230-
(0x3BC, _) => { pmpaddr12 = pmpWriteAddr(pmpLocked(pmp12cfg), pmpTORLocked(pmp13cfg), pmpaddr12, value); Some(pmpaddr12) },
231-
(0x3BD, _) => { pmpaddr13 = pmpWriteAddr(pmpLocked(pmp13cfg), pmpTORLocked(pmp14cfg), pmpaddr13, value); Some(pmpaddr13) },
232-
(0x3BE, _) => { pmpaddr14 = pmpWriteAddr(pmpLocked(pmp14cfg), pmpTORLocked(pmp15cfg), pmpaddr14, value); Some(pmpaddr14) },
233-
(0x3BF, _) => { pmpaddr15 = pmpWriteAddr(pmpLocked(pmp15cfg), false, pmpaddr15, value); Some(pmpaddr15) },
204+
// pmpaddrN. Unfortunately the PMP index does not nicely align with the CSR index bits.
205+
(0x3B @ idx : bits(4), _) => { let idx = unsigned(0b00 @ idx); pmpWriteAddrReg(idx, value); Some(pmpReadAddrReg(idx)) },
206+
(0x3C @ idx : bits(4), _) => { let idx = unsigned(0b01 @ idx); pmpWriteAddrReg(idx, value); Some(pmpReadAddrReg(idx)) },
207+
(0x3D @ idx : bits(4), _) => { let idx = unsigned(0b10 @ idx); pmpWriteAddrReg(idx, value); Some(pmpReadAddrReg(idx)) },
208+
(0x3E @ idx : bits(4), _) => { let idx = unsigned(0b11 @ idx); pmpWriteAddrReg(idx, value); Some(pmpReadAddrReg(idx)) },
234209

235210
/* machine mode counters */
236211
(0xB00, _) => { mcycle[(sizeof(xlen) - 1) .. 0] = value; Some(value) },

model/riscv_mem.sail

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ function checked_mem_read forall 'n, 0 < 'n <= max_mem_access . (t : AccessType(
144144

145145
/* PMP checks if enabled */
146146
function pmp_mem_read forall 'n, 0 < 'n <= max_mem_access . (t : AccessType(ext_access_type), p : Privilege, paddr : xlenbits, width : atom('n), aq : bool, rl : bool, res: bool, meta : bool) -> MemoryOpResult((bits(8 * 'n), mem_meta)) =
147-
if not(plat_enable_pmp())
147+
if sys_pmp_count() == 0
148148
then checked_mem_read(t, paddr, width, aq, rl, res, meta)
149149
else {
150150
match pmpCheck(paddr, width, t, p) {
@@ -272,7 +272,7 @@ function checked_mem_write forall 'n, 0 < 'n <= max_mem_access . (wk : write_kin
272272

273273
/* PMP checks if enabled */
274274
function pmp_mem_write forall 'n, 0 < 'n <= max_mem_access . (wk: write_kind, paddr : xlenbits, width : atom('n), data: bits(8 * 'n), typ: AccessType(ext_access_type), priv: Privilege, meta: mem_meta) -> MemoryOpResult(bool) =
275-
if not(plat_enable_pmp())
275+
if sys_pmp_count() == 0
276276
then checked_mem_write(wk, paddr, width, data, meta)
277277
else {
278278
match pmpCheck(paddr, width, typ, priv) {

0 commit comments

Comments
 (0)