fix privilege behavior
This commit is contained in:
parent
2f4b5bd9b2
commit
473f8a5a17
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue