rvcpp: fix busted RMW CSR logic, fix ordering of CSR write vs update, csr_mcycle testcase now passes

This commit is contained in:
Luke Wren 2024-03-20 01:37:04 +00:00
parent 55504fa8f3
commit 8cbf5fceee
2 changed files with 58 additions and 38 deletions

View File

@ -18,6 +18,11 @@
// - M // - M
// - A // - A
// - C (also called Zca) // - C (also called Zca)
// - Zba
// - Zbb
// - Zbc
// - Zbs
// - Zbkb
// - Zcmp // - Zcmp
// - M-mode traps // - M-mode traps
@ -158,7 +163,8 @@ class RVCSR {
ux_t mepc; ux_t mepc;
ux_t mcause; ux_t mcause;
std::optional<ux_t> addr_written_this_step; std::optional<ux_t> pending_write_addr;
ux_t pending_write_data;
public: public:
@ -182,7 +188,7 @@ public:
mscratch = 0; mscratch = 0;
mepc = 0; mepc = 0;
mcause = 0; mcause = 0;
addr_written_this_step = {}; pending_write_addr = {};
} }
void step() { void step() {
@ -194,19 +200,36 @@ public:
if (!(mcountinhibit & 0x4u)) { if (!(mcountinhibit & 0x4u)) {
++minstret_64; ++minstret_64;
} }
if (!(addr_written_this_step && *addr_written_this_step == CSR_MCYCLEH)) { if (!(pending_write_addr && *pending_write_addr == CSR_MCYCLEH)) {
mcycleh = mcycle_64 >> 32; mcycleh = mcycle_64 >> 32;
} }
if (!(addr_written_this_step && *addr_written_this_step == CSR_MCYCLE)) { if (!(pending_write_addr && *pending_write_addr == CSR_MCYCLE)) {
mcycle = mcycle_64 & 0xffffffffu; mcycle = mcycle_64 & 0xffffffffu;
} }
if (!(addr_written_this_step && *addr_written_this_step == CSR_MINSTRETH)) { if (!(pending_write_addr && *pending_write_addr == CSR_MINSTRETH)) {
minstreth = minstret_64 >> 32; minstreth = minstret_64 >> 32;
} }
if (!(addr_written_this_step && *addr_written_this_step == CSR_MINSTRET)) { if (!(pending_write_addr && *pending_write_addr == CSR_MINSTRET)) {
minstret = minstret_64 & 0xffffffffu; minstret = minstret_64 & 0xffffffffu;
} }
addr_written_this_step = {}; if (pending_write_addr) {
switch (*pending_write_addr) {
case CSR_MSTATUS: mstatus = pending_write_data; break;
case CSR_MIE: mie = pending_write_data; break;
case CSR_MTVEC: mtvec = pending_write_data & 0xfffffffdu; break;
case CSR_MSCRATCH: mscratch = pending_write_data; break;
case CSR_MEPC: mepc = pending_write_data & 0xfffffffeu; break;
case CSR_MCAUSE: mcause = pending_write_data & 0x8000000fu; break;
case CSR_MCYCLE: mcycle = pending_write_data; break;
case CSR_MCYCLEH: mcycleh = pending_write_data; break;
case CSR_MINSTRET: minstret = pending_write_data; break;
case CSR_MINSTRETH: minstreth = pending_write_data; break;
case CSR_MCOUNTINHIBIT: mcountinhibit = pending_write_data & 0x7u; break;
default: break;
}
pending_write_addr = {};
}
} }
// Returns None on permission/decode fail // Returns None on permission/decode fail
@ -243,41 +266,43 @@ public:
// Returns false on permission/decode fail // Returns false on permission/decode fail
bool write(uint16_t addr, ux_t data, uint op=WRITE) { bool write(uint16_t addr, ux_t data, uint op=WRITE) {
addr_written_this_step = addr;
if (addr >= 1u << 12 || GETBITS(addr, 9, 8) > priv) if (addr >= 1u << 12 || GETBITS(addr, 9, 8) > priv)
return false; return false;
if (addr >= 1u << 12)
if (op == WRITE_CLEAR || op == WRITE_SET) { if (op == WRITE_CLEAR || op == WRITE_SET) {
std::optional<ux_t> rdata = read(addr, false); std::optional<ux_t> rdata = read(addr, false);
if (!rdata) if (!rdata)
return false; return false;
if (op == WRITE_CLEAR) if (op == WRITE_CLEAR)
data &= ~*rdata; data = *rdata & ~data;
else else
data |= *rdata; data = *rdata | data;
} }
pending_write_addr = addr;
pending_write_data = data;
// Actual write is applied at end of step() -- ordering is important
// e.g. for mcycle updates. However we validate address for
// writability immediately.
switch (addr) { switch (addr) {
case CSR_MISA: break; case CSR_MISA: break;
case CSR_MHARTID: break; case CSR_MHARTID: break;
case CSR_MARCHID: break; case CSR_MARCHID: break;
case CSR_MIMPID: break; case CSR_MIMPID: break;
case CSR_MSTATUS: mstatus = data; break; case CSR_MSTATUS: break;
case CSR_MIE: mie = data; break; case CSR_MIE: break;
case CSR_MIP: break; case CSR_MIP: break;
case CSR_MTVEC: mtvec = data & 0xfffffffdu; break; case CSR_MTVEC: break;
case CSR_MSCRATCH: mscratch = data; break; case CSR_MSCRATCH: break;
case CSR_MEPC: mepc = data & 0xfffffffeu; break; case CSR_MEPC: break;
case CSR_MCAUSE: mcause = data & 0x8000000fu; break; case CSR_MCAUSE: break;
case CSR_MTVAL: break; case CSR_MTVAL: break;
case CSR_MCYCLE: mcycle = data; break; case CSR_MCYCLE: break;
case CSR_MCYCLEH: mcycleh = data; break; case CSR_MCYCLEH: break;
case CSR_MINSTRET: minstret = data; break; case CSR_MINSTRET: break;
case CSR_MINSTRETH: minstreth = data; break; case CSR_MINSTRETH: break;
case CSR_MCOUNTINHIBIT: mcountinhibit = data & 0x7u; break; case CSR_MCOUNTINHIBIT: break;
default: return false; default: return false;
} }
return true; return true;
} }

View File

@ -45,14 +45,9 @@ int main() {
asm volatile ( asm volatile (
".p2align 2\n" ".p2align 2\n"
" csrw mcycle, zero\n" " csrw mcycle, zero\n"
" j 1f\n" // 2 cycles each ".rept 8\n"
"1:\n" " nop\n"
" j 1f\n" ".endr\n"
"1:\n"
" j 1f\n"
"1:\n"
" j 1f\n"
"1:\n"
" csrr %0, mcycle\n" " csrr %0, mcycle\n"
: "=r" (tmp0) : "=r" (tmp0)
); );