From 473f8a5a17b6be02bdc332b3f4a541f52ec61db9 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Wed, 7 Jul 2021 11:30:00 +0200 Subject: [PATCH] fix privilege behavior --- incl/iss/arch/riscv_hart_m_p.h | 48 ++++--- incl/iss/arch/riscv_hart_msu_vp.h | 146 +++++++++++++++----- incl/iss/arch/riscv_hart_mu_p.h | 214 ++++++++++++++++++++++++------ 3 files changed, 322 insertions(+), 86 deletions(-) diff --git a/incl/iss/arch/riscv_hart_m_p.h b/incl/iss/arch/riscv_hart_m_p.h index 699f341..b02f999 100644 --- a/incl/iss/arch/riscv_hart_m_p.h +++ b/incl/iss/arch/riscv_hart_m_p.h @@ -176,6 +176,10 @@ public: return 0b100010001000; // only machine mode is supported } + constexpr reg_t get_pc_mask() { + return traits::MISA_VAL&0b0100?~1:~3; + } + riscv_hart_m_p(); virtual ~riscv_hart_m_p() = default; @@ -285,6 +289,7 @@ private: iss::status read_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 write_mepc(unsigned addr, reg_t val); reg_t mhartid_reg{0x0}; std::functionmem_read_cb; @@ -317,13 +322,12 @@ riscv_hart_m_p::riscv_hart_m_p() csr_rd_cb[addr] = &this_class::read_null; 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_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_wr_cb[addr] = &this_class::write_reg; + //csr_wr_cb[addr] = &this_class::write_reg; } // common regs const std::array addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}}; @@ -333,9 +337,12 @@ riscv_hart_m_p::riscv_hart_m_p() } // special handling & overrides csr_rd_cb[time] = &this_class::read_time; - csr_wr_cb[time] = nullptr; 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_wr_cb[mcycle] = &this_class::write_cycle; csr_rd_cb[mcycleh] = &this_class::read_cycle; @@ -354,6 +361,7 @@ riscv_hart_m_p::riscv_hart_m_p() csr_rd_cb[mcounteren] = &this_class::read_null; csr_wr_cb[mcounteren] = &this_class::write_null; 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[mvendorid] = &this_class::write_null; csr_wr_cb[marchid] = &this_class::write_null; @@ -656,9 +664,9 @@ template iss::status riscv_hart_m_p::write_cycle(unsigned } template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) { - if (addr == minstret) { + if ((addr&0xff) == (minstret&0xff)) { val = static_cast(this->reg.instret); - } else if (addr == minstreth) { + } else if ((addr&0xff) == (minstreth&0xff)) { if (sizeof(typename traits::reg_t) != 4) return iss::Err; val = static_cast(this->reg.instret >> 32); } @@ -667,11 +675,11 @@ template iss::status riscv_hart_m_p::read_instret(unsigned template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) { if (sizeof(typename traits::reg_t) != 4) { - if (addr == minstreth) + if ((addr&0xff) == (minstreth&0xff)) return iss::Err; this->reg.instret = static_cast(val); } else { - if (addr == minstret) { + if ((addr&0xff) == (minstret&0xff)) { this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; } else { this->reg.instret = (static_cast(val)<<32) + (this->reg.instret & 0xffffffff); @@ -710,7 +718,6 @@ template iss::status riscv_hart_m_p::write_status(unsigned template iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t &val) { val = csr[mie]; - //val &= csr[mideleg]; return iss::Ok; } @@ -728,7 +735,6 @@ template iss::status riscv_hart_m_p::write_ie(unsigned add template iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t &val) { val = csr[mip]; - //val &= csr[mideleg]; return iss::Ok; } @@ -740,6 +746,12 @@ template iss::status riscv_hart_m_p::write_ip(unsigned add return iss::Ok; } +template iss::status riscv_hart_m_p::write_mepc(unsigned addr, reg_t val) { + auto mask = get_pc_mask(); + csr[addr] = val;//(csr[addr] & ~mask) | (val & mask); + return iss::Ok; +} + template iss::status riscv_hart_m_p::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { if(mem_read_cb) return mem_read_cb(paddr, length, data); @@ -798,9 +810,10 @@ iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, unsigned length, std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); // tohost handling in case of riscv-test if (paddr.access && iss::access_type::FUNC) { - auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4)); + auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4)) || + (traits::XLEN == 64 && paddr.val == tohost); auto tohost_lower = - (traits::XLEN == 32 && paddr.val == tohost); + (traits::XLEN == 32 && paddr.val == tohost) || (traits::XLEN == 64 && paddr.val == tohost); if (tohost_lower || tohost_upper) { uint64_t hostvar = *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)); if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { @@ -831,7 +844,8 @@ iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, unsigned length, } } else if (tohost_lower) to_host_wr_cnt++; - } else if (traits::XLEN == 32 && paddr.val == fromhost + 4) { + } else if ((traits::XLEN == 32 && paddr.val == fromhost + 4) || + (traits::XLEN == 64 && paddr.val == fromhost)) { uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask)); *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; } @@ -856,7 +870,7 @@ template void riscv_hart_m_p::check_interrupt() { bool mie = state.mstatus.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) { int res = 0; @@ -918,7 +932,7 @@ template uint64_t riscv_hart_m_p::leave_trap(uint64_t flag state.mstatus.MIE = state.mstatus.MPIE; state.mstatus.MPIE = 1; // 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"; check_interrupt(); return this->reg.NEXT_PC; diff --git a/incl/iss/arch/riscv_hart_msu_vp.h b/incl/iss/arch/riscv_hart_msu_vp.h index d9cb528..f43d0e0 100644 --- a/incl/iss/arch/riscv_hart_msu_vp.h +++ b/incl/iss/arch/riscv_hart_msu_vp.h @@ -356,7 +356,10 @@ protected: virtual iss::status write_csr(unsigned addr, reg_t val); 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; std::array vm; uint64_t tohost = tohost_dflt; @@ -377,10 +380,15 @@ protected: std::unordered_map csr_wr_cb; private: - iss::status read_null(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 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 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_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 write_ip(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 write_satp(unsigned addr, reg_t val); iss::status read_fcsr(unsigned addr, reg_t &val); @@ -405,15 +414,19 @@ protected: template riscv_hart_msu_vp::riscv_hart_msu_vp() : state() -, cycle_offset(0) , instr_if(*this) { - csr[misa] = hart_state_type::get_misa(); + // reset values + csr[misa] = traits::MISA_VAL; + csr[mvendorid] = 0x669; + csr[marchid] = 0x80000003; + csr[mimpid] = 1; + 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_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_wr_cb[addr] = &this_class::write_reg; } @@ -421,23 +434,35 @@ riscv_hart_msu_vp::riscv_hart_msu_vp() csr_rd_cb[addr] = &this_class::read_null; 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_wr_cb[addr] = &this_class::write_reg; } for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){ csr_rd_cb[addr] = &this_class::read_null; + //csr_wr_cb[addr] = &this_class::write_reg; + } + // common regs + const std::array 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 + // special handling & overrides csr_rd_cb[time] = &this_class::read_time; - csr_wr_cb[time] = nullptr; 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_wr_cb[mcycle] = &this_class::write_cycle; csr_rd_cb[mcycleh] = &this_class::read_cycle; - csr_rd_cb[minstret] = &this_class::read_cycle; - csr_rd_cb[minstreth] = &this_class::read_cycle; + csr_wr_cb[mcycleh] = &this_class::write_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_wr_cb[mstatus] = &this_class::write_status; csr_rd_cb[sstatus] = &this_class::read_status; @@ -457,16 +482,14 @@ riscv_hart_msu_vp::riscv_hart_msu_vp() csr_rd_cb[uie] = &this_class::read_ie; csr_wr_cb[uie] = &this_class::write_ie; csr_rd_cb[mhartid] = &this_class::read_hartid; - // common regs - const std::array addrs{{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; - } - // read-only registers - csr_rd_cb[misa] = &this_class::read_reg; - csr_wr_cb[misa] = nullptr; - + csr_rd_cb[mcounteren] = &this_class::read_null; + csr_wr_cb[mcounteren] = &this_class::write_null; + 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[mvendorid] = &this_class::write_null; + csr_wr_cb[marchid] = &this_class::write_null; + csr_wr_cb[mimpid] = &this_class::write_null; csr_rd_cb[satp] = &this_class::read_satp; csr_wr_cb[satp] = &this_class::write_satp; csr_rd_cb[fcsr] = &this_class::read_fcsr; @@ -557,10 +580,14 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ auto res = type==iss::address_type::PHYSICAL? 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); - 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; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } } break; @@ -597,6 +624,7 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ return iss::Ok; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } } @@ -651,11 +679,14 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access auto res = type==iss::address_type::PHYSICAL? write_mem(phys_addr_t{access, space, addr}, length, data): write_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 7 (Store/AMO access fault) + if (unlikely(res != iss::Ok)) { + this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) + fault_data=addr; + } return res; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } @@ -720,6 +751,7 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access return iss::Ok; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } } @@ -774,8 +806,50 @@ template iss::status riscv_hart_m_p::read_cycle(unsigned a return iss::Ok; } -template iss::status riscv_hart_msu_vp::read_time(unsigned addr, reg_t &val) { - uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; +template iss::status riscv_hart_m_p::write_cycle(unsigned addr, reg_t val) { + if (sizeof(typename traits::reg_t) != 4) { + if (addr == mcycleh) + return iss::Err; + mcycle_csr = static_cast(val); + } else { + if (addr == mcycle) { + mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val; + } else { + mcycle_csr = (static_cast(val)<<32) + (mcycle_csr & 0xffffffff); + } + } + cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around + return iss::Ok; +} + +template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) { + if ((addr&0xff) == (minstret&0xff)) { + val = static_cast(this->reg.instret); + } else if ((addr&0xff) == (minstreth&0xff)) { + if (sizeof(typename traits::reg_t) != 4) return iss::Err; + val = static_cast(this->reg.instret >> 32); + } + return iss::Ok; +} + +template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) { + if (sizeof(typename traits::reg_t) != 4) { + if ((addr&0xff) == (minstreth&0xff)) + return iss::Err; + this->reg.instret = static_cast(val); + } else { + if ((addr&0xff) == (minstret&0xff)) { + this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; + } else { + this->reg.instret = (static_cast(val)<<32) + (this->reg.instret & 0xffffffff); + } + } + this->reg.instret--; + return iss::Ok; +} + +template iss::status riscv_hart_m_p::read_time(unsigned addr, reg_t &val) { + uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052; if (addr == time) { val = static_cast(time_val); } else if (addr == timeh) { @@ -785,6 +859,11 @@ template iss::status riscv_hart_msu_vp::read_time(unsigned return iss::Ok; } +template iss::status riscv_hart_m_p::read_mtvec(unsigned addr, reg_t &val) { + val = csr[mtvec] & ~2; + return iss::Ok; +} + template iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t &val) { auto req_priv_lvl = (addr >> 8) & 0x3; val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); @@ -835,6 +914,12 @@ template iss::status riscv_hart_msu_vp::write_ip(unsigned return iss::Ok; } +template iss::status riscv_hart_m_p::write_mepc(unsigned addr, reg_t val) { + auto mask = get_pc_mask(); + csr[addr] = val;//(csr[addr] & ~mask) | (val & mask); + return iss::Ok; +} + template iss::status riscv_hart_msu_vp::read_satp(unsigned addr, reg_t &val) { reg_t tvm = state.mstatus.TVM; if (this->reg.PRIV == PRIV_S & tvm != 0) { @@ -918,7 +1003,6 @@ iss::status riscv_hart_msu_vp::read_mem(phys_addr_t paddr, unsigned length template iss::status riscv_hart_msu_vp::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); switch (paddr.val) { case 0x10013000: // UART0 base, TXFIFO reg @@ -1153,7 +1237,7 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f * access, or page-fault exception occurs, mtval is written with the * 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; } else { if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) @@ -1193,7 +1277,7 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f auto ivec = csr[utvec | (new_priv << 8)]; // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE // 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; // reset trap state this->reg.PRIV = new_priv; diff --git a/incl/iss/arch/riscv_hart_mu_p.h b/incl/iss/arch/riscv_hart_mu_p.h index 50f4d5e..c7f5b2f 100644 --- a/incl/iss/arch/riscv_hart_mu_p.h +++ b/incl/iss/arch/riscv_hart_mu_p.h @@ -154,15 +154,29 @@ public: mstatus = new_val; } - T satp; - static constexpr uint32_t get_mask(unsigned priv_lvl) { #if __cplusplus < 201402L return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; #else switch (priv_lvl) { - case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 - default: return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 + case PRIV_U: return 0x00000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 + default: + // +-SD + // | +-TSR + // | |+-TW + // | ||+-TVM + // | |||+-MXR + // | ||||+-SUM + // | |||||+-MPRV + // | |||||| +-XS + // | |||||| | +-FS + // | |||||| | | +-MPP + // | |||||| | | | +-SPP + // | |||||| | | | |+-MPIE + // | |||||| | | | || +-UPIE + // | ||||||/|/|/| || |+-MIE + // | ||||||/|/|/| || || +-UIE + return 0b00000000000000000001100010011001; } #endif } @@ -172,13 +186,17 @@ public: constexpr reg_t get_irq_mask(size_t mode) { std::array m = {{ 0b000100010001, // U mode - 0b001100110011, // S mode + 0, // S mode 0, - 0b101110111011 // M mode + 0b100110011001 // M mode }}; return m[mode]; } + constexpr reg_t get_pc_mask() { + return traits::MISA_VAL&0b0100?~1:~3; + } + riscv_hart_mu_p(); virtual ~riscv_hart_mu_p() = default; @@ -200,7 +218,7 @@ public: void disass_output(uint64_t pc, const std::string instr) override { 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; } @@ -249,7 +267,10 @@ protected: virtual iss::status write_csr(unsigned addr, reg_t val); 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; uint64_t tohost = tohost_dflt; uint64_t fromhost = fromhost_dflt; @@ -270,7 +291,13 @@ protected: private: iss::status read_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 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_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 write_ip(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}; std::functionmem_read_cb; @@ -291,21 +319,55 @@ protected: template riscv_hart_mu_p::riscv_hart_mu_p() : state() -, cycle_offset(0) , instr_if(*this) { + // reset values csr[misa] = traits::MISA_VAL; + csr[mvendorid] = 0x669; + csr[marchid] = 0x80000003; + csr[mimpid] = 1; + uart_buf.str(""); - for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr; - for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr; - // special handling + for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){ + csr_rd_cb[addr] = &this_class::read_null; + 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 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_wr_cb[time] = nullptr; 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_wr_cb[mcycle] = &this_class::write_cycle; csr_rd_cb[mcycleh] = &this_class::read_cycle; - csr_rd_cb[minstret] = &this_class::read_cycle; - csr_rd_cb[minstreth] = &this_class::read_cycle; + csr_wr_cb[mcycleh] = &this_class::write_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_wr_cb[mstatus] = &this_class::write_status; csr_rd_cb[ustatus] = &this_class::read_status; @@ -319,15 +381,14 @@ riscv_hart_mu_p::riscv_hart_mu_p() csr_rd_cb[uie] = &this_class::read_ie; csr_wr_cb[uie] = &this_class::write_ie; csr_rd_cb[mhartid] = &this_class::read_hartid; - // common regs - const std::array addrs{{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; - } - // read-only registers - csr_rd_cb[misa] = &this_class::read_reg; - csr_wr_cb[misa] = nullptr; + csr_rd_cb[mcounteren] = &this_class::read_null; + csr_wr_cb[mcounteren] = &this_class::write_null; + 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[mvendorid] = &this_class::write_null; + csr_wr_cb[marchid] = &this_class::write_null; + csr_wr_cb[mimpid] = &this_class::write_null; if(FEAT & FEAT_PMP){ for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){ @@ -413,13 +474,23 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc return iss::Err; } try { + auto alignment = access == iss::access_type::FETCH? (traits::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? 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); - 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; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } } break; @@ -445,6 +516,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc return iss::Ok; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } } @@ -485,14 +557,22 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac return iss::Err; } 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? write_mem(phys_addr_t{access, space, addr}, length, data): write_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 7 (Store/AMO access fault) + if (unlikely(res != iss::Ok)) { + this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) + fault_data=addr; + } return res; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } @@ -552,6 +632,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac return iss::Ok; } catch (trap_access &ta) { this->reg.trap_state = (1 << 31) | ta.id; + fault_data=ta.addr; return iss::Err; } } @@ -585,6 +666,11 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::read_null(unsigned addr, reg_t &val) { + val = 0; + return iss::Ok; +} + template iss::status riscv_hart_mu_p::write_reg(unsigned addr, reg_t val) { csr[addr] = val; return iss::Ok; @@ -601,8 +687,50 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::write_cycle(unsigned addr, reg_t val) { + if (sizeof(typename traits::reg_t) != 4) { + if (addr == mcycleh) + return iss::Err; + mcycle_csr = static_cast(val); + } else { + if (addr == mcycle) { + mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val; + } else { + mcycle_csr = (static_cast(val)<<32) + (mcycle_csr & 0xffffffff); + } + } + cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around + return iss::Ok; +} + +template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) { + if ((addr&0xff) == (minstret&0xff)) { + val = static_cast(this->reg.instret); + } else if ((addr&0xff) == (minstreth&0xff)) { + if (sizeof(typename traits::reg_t) != 4) return iss::Err; + val = static_cast(this->reg.instret >> 32); + } + return iss::Ok; +} + +template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) { + if (sizeof(typename traits::reg_t) != 4) { + if ((addr&0xff) == (minstreth&0xff)) + return iss::Err; + this->reg.instret = static_cast(val); + } else { + if ((addr&0xff) == (minstret&0xff)) { + this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; + } else { + this->reg.instret = (static_cast(val)<<32) + (this->reg.instret & 0xffffffff); + } + } + this->reg.instret--; + return iss::Ok; +} + template iss::status riscv_hart_mu_p::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) { val = static_cast(time_val); } else if (addr == timeh) { @@ -612,6 +740,10 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::read_mtvec(unsigned addr, reg_t &val) { + val = csr[mtvec] & ~2; + return iss::Ok; +} template iss::status riscv_hart_mu_p::read_status(unsigned addr, reg_t &val) { auto req_priv_lvl = (addr >> 8) & 0x3; val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); @@ -659,9 +791,14 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::write_mepc(unsigned addr, reg_t val) { + auto mask = get_pc_mask(); + csr[addr] = val;//(csr[addr] & ~mask) | (val & mask); + return iss::Ok; +} + template iss::status riscv_hart_mu_p::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); switch (paddr.val) { case 0x0200BFF8: { // CLINT base, mtime reg @@ -677,9 +814,9 @@ iss::status riscv_hart_mu_p::read_mem(phys_addr_t paddr, unsigned le if (this->reg.icount > 30000) data[3] |= 0x80; } break; default: { - const auto &p = mem(paddr.val / mem.page_size); - auto offs = paddr.val & mem.page_addr_mask; - std::copy(p.data() + offs, p.data() + offs + length, data); + for(auto offs=0U; offs::read_mem(phys_addr_t paddr, unsigned le template iss::status riscv_hart_mu_p::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); switch (paddr.val) { case 0x10013000: // UART0 base, TXFIFO reg @@ -719,9 +855,10 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, unsigned l std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); // tohost handling in case of riscv-test if (paddr.access && iss::access_type::FUNC) { - auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4)); + auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4)) || + (traits::XLEN == 64 && paddr.val == tohost); auto tohost_lower = - (traits::XLEN == 32 && paddr.val == tohost); + (traits::XLEN == 32 && paddr.val == tohost) || (traits::XLEN == 64 && paddr.val == tohost); if (tohost_lower || tohost_upper) { uint64_t hostvar = *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)); if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { @@ -752,7 +889,8 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, unsigned l } } else if (tohost_lower) to_host_wr_cnt++; - } else if (traits::XLEN == 32 && paddr.val == fromhost + 4) { + } else if ((traits::XLEN == 32 && paddr.val == fromhost + 4) || + (traits::XLEN == 64 && paddr.val == fromhost)) { uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask)); *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; } @@ -809,7 +947,7 @@ template uint64_t riscv_hart_mu_p:: * access, or page-fault exception occurs, mtval is written with the * 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; } else { if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)