Hazard3/test/sim/rvcpp/include/rv_csr.h

142 lines
2.6 KiB
C++

#pragma once
#include <optional>
#include "rv_types.h"
class RVCSR {
static const int PMP_REGIONS = 16;
static const int IMPLEMENTED_PMP_REGIONS = 4;
// Latched IRQ signals into core
bool irq_t;
bool irq_s;
bool irq_e;
// Current core privilege level (M/S/U)
uint priv;
ux_t mcycle;
ux_t mcycleh;
ux_t minstret;
ux_t minstreth;
ux_t mcountinhibit;
ux_t mstatus;
ux_t mie;
ux_t mip;
ux_t mtvec;
ux_t mscratch;
ux_t mepc;
ux_t mcause;
ux_t hazard3_msleep;
ux_t pmpaddr[PMP_REGIONS];
ux_t pmpcfg[PMP_REGIONS / 4];
std::optional<ux_t> pending_write_addr;
ux_t pending_write_data;
ux_t get_effective_xip();
// Internal interface for updating trap state. Returns trap target pc.
ux_t trap_enter(uint xcause, ux_t xepc);
ux_t pmpcfg_a(int i) {
uint8_t cfg_bits = pmpcfg[i / 4] >> 8 * (i % 4);
return (cfg_bits >> 3) & 0x3u;
}
ux_t pmpcfg_xwr(int i) {
uint8_t cfg_bits = pmpcfg[i / 4] >> 8 * (i % 4);
return cfg_bits & 0x7u;
}
ux_t pmpcfg_l(int i) {
uint8_t cfg_bits = pmpcfg[i / 4] >> 8 * (i % 4);
return (cfg_bits >> 7) & 0x1u;
}
public:
enum {
WRITE = 0,
WRITE_SET = 1,
WRITE_CLEAR = 2
};
RVCSR() {
irq_t = false;
irq_s = false;
irq_e = false;
priv = 3;
mcycle = 0;
mcycleh = 0;
minstret = 0;
minstreth = 0;
mcountinhibit = 0x5;
mstatus = 0;
mie = 0;
mip = 0;
mtvec = 0;
mscratch = 0;
mepc = 0;
mcause = 0;
hazard3_msleep = 0;
pending_write_addr = {};
for (int i = 0; i < PMP_REGIONS; ++i) {
pmpaddr[i] = 0;
}
for (int i = 0; i < PMP_REGIONS / 4; ++i) {
pmpcfg[i] = 0;
}
}
void step();
// Returns None on permission/decode fail
std::optional<ux_t> read(uint16_t addr, bool side_effect=true);
// Returns false on permission/decode fail
bool write(uint16_t addr, ux_t data, uint op=WRITE);
// Determine target privilege level of an exception, update trap state
// (including change of privilege level), return trap target PC
ux_t trap_enter_exception(uint xcause, ux_t xepc);
// If there is currently a pending IRQ that must be entered, then
// determine its target privilege level, update trap state, and return
// trap target PC. Otherwise return None.
std::optional<ux_t> trap_check_enter_irq(ux_t xepc);
// Update trap state, return mepc:
ux_t trap_mret();
uint get_true_priv() {
return priv;
}
bool get_mstatus_tw() {
return mstatus & 0x00200000u;
}
void set_irq_t(bool irq) {
irq_t = irq;
}
void set_irq_s(bool irq) {
irq_s = irq;
}
void set_irq_e(bool irq) {
irq_e = irq;
}
ux_t get_xcause() {
return mcause;
}
// Return region, or -1 for no match
int get_pmp_match(ux_t addr);
uint get_pmp_xwr(ux_t addr);
};