diff --git a/test/sim/rvcpp/include/rv_csr.h b/test/sim/rvcpp/include/rv_csr.h index c857d42..5e37820 100644 --- a/test/sim/rvcpp/include/rv_csr.h +++ b/test/sim/rvcpp/include/rv_csr.h @@ -127,5 +127,8 @@ public: return mcause; } + // Return region, or -1 for no match + int get_pmp_match(ux_t addr); + uint get_pmp_xwr(ux_t addr); }; diff --git a/test/sim/rvcpp/rv_core.cpp b/test/sim/rvcpp/rv_core.cpp index 804abc0..bf89403 100644 --- a/test/sim/rvcpp/rv_core.cpp +++ b/test/sim/rvcpp/rv_core.cpp @@ -143,10 +143,15 @@ void RVCore::step(bool trace) { uint funct3 = instr >> 12 & 0x7; 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); if (irq_target_pc) { // 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; } else if ((instr & 0x3) == 0x3) { // 32-bit instruction diff --git a/test/sim/rvcpp/rv_csr.cpp b/test/sim/rvcpp/rv_csr.cpp index 926589b..5ad8d74 100644 --- a/test/sim/rvcpp/rv_csr.cpp +++ b/test/sim/rvcpp/rv_csr.cpp @@ -2,6 +2,7 @@ #include "encoding/rv_csr.h" #include <cassert> +#include <cstdio> // Inclusive msb:lsb style, like Verilog (and like the ISA manual) #define BITS_UPTO(msb) (~((-1u << (msb)) << 1)) @@ -251,27 +252,38 @@ ux_t RVCSR::trap_mret() { return mepc; } -uint RVCSR::get_pmp_xwr(ux_t addr) { - bool match = false; - uint matching_xwr = 0; - uint matching_l = 0; - bool trace_pmp = get_true_priv() == PRV_U && true; +int RVCSR::get_pmp_match(ux_t addr) { for (int i = 0; i < PMP_REGIONS; ++i) { if (pmpcfg_a(i) == 0u) { continue; } - uint32_t mask = 0xffffffffu; - if (pmpcfg_a(i) == 2) { - mask = 0xfffffffeu << __builtin_ctz(~pmpaddr[i]); + ux_t mask = 0xffffffffu; + if (pmpcfg_a(i) == 3) { + if (pmpaddr[i] == 0xffffffffu) { + mask = 0u; + } else { + mask = 0xfffffffeu << __builtin_ctz(~pmpaddr[i]); + } } - match = ((addr >> 2) & mask) == (pmpaddr[i] & mask); + bool 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; + 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) { // TODO MPRV if (get_true_priv() == PRV_M && !matching_l) {