Add simple test to read, write and lock PMP registers
This commit is contained in:
parent
456810b09e
commit
7340765699
|
@ -0,0 +1,157 @@
|
|||
#ifndef _PMP_H
|
||||
#define _PMP_H
|
||||
|
||||
#include "hazard3_csr.h"
|
||||
|
||||
#define PMPCFG_L_LSB 7
|
||||
#define PMPCFG_L_BITS 0x80
|
||||
#define PMPCFG_A_LSB 3
|
||||
#define PMPCFG_A_BITS 0x18
|
||||
#define PMPCFG_R_BITS 0x04
|
||||
#define PMPCFG_W_BITS 0x02
|
||||
#define PMPCFG_X_BITS 0x01
|
||||
|
||||
#define PMPCFG_A_OFF 0x0
|
||||
#define PMPCFG_A_TOR 0x1
|
||||
#define PMPCFG_A_NA4 0x2
|
||||
#define PMPCFG_A_NAPOT 0x3
|
||||
|
||||
// Note these aren't declared as inline -- presumably ok as our tests are single C files
|
||||
|
||||
void write_pmpaddr(unsigned int region, uintptr_t addr) {
|
||||
switch (region) {
|
||||
case 0:
|
||||
write_csr(pmpaddr0, addr);
|
||||
break;
|
||||
case 1:
|
||||
write_csr(pmpaddr1, addr);
|
||||
break;
|
||||
case 2:
|
||||
write_csr(pmpaddr2, addr);
|
||||
break;
|
||||
case 3:
|
||||
write_csr(pmpaddr3, addr);
|
||||
break;
|
||||
case 4:
|
||||
write_csr(pmpaddr4, addr);
|
||||
break;
|
||||
case 5:
|
||||
write_csr(pmpaddr5, addr);
|
||||
break;
|
||||
case 6:
|
||||
write_csr(pmpaddr6, addr);
|
||||
break;
|
||||
case 7:
|
||||
write_csr(pmpaddr7, addr);
|
||||
break;
|
||||
case 8:
|
||||
write_csr(pmpaddr8, addr);
|
||||
break;
|
||||
case 9:
|
||||
write_csr(pmpaddr9, addr);
|
||||
break;
|
||||
case 10:
|
||||
write_csr(pmpaddr10, addr);
|
||||
break;
|
||||
case 11:
|
||||
write_csr(pmpaddr11, addr);
|
||||
break;
|
||||
case 12:
|
||||
write_csr(pmpaddr12, addr);
|
||||
break;
|
||||
case 13:
|
||||
write_csr(pmpaddr13, addr);
|
||||
break;
|
||||
case 14:
|
||||
write_csr(pmpaddr14, addr);
|
||||
break;
|
||||
case 15:
|
||||
write_csr(pmpaddr15, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t read_pmpaddr(unsigned int region) {
|
||||
switch (region) {
|
||||
case 0:
|
||||
return read_csr(pmpaddr0);
|
||||
case 1:
|
||||
return read_csr(pmpaddr1);
|
||||
case 2:
|
||||
return read_csr(pmpaddr2);
|
||||
case 3:
|
||||
return read_csr(pmpaddr3);
|
||||
case 4:
|
||||
return read_csr(pmpaddr4);
|
||||
case 5:
|
||||
return read_csr(pmpaddr5);
|
||||
case 6:
|
||||
return read_csr(pmpaddr6);
|
||||
case 7:
|
||||
return read_csr(pmpaddr7);
|
||||
case 8:
|
||||
return read_csr(pmpaddr8);
|
||||
case 9:
|
||||
return read_csr(pmpaddr9);
|
||||
case 10:
|
||||
return read_csr(pmpaddr10);
|
||||
case 11:
|
||||
return read_csr(pmpaddr11);
|
||||
case 12:
|
||||
return read_csr(pmpaddr12);
|
||||
case 13:
|
||||
return read_csr(pmpaddr13);
|
||||
case 14:
|
||||
return read_csr(pmpaddr14);
|
||||
case 15:
|
||||
return read_csr(pmpaddr15);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void write_pmpcfg(unsigned int region, uint8_t cfg) {
|
||||
int regnum = region / 4;
|
||||
int lsb = (region % 4) * 8;
|
||||
uint32_t set_mask = (uint32_t)cfg << lsb;
|
||||
uint32_t clr_mask = ~(uint32_t)cfg & 0xffu << lsb;
|
||||
switch (regnum) {
|
||||
case 0:
|
||||
clear_csr(pmpcfg0, clr_mask);
|
||||
set_csr(pmpcfg0, set_mask);
|
||||
break;
|
||||
case 1:
|
||||
clear_csr(pmpcfg1, clr_mask);
|
||||
set_csr(pmpcfg1, set_mask);
|
||||
break;
|
||||
case 2:
|
||||
clear_csr(pmpcfg2, clr_mask);
|
||||
set_csr(pmpcfg2, set_mask);
|
||||
break;
|
||||
case 3:
|
||||
clear_csr(pmpcfg3, clr_mask);
|
||||
set_csr(pmpcfg3, set_mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t read_pmpcfg(unsigned int region) {
|
||||
uint32_t cfgreg = 0;
|
||||
switch (region / 4) {
|
||||
case 0:
|
||||
cfgreg = read_csr(pmpcfg0);
|
||||
break;
|
||||
case 1:
|
||||
cfgreg = read_csr(pmpcfg1);
|
||||
break;
|
||||
case 2:
|
||||
cfgreg = read_csr(pmpcfg2);
|
||||
break;
|
||||
case 3:
|
||||
cfgreg = read_csr(pmpcfg3);
|
||||
break;
|
||||
}
|
||||
return (cfgreg >> (region % 4 * 8)) & 0xffu;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,52 @@
|
|||
#include "tb_cxxrtl_io.h"
|
||||
#include "hazard3_csr.h"
|
||||
#include "pmp.h"
|
||||
|
||||
// Check PMP registers can be written and read back. Check that lock bit
|
||||
// prevents further writes.
|
||||
|
||||
/*EXPECTED-OUTPUT***************************************************************
|
||||
*******************************************************************************/
|
||||
|
||||
// Number of implemented regions configured in the testbench
|
||||
#define PMP_REGIONS 4
|
||||
// Number of registers including WARL-0
|
||||
#define PMP_REGIONS_MAX 16
|
||||
|
||||
int main() {
|
||||
tb_puts("Reset value check\n");
|
||||
for (int i = 0; i < PMP_REGIONS_MAX; ++i)
|
||||
tb_printf("%02d: cfg = %02x, addr = %08x\n", i, read_pmpcfg(i), read_pmpaddr(i));
|
||||
|
||||
tb_puts("Write all ones (except lock bit)\n");
|
||||
for (int i = 0; i < PMP_REGIONS_MAX; ++i) {
|
||||
write_pmpcfg(i, 0x1fu);
|
||||
write_pmpaddr(i, -1u);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PMP_REGIONS_MAX; ++i)
|
||||
tb_printf("%02d: cfg = %02x, addr = %08x\n", i, read_pmpcfg(i), read_pmpaddr(i));
|
||||
|
||||
tb_puts("Write unique values\n");
|
||||
for (unsigned int i = 0; i < PMP_REGIONS; ++i) {
|
||||
write_pmpcfg(i, i);
|
||||
write_pmpaddr(i, (i + 1) * 0x11111111u);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PMP_REGIONS; ++i)
|
||||
tb_printf("%02d: cfg = %02x, addr = %08x\n", i, read_pmpcfg(i), read_pmpaddr(i));
|
||||
|
||||
tb_puts("Set lock bits\n");
|
||||
for (int i = 0; i < PMP_REGIONS; ++i)
|
||||
write_pmpcfg(i, PMPCFG_L_BITS);
|
||||
tb_puts("Try to set all-ones again\n");
|
||||
for (int i = 0; i < PMP_REGIONS_MAX; ++i) {
|
||||
write_pmpcfg(i, 0x1fu);
|
||||
write_pmpaddr(i, -1u);
|
||||
}
|
||||
|
||||
for (int i = 0; i < PMP_REGIONS; ++i)
|
||||
tb_printf("%02d: cfg = %02x, addr = %08x\n", i, read_pmpcfg(i), read_pmpaddr(i));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue