|
|
|
@ -146,7 +146,7 @@ public:
|
|
|
|
|
|
|
|
|
|
mstatus_t mstatus;
|
|
|
|
|
|
|
|
|
|
static const reg_t mstatus_reset_val = 0;
|
|
|
|
|
static const reg_t mstatus_reset_val = 0x1800; // MPP set to 1
|
|
|
|
|
|
|
|
|
|
void write_mstatus(T val, unsigned priv_lvl) {
|
|
|
|
|
auto mask = get_mask(priv_lvl);
|
|
|
|
@ -543,25 +543,27 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
|
|
|
|
|
constexpr auto PMP_NA4 =0x2U;
|
|
|
|
|
constexpr auto PMP_NAPOT =0x3U;
|
|
|
|
|
reg_t base = 0;
|
|
|
|
|
auto any_active = false;
|
|
|
|
|
for (size_t i = 0; i < 16; i++) {
|
|
|
|
|
reg_t tor = csr[pmpaddr0+i] << PMP_SHIFT;
|
|
|
|
|
uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4);
|
|
|
|
|
if (cfg & PMP_A) {
|
|
|
|
|
any_active=true;
|
|
|
|
|
auto pmp_a = (cfg & PMP_A) >> 3;
|
|
|
|
|
bool is_tor = pmp_a == PMP_TOR;
|
|
|
|
|
bool is_na4 = pmp_a == PMP_NA4;
|
|
|
|
|
auto is_tor = pmp_a == PMP_TOR;
|
|
|
|
|
auto is_na4 = pmp_a == PMP_NA4;
|
|
|
|
|
|
|
|
|
|
reg_t mask = (csr[pmpaddr0+i] << 1) | (!is_na4);
|
|
|
|
|
mask = ~(mask & ~(mask + 1)) << PMP_SHIFT;
|
|
|
|
|
|
|
|
|
|
// Check each 4-byte sector of the access
|
|
|
|
|
bool any_match = false;
|
|
|
|
|
bool all_match = true;
|
|
|
|
|
auto any_match = false;
|
|
|
|
|
auto all_match = true;
|
|
|
|
|
for (reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) {
|
|
|
|
|
reg_t cur_addr = addr + offset;
|
|
|
|
|
bool napot_match = ((cur_addr ^ tor) & mask) == 0;
|
|
|
|
|
bool tor_match = base <= cur_addr && cur_addr < tor;
|
|
|
|
|
bool match = is_tor ? tor_match : napot_match;
|
|
|
|
|
auto napot_match = ((cur_addr ^ tor) & mask) == 0;
|
|
|
|
|
auto tor_match = base <= cur_addr && cur_addr < tor;
|
|
|
|
|
auto match = is_tor ? tor_match : napot_match;
|
|
|
|
|
any_match |= match;
|
|
|
|
|
all_match &= match;
|
|
|
|
|
}
|
|
|
|
@ -577,7 +579,7 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
|
|
|
|
|
}
|
|
|
|
|
base = tor;
|
|
|
|
|
}
|
|
|
|
|
return this->reg.PRIV == PRIV_M;
|
|
|
|
|
return !any_active || this->reg.PRIV == PRIV_M;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -926,8 +928,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
|
|
|
|
|
|
|
|
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
|
|
|
|
|
auto mask = get_irq_wrmask((addr >> 8) & 0x3);
|
|
|
|
|
if(this->reg.PRIV==0)
|
|
|
|
|
mask&= ~(0xff<<4); // STIE and UTIE are read only in user and supervisor mode
|
|
|
|
|
csr[mie] = (csr[mie] & ~mask) | (val & mask);
|
|
|
|
|
check_interrupt();
|
|
|
|
|
return iss::Ok;
|
|
|
|
@ -1256,27 +1256,33 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
|
|
|
|
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) {
|
|
|
|
|
auto cur_priv = this->reg.PRIV;
|
|
|
|
|
auto inst_priv = (flags & 0x3)? 3:0;
|
|
|
|
|
auto status = state.mstatus;
|
|
|
|
|
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
|
|
|
|
// clear respective yIE
|
|
|
|
|
switch (inst_priv) {
|
|
|
|
|
case PRIV_M:
|
|
|
|
|
this->reg.PRIV = state.mstatus.MPP;
|
|
|
|
|
state.mstatus.MPP = 0; // clear mpp to U mode
|
|
|
|
|
state.mstatus.MIE = state.mstatus.MPIE;
|
|
|
|
|
state.mstatus.MPIE = 1;
|
|
|
|
|
break;
|
|
|
|
|
case PRIV_U:
|
|
|
|
|
this->reg.PRIV = 0;
|
|
|
|
|
state.mstatus.UIE = state.mstatus.UPIE;
|
|
|
|
|
state.mstatus.UPIE = 1;
|
|
|
|
|
break;
|
|
|
|
|
if(inst_priv>cur_priv){
|
|
|
|
|
auto trap_val = 0x80ULL << 24 | (2 << 16); // illegal instruction
|
|
|
|
|
this->reg.trap_state = trap_val;
|
|
|
|
|
this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max();
|
|
|
|
|
} else {
|
|
|
|
|
auto status = state.mstatus;
|
|
|
|
|
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
|
|
|
|
// clear respective yIE
|
|
|
|
|
switch (inst_priv) {
|
|
|
|
|
case PRIV_M:
|
|
|
|
|
this->reg.PRIV = state.mstatus.MPP;
|
|
|
|
|
state.mstatus.MPP = 0; // clear mpp to U mode
|
|
|
|
|
state.mstatus.MIE = state.mstatus.MPIE;
|
|
|
|
|
state.mstatus.MPIE = 1;
|
|
|
|
|
break;
|
|
|
|
|
case PRIV_U:
|
|
|
|
|
this->reg.PRIV = 0;
|
|
|
|
|
state.mstatus.UIE = state.mstatus.UPIE;
|
|
|
|
|
state.mstatus.UPIE = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// sets the pc to the value stored in the x epc register.
|
|
|
|
|
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
|
|
|
|
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to "
|
|
|
|
|
<< lvl[this->reg.PRIV];
|
|
|
|
|
check_interrupt();
|
|
|
|
|
}
|
|
|
|
|
// sets the pc to the value stored in the x epc register.
|
|
|
|
|
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
|
|
|
|
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to "
|
|
|
|
|
<< lvl[this->reg.PRIV];
|
|
|
|
|
check_interrupt();
|
|
|
|
|
return this->reg.NEXT_PC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|