rvcpp: fix up PMP address mask for all-ones pmpaddr, and raise instruction fault on instruction stradding two PMP regions, like the hardware
This commit is contained in:
parent
7d370292b0
commit
ebe5a44454
|
@ -127,5 +127,8 @@ public:
|
||||||
return mcause;
|
return mcause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return region, or -1 for no match
|
||||||
|
int get_pmp_match(ux_t addr);
|
||||||
|
|
||||||
uint get_pmp_xwr(ux_t addr);
|
uint get_pmp_xwr(ux_t addr);
|
||||||
};
|
};
|
||||||
|
|
|
@ -143,10 +143,15 @@ void RVCore::step(bool trace) {
|
||||||
uint funct3 = instr >> 12 & 0x7;
|
uint funct3 = instr >> 12 & 0x7;
|
||||||
uint funct7 = instr >> 25 & 0x7f;
|
uint funct7 = instr >> 25 & 0x7f;
|
||||||
|
|
||||||
|
bool pmp_straddle = false;
|
||||||
|
if (fetch0 && (*fetch0 & 0x3) == 0x3) {
|
||||||
|
pmp_straddle = csr.get_pmp_match(pc) != csr.get_pmp_match(pc + 2);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ux_t> irq_target_pc = csr.trap_check_enter_irq(pc);
|
std::optional<ux_t> irq_target_pc = csr.trap_check_enter_irq(pc);
|
||||||
if (irq_target_pc) {
|
if (irq_target_pc) {
|
||||||
// Replace current instruction with IRQ entry
|
// Replace current instruction with IRQ entry
|
||||||
} else if (!fetch0 || ((*fetch0 & 0x3) == 0x3 && !fetch1)) {
|
} else if (!fetch0 || ((*fetch0 & 0x3) == 0x3 && (!fetch1 || pmp_straddle))) {
|
||||||
exception_cause = XCAUSE_INSTR_FAULT;
|
exception_cause = XCAUSE_INSTR_FAULT;
|
||||||
} else if ((instr & 0x3) == 0x3) {
|
} else if ((instr & 0x3) == 0x3) {
|
||||||
// 32-bit instruction
|
// 32-bit instruction
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "encoding/rv_csr.h"
|
#include "encoding/rv_csr.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
// Inclusive msb:lsb style, like Verilog (and like the ISA manual)
|
// Inclusive msb:lsb style, like Verilog (and like the ISA manual)
|
||||||
#define BITS_UPTO(msb) (~((-1u << (msb)) << 1))
|
#define BITS_UPTO(msb) (~((-1u << (msb)) << 1))
|
||||||
|
@ -251,26 +252,37 @@ ux_t RVCSR::trap_mret() {
|
||||||
return mepc;
|
return mepc;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint RVCSR::get_pmp_xwr(ux_t addr) {
|
int RVCSR::get_pmp_match(ux_t addr) {
|
||||||
bool match = false;
|
|
||||||
uint matching_xwr = 0;
|
|
||||||
uint matching_l = 0;
|
|
||||||
bool trace_pmp = get_true_priv() == PRV_U && true;
|
|
||||||
for (int i = 0; i < PMP_REGIONS; ++i) {
|
for (int i = 0; i < PMP_REGIONS; ++i) {
|
||||||
if (pmpcfg_a(i) == 0u) {
|
if (pmpcfg_a(i) == 0u) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint32_t mask = 0xffffffffu;
|
ux_t mask = 0xffffffffu;
|
||||||
if (pmpcfg_a(i) == 2) {
|
if (pmpcfg_a(i) == 3) {
|
||||||
|
if (pmpaddr[i] == 0xffffffffu) {
|
||||||
|
mask = 0u;
|
||||||
|
} else {
|
||||||
mask = 0xfffffffeu << __builtin_ctz(~pmpaddr[i]);
|
mask = 0xfffffffeu << __builtin_ctz(~pmpaddr[i]);
|
||||||
}
|
}
|
||||||
match = ((addr >> 2) & mask) == (pmpaddr[i] & mask);
|
|
||||||
if (match) {
|
|
||||||
matching_xwr = pmpcfg_xwr(i);
|
|
||||||
matching_l = pmpcfg_l(i);
|
|
||||||
// Lowest-numbered match determines success/failure:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
bool match = ((addr >> 2) & mask) == (pmpaddr[i] & mask);
|
||||||
|
if (match) {
|
||||||
|
// Lowest-numbered match determines success/failure:
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint RVCSR::get_pmp_xwr(ux_t addr) {
|
||||||
|
int region = get_pmp_match(addr);
|
||||||
|
bool match = false;
|
||||||
|
uint matching_xwr = 0;
|
||||||
|
uint matching_l = 0;
|
||||||
|
if (region >= 0) {
|
||||||
|
match = true;
|
||||||
|
matching_xwr = pmpcfg_xwr(region);
|
||||||
|
matching_l = pmpcfg_l(region);
|
||||||
}
|
}
|
||||||
if (match) {
|
if (match) {
|
||||||
// TODO MPRV
|
// TODO MPRV
|
||||||
|
|
Loading…
Reference in New Issue