fix privilege behavior

This commit is contained in:
Eyck Jentzsch 2021-07-07 11:30:00 +02:00
parent 2f4b5bd9b2
commit 473f8a5a17
3 changed files with 322 additions and 86 deletions

View File

@ -176,6 +176,10 @@ public:
return 0b100010001000; // only machine mode is supported return 0b100010001000; // only machine mode is supported
} }
constexpr reg_t get_pc_mask() {
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
}
riscv_hart_m_p(); riscv_hart_m_p();
virtual ~riscv_hart_m_p() = default; virtual ~riscv_hart_m_p() = default;
@ -285,6 +289,7 @@ private:
iss::status read_ip(unsigned addr, reg_t &val); iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val); iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val); iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_mepc(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0}; reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb; std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
@ -317,13 +322,12 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_reg;
} }
for (unsigned addr = cycle; addr <= hpmcounter31; ++addr){ for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
} }
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){ for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; //csr_wr_cb[addr] = &this_class::write_reg;
} }
// common regs // common regs
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}}; const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
@ -333,9 +337,12 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
} }
// special handling & overrides // special handling & overrides
csr_rd_cb[time] = &this_class::read_time; csr_rd_cb[time] = &this_class::read_time;
csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time; csr_rd_cb[timeh] = &this_class::read_time;
csr_wr_cb[timeh] = nullptr; csr_rd_cb[cycle] = &this_class::read_cycle;
csr_rd_cb[cycleh] = &this_class::read_cycle;
csr_rd_cb[instret] = &this_class::read_instret;
csr_rd_cb[instreth] = &this_class::read_instret;
csr_rd_cb[mcycle] = &this_class::read_cycle; csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle; csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle; csr_rd_cb[mcycleh] = &this_class::read_cycle;
@ -354,6 +361,7 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
csr_rd_cb[mcounteren] = &this_class::read_null; csr_rd_cb[mcounteren] = &this_class::read_null;
csr_wr_cb[mcounteren] = &this_class::write_null; csr_wr_cb[mcounteren] = &this_class::write_null;
csr_rd_cb[mtvec] = &this_class::read_mtvec; csr_rd_cb[mtvec] = &this_class::read_mtvec;
csr_wr_cb[mepc] = &this_class::write_mepc;
csr_wr_cb[misa] = &this_class::write_null; csr_wr_cb[misa] = &this_class::write_null;
csr_wr_cb[mvendorid] = &this_class::write_null; csr_wr_cb[mvendorid] = &this_class::write_null;
csr_wr_cb[marchid] = &this_class::write_null; csr_wr_cb[marchid] = &this_class::write_null;
@ -656,9 +664,9 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
if (addr == minstret) { if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->reg.instret); val = static_cast<reg_t>(this->reg.instret);
} else if (addr == minstreth) { } else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err; if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32); val = static_cast<reg_t>(this->reg.instret >> 32);
} }
@ -667,11 +675,11 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) { if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == minstreth) if ((addr&0xff) == (minstreth&0xff))
return iss::Err; return iss::Err;
this->reg.instret = static_cast<uint64_t>(val); this->reg.instret = static_cast<uint64_t>(val);
} else { } else {
if (addr == minstret) { if ((addr&0xff) == (minstret&0xff)) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else { } else {
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff); this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
@ -710,7 +718,6 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) {
val = csr[mie]; val = csr[mie];
//val &= csr[mideleg];
return iss::Ok; return iss::Ok;
} }
@ -728,7 +735,6 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned add
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) {
val = csr[mip]; val = csr[mip];
//val &= csr[mideleg];
return iss::Ok; return iss::Ok;
} }
@ -740,6 +746,12 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned add
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_mepc(unsigned addr, reg_t val) {
auto mask = get_pc_mask();
csr[addr] = val;//(csr[addr] & ~mask) | (val & mask);
return iss::Ok;
}
template <typename BASE> template <typename BASE>
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if(mem_read_cb) return mem_read_cb(paddr, length, data); if(mem_read_cb) return mem_read_cb(paddr, length, data);
@ -798,9 +810,10 @@ iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length,
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// tohost handling in case of riscv-test // tohost handling in case of riscv-test
if (paddr.access && iss::access_type::FUNC) { if (paddr.access && iss::access_type::FUNC) {
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)); auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) ||
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
auto tohost_lower = auto tohost_lower =
(traits<BASE>::XLEN == 32 && paddr.val == tohost); (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
if (tohost_lower || tohost_upper) { if (tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)); uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask));
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
@ -831,7 +844,8 @@ iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length,
} }
} else if (tohost_lower) } else if (tohost_lower)
to_host_wr_cnt++; to_host_wr_cnt++;
} else if (traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) { } else if ((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) ||
(traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask)); uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask));
*reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
} }
@ -856,7 +870,7 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
bool mie = state.mstatus.MIE; bool mie = state.mstatus.MIE;
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie); auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
auto enabled_interrupts = m_enabled ? ena_irq /*& ~ideleg*/ : 0; auto enabled_interrupts = m_enabled ? ena_irq : 0;
if (enabled_interrupts != 0) { if (enabled_interrupts != 0) {
int res = 0; int res = 0;
@ -918,7 +932,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flag
state.mstatus.MIE = state.mstatus.MPIE; state.mstatus.MIE = state.mstatus.MPIE;
state.mstatus.MPIE = 1; state.mstatus.MPIE = 1;
// sets the pc to the value stored in the x epc register. // sets the pc to the value stored in the x epc register.
this->reg.NEXT_PC = csr[mepc]; this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
CLOG(INFO, disass) << "Executing xRET"; CLOG(INFO, disass) << "Executing xRET";
check_interrupt(); check_interrupt();
return this->reg.NEXT_PC; return this->reg.NEXT_PC;

View File

@ -356,7 +356,10 @@ protected:
virtual iss::status write_csr(unsigned addr, reg_t val); virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state; hart_state_type state;
uint64_t cycle_offset; int64_t cycle_offset{0};
uint64_t mcycle_csr{0};
int64_t instret_offset{0};
uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
std::array<vm_info, 2> vm; std::array<vm_info, 2> vm;
uint64_t tohost = tohost_dflt; uint64_t tohost = tohost_dflt;
@ -377,10 +380,15 @@ protected:
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb; std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
private: private:
iss::status read_null(unsigned addr, reg_t &val);
iss::status read_reg(unsigned addr, reg_t &val); iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val); iss::status write_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val); iss::status read_cycle(unsigned addr, reg_t &val);
iss::status write_cycle(unsigned addr, reg_t val);
iss::status read_instret(unsigned addr, reg_t &val);
iss::status write_instret(unsigned addr, reg_t val);
iss::status read_mtvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val); iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val); iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val); iss::status write_status(unsigned addr, reg_t val);
@ -389,6 +397,7 @@ private:
iss::status read_ip(unsigned addr, reg_t &val); iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val); iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val); iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_mepc(unsigned addr, reg_t val);
iss::status read_satp(unsigned addr, reg_t &val); iss::status read_satp(unsigned addr, reg_t &val);
iss::status write_satp(unsigned addr, reg_t val); iss::status write_satp(unsigned addr, reg_t val);
iss::status read_fcsr(unsigned addr, reg_t &val); iss::status read_fcsr(unsigned addr, reg_t &val);
@ -405,15 +414,19 @@ protected:
template <typename BASE> template <typename BASE>
riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
: state() : state()
, cycle_offset(0)
, instr_if(*this) { , instr_if(*this) {
csr[misa] = hart_state_type::get_misa(); // reset values
csr[misa] = traits<BASE>::MISA_VAL;
csr[mvendorid] = 0x669;
csr[marchid] = 0x80000003;
csr[mimpid] = 1;
uart_buf.str(""); uart_buf.str("");
for (unsigned addr = mcycle; addr <= mhpmcounter31; ++addr){ for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_reg;
} }
for (unsigned addr = mcycleh; addr <= mhpmcounter31h; ++addr){ for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_reg;
} }
@ -421,23 +434,35 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_reg;
} }
for (unsigned addr = cycle; addr <= hpmcounter31; ++addr){ for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
} }
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){ for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
//csr_wr_cb[addr] = &this_class::write_reg;
}
// common regs
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_reg;
} }
// special handling // special handling & overrides
csr_rd_cb[time] = &this_class::read_time; csr_rd_cb[time] = &this_class::read_time;
csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time; csr_rd_cb[timeh] = &this_class::read_time;
csr_wr_cb[timeh] = nullptr; csr_rd_cb[cycle] = &this_class::read_cycle;
csr_rd_cb[cycleh] = &this_class::read_cycle;
csr_rd_cb[instret] = &this_class::read_instret;
csr_rd_cb[instreth] = &this_class::read_instret;
csr_rd_cb[mcycle] = &this_class::read_cycle; csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle; csr_rd_cb[mcycleh] = &this_class::read_cycle;
csr_rd_cb[minstret] = &this_class::read_cycle; csr_wr_cb[mcycleh] = &this_class::write_cycle;
csr_rd_cb[minstreth] = &this_class::read_cycle; csr_rd_cb[minstret] = &this_class::read_instret;
csr_wr_cb[minstret] = &this_class::write_instret;
csr_rd_cb[minstreth] = &this_class::read_instret;
csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status; csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status; csr_wr_cb[mstatus] = &this_class::write_status;
csr_rd_cb[sstatus] = &this_class::read_status; csr_rd_cb[sstatus] = &this_class::read_status;
@ -457,16 +482,14 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
csr_rd_cb[uie] = &this_class::read_ie; csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie; csr_wr_cb[uie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid; csr_rd_cb[mhartid] = &this_class::read_hartid;
// common regs csr_rd_cb[mcounteren] = &this_class::read_null;
const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}}; csr_wr_cb[mcounteren] = &this_class::write_null;
for(auto addr: addrs) { csr_rd_cb[mtvec] = &this_class::read_mtvec;
csr_rd_cb[addr] = &this_class::read_reg; csr_wr_cb[mepc] = &this_class::write_mepc;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[misa] = &this_class::write_null;
} csr_wr_cb[mvendorid] = &this_class::write_null;
// read-only registers csr_wr_cb[marchid] = &this_class::write_null;
csr_rd_cb[misa] = &this_class::read_reg; csr_wr_cb[mimpid] = &this_class::write_null;
csr_wr_cb[misa] = nullptr;
csr_rd_cb[satp] = &this_class::read_satp; csr_rd_cb[satp] = &this_class::read_satp;
csr_wr_cb[satp] = &this_class::write_satp; csr_wr_cb[satp] = &this_class::write_satp;
csr_rd_cb[fcsr] = &this_class::read_fcsr; csr_rd_cb[fcsr] = &this_class::read_fcsr;
@ -557,10 +580,14 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
auto res = type==iss::address_type::PHYSICAL? auto res = type==iss::address_type::PHYSICAL?
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data): read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault if (unlikely(res != iss::Ok)){
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
} break; } break;
@ -597,6 +624,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
} }
@ -651,11 +679,14 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
auto res = type==iss::address_type::PHYSICAL? auto res = type==iss::address_type::PHYSICAL?
write_mem(phys_addr_t{access, space, addr}, length, data): write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) if (unlikely(res != iss::Ok)) {
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault) this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -720,6 +751,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
} }
@ -774,8 +806,50 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == mcycleh)
return iss::Err;
mcycle_csr = static_cast<uint64_t>(val);
} else {
if (addr == mcycle) {
mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
} else {
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
}
}
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if ((addr&0xff) == (minstreth&0xff))
return iss::Err;
this->reg.instret = static_cast<uint64_t>(val);
} else {
if ((addr&0xff) == (minstret&0xff)) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->reg.instret--;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) { if (addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if (addr == timeh) { } else if (addr == timeh) {
@ -785,6 +859,11 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_mtvec(unsigned addr, reg_t &val) {
val = csr[mtvec] & ~2;
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_status(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_status(unsigned addr, reg_t &val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
@ -835,6 +914,12 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_ip(unsigned
return iss::Ok; return iss::Ok;
} }
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_mepc(unsigned addr, reg_t val) {
auto mask = get_pc_mask();
csr[addr] = val;//(csr[addr] & ~mask) | (val & mask);
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) {
reg_t tvm = state.mstatus.TVM; reg_t tvm = state.mstatus.TVM;
if (this->reg.PRIV == PRIV_S & tvm != 0) { if (this->reg.PRIV == PRIV_S & tvm != 0) {
@ -918,7 +1003,6 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
template <typename BASE> template <typename BASE>
iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_write_cb) return mem_write_cb(paddr, length, data); if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) { switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg case 0x10013000: // UART0 base, TXFIFO reg
@ -1153,7 +1237,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
* access, or page-fault exception occurs, mtval is written with the * access, or page-fault exception occurs, mtval is written with the
* faulting effective address. * faulting effective address.
*/ */
csr[utval | (new_priv << 8)] = cause==2?instr : fault_data; csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0; fault_data = 0;
} else { } else {
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
@ -1193,7 +1277,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
auto ivec = csr[utvec | (new_priv << 8)]; auto ivec = csr[utvec | (new_priv << 8)];
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
// bits in mtvec // bits in mtvec
this->reg.NEXT_PC = ivec & ~0x1UL; this->reg.NEXT_PC = ivec & ~0x3UL;
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause; if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
// reset trap state // reset trap state
this->reg.PRIV = new_priv; this->reg.PRIV = new_priv;

View File

@ -154,15 +154,29 @@ public:
mstatus = new_val; mstatus = new_val;
} }
T satp;
static constexpr uint32_t get_mask(unsigned priv_lvl) { static constexpr uint32_t get_mask(unsigned priv_lvl) {
#if __cplusplus < 201402L #if __cplusplus < 201402L
return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL;
#else #else
switch (priv_lvl) { switch (priv_lvl) {
case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 case PRIV_U: return 0x00000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
default: return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 default:
// +-SD
// | +-TSR
// | |+-TW
// | ||+-TVM
// | |||+-MXR
// | ||||+-SUM
// | |||||+-MPRV
// | |||||| +-XS
// | |||||| | +-FS
// | |||||| | | +-MPP
// | |||||| | | | +-SPP
// | |||||| | | | |+-MPIE
// | |||||| | | | || +-UPIE
// | ||||||/|/|/| || |+-MIE
// | ||||||/|/|/| || || +-UIE
return 0b00000000000000000001100010011001;
} }
#endif #endif
} }
@ -172,13 +186,17 @@ public:
constexpr reg_t get_irq_mask(size_t mode) { constexpr reg_t get_irq_mask(size_t mode) {
std::array<const reg_t, 4> m = {{ std::array<const reg_t, 4> m = {{
0b000100010001, // U mode 0b000100010001, // U mode
0b001100110011, // S mode 0, // S mode
0, 0,
0b101110111011 // M mode 0b100110011001 // M mode
}}; }};
return m[mode]; return m[mode];
} }
constexpr reg_t get_pc_mask() {
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
}
riscv_hart_mu_p(); riscv_hart_mu_p();
virtual ~riscv_hart_mu_p() = default; virtual ~riscv_hart_mu_p() = default;
@ -200,7 +218,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount); pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
}; };
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -249,7 +267,10 @@ protected:
virtual iss::status write_csr(unsigned addr, reg_t val); virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state; hart_state_type state;
uint64_t cycle_offset; int64_t cycle_offset{0};
uint64_t mcycle_csr{0};
int64_t instret_offset{0};
uint64_t minstret_csr{0};
reg_t fault_data; reg_t fault_data;
uint64_t tohost = tohost_dflt; uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt; uint64_t fromhost = fromhost_dflt;
@ -270,7 +291,13 @@ protected:
private: private:
iss::status read_reg(unsigned addr, reg_t &val); iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val); iss::status write_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val); iss::status read_cycle(unsigned addr, reg_t &val);
iss::status write_cycle(unsigned addr, reg_t val);
iss::status read_instret(unsigned addr, reg_t &val);
iss::status write_instret(unsigned addr, reg_t val);
iss::status read_mtvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val); iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val); iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val); iss::status write_status(unsigned addr, reg_t val);
@ -279,6 +306,7 @@ private:
iss::status read_ip(unsigned addr, reg_t &val); iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val); iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val); iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_mepc(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0}; reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb; std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
@ -291,21 +319,55 @@ protected:
template <typename BASE, features_e FEAT> template <typename BASE, features_e FEAT>
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
: state() : state()
, cycle_offset(0)
, instr_if(*this) { , instr_if(*this) {
// reset values
csr[misa] = traits<BASE>::MISA_VAL; csr[misa] = traits<BASE>::MISA_VAL;
csr[mvendorid] = 0x669;
csr[marchid] = 0x80000003;
csr[mimpid] = 1;
uart_buf.str(""); uart_buf.str("");
for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr; for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr; csr_rd_cb[addr] = &this_class::read_null;
// special handling csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
}
for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
//csr_wr_cb[addr] = &this_class::write_reg;
}
// common regs
const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg;
}
// special handling & overrides
csr_rd_cb[time] = &this_class::read_time; csr_rd_cb[time] = &this_class::read_time;
csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time; csr_rd_cb[timeh] = &this_class::read_time;
csr_wr_cb[timeh] = nullptr; csr_rd_cb[cycle] = &this_class::read_cycle;
csr_rd_cb[cycleh] = &this_class::read_cycle;
csr_rd_cb[instret] = &this_class::read_instret;
csr_rd_cb[instreth] = &this_class::read_instret;
csr_rd_cb[mcycle] = &this_class::read_cycle; csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle; csr_rd_cb[mcycleh] = &this_class::read_cycle;
csr_rd_cb[minstret] = &this_class::read_cycle; csr_wr_cb[mcycleh] = &this_class::write_cycle;
csr_rd_cb[minstreth] = &this_class::read_cycle; csr_rd_cb[minstret] = &this_class::read_instret;
csr_wr_cb[minstret] = &this_class::write_instret;
csr_rd_cb[minstreth] = &this_class::read_instret;
csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status; csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status; csr_wr_cb[mstatus] = &this_class::write_status;
csr_rd_cb[ustatus] = &this_class::read_status; csr_rd_cb[ustatus] = &this_class::read_status;
@ -319,15 +381,14 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
csr_rd_cb[uie] = &this_class::read_ie; csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie; csr_wr_cb[uie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid; csr_rd_cb[mhartid] = &this_class::read_hartid;
// common regs csr_rd_cb[mcounteren] = &this_class::read_null;
const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}}; csr_wr_cb[mcounteren] = &this_class::write_null;
for(auto addr: addrs) { csr_rd_cb[mtvec] = &this_class::read_mtvec;
csr_rd_cb[addr] = &this_class::read_reg; csr_wr_cb[mepc] = &this_class::write_mepc;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[misa] = &this_class::write_null;
} csr_wr_cb[mvendorid] = &this_class::write_null;
// read-only registers csr_wr_cb[marchid] = &this_class::write_null;
csr_rd_cb[misa] = &this_class::read_reg; csr_wr_cb[mimpid] = &this_class::write_null;
csr_wr_cb[misa] = nullptr;
if(FEAT & FEAT_PMP){ if(FEAT & FEAT_PMP){
for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){ for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){
@ -413,13 +474,23 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
return iss::Err; return iss::Err;
} }
try { try {
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if(alignment>1 && (addr&(alignment-1))){
this->reg.trap_state = 1<<31 | 4<<16;
fault_data=addr;
return iss::Err;
}
auto res = type==iss::address_type::PHYSICAL? auto res = type==iss::address_type::PHYSICAL?
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data): read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault if (unlikely(res != iss::Ok)){
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
} break; } break;
@ -445,6 +516,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
} }
@ -485,14 +557,22 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
return iss::Err; return iss::Err;
} }
try { try {
if(length>1 && (addr&(length-1))){
this->reg.trap_state = 1<<31 | 6<<16;
fault_data=addr;
return iss::Err;
}
auto res = type==iss::address_type::PHYSICAL? auto res = type==iss::address_type::PHYSICAL?
write_mem(phys_addr_t{access, space, addr}, length, data): write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) if (unlikely(res != iss::Ok)) {
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault) this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -552,6 +632,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
} }
@ -585,6 +666,11 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_null(unsigned addr, reg_t &val) {
val = 0;
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_reg(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_reg(unsigned addr, reg_t val) {
csr[addr] = val; csr[addr] = val;
return iss::Ok; return iss::Ok;
@ -601,8 +687,50 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == mcycleh)
return iss::Err;
mcycle_csr = static_cast<uint64_t>(val);
} else {
if (addr == mcycle) {
mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
} else {
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
}
}
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) {
if ((addr&0xff) == (minstreth&0xff))
return iss::Err;
this->reg.instret = static_cast<uint64_t>(val);
} else {
if ((addr&0xff) == (minstret&0xff)) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->reg.instret--;
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) { if (addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if (addr == timeh) { } else if (addr == timeh) {
@ -612,6 +740,10 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
return iss::Ok; return iss::Ok;
} }
template <typename BASEE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_mtvec(unsigned addr, reg_t &val) {
val = csr[mtvec] & ~2;
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
@ -659,9 +791,14 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_mepc(unsigned addr, reg_t val) {
auto mask = get_pc_mask();
csr[addr] = val;//(csr[addr] & ~mask) | (val & mask);
return iss::Ok;
}
template <typename BASE, features_e FEAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_read_cb) return mem_read_cb(paddr, length, data); if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) { switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg case 0x0200BFF8: { // CLINT base, mtime reg
@ -677,9 +814,9 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
if (this->reg.icount > 30000) data[3] |= 0x80; if (this->reg.icount > 30000) data[3] |= 0x80;
} break; } break;
default: { default: {
const auto &p = mem(paddr.val / mem.page_size); for(auto offs=0U; offs<length; ++offs) {
auto offs = paddr.val & mem.page_addr_mask; *(data + offs)=mem[(paddr.val+offs)%mem.size()];
std::copy(p.data() + offs, p.data() + offs + length, data); }
} }
} }
return iss::Ok; return iss::Ok;
@ -687,7 +824,6 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
template <typename BASE, features_e FEAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_write_cb) return mem_write_cb(paddr, length, data); if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) { switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg case 0x10013000: // UART0 base, TXFIFO reg
@ -719,9 +855,10 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// tohost handling in case of riscv-test // tohost handling in case of riscv-test
if (paddr.access && iss::access_type::FUNC) { if (paddr.access && iss::access_type::FUNC) {
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)); auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4)) ||
(traits<BASE>::XLEN == 64 && paddr.val == tohost);
auto tohost_lower = auto tohost_lower =
(traits<BASE>::XLEN == 32 && paddr.val == tohost); (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
if (tohost_lower || tohost_upper) { if (tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)); uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask));
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
@ -752,7 +889,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
} }
} else if (tohost_lower) } else if (tohost_lower)
to_host_wr_cnt++; to_host_wr_cnt++;
} else if (traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) { } else if ((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) ||
(traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask)); uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask));
*reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
} }
@ -809,7 +947,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
* access, or page-fault exception occurs, mtval is written with the * access, or page-fault exception occurs, mtval is written with the
* faulting effective address. * faulting effective address.
*/ */
csr[utval | (new_priv << 8)] = cause==2?instr:fault_data; csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0; fault_data = 0;
} else { } else {
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)