Compare commits
	
		
			1 Commits
		
	
	
		
			2f4b5bd9b2
			...
			473f8a5a17
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 473f8a5a17 | 
| @@ -176,6 +176,10 @@ public: | ||||
|         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(); | ||||
|     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::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_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<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 | ||||
|     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<BASE>::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 <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) { | ||||
|     if (addr == minstret) { | ||||
|     if ((addr&0xff) == (minstret&0xff)) { | ||||
|         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; | ||||
|         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) { | ||||
|     if (sizeof(typename traits<BASE>::reg_t) != 4) { | ||||
|         if (addr == minstreth) | ||||
|         if ((addr&0xff) == (minstreth&0xff)) | ||||
|             return iss::Err; | ||||
|         this->reg.instret = static_cast<uint64_t>(val); | ||||
|     } else { | ||||
|         if (addr == minstret) { | ||||
|         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); | ||||
| @@ -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) { | ||||
|     val = csr[mie]; | ||||
|     //val &= csr[mideleg]; | ||||
|     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) { | ||||
|     val = csr[mip]; | ||||
|     //val &= csr[mideleg]; | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| @@ -740,6 +746,12 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned add | ||||
|     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_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); | ||||
| @@ -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)); | ||||
|         // tohost handling in case of riscv-test | ||||
|         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 = | ||||
|                 (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) { | ||||
|                 uint64_t hostvar = *reinterpret_cast<uint64_t *>(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<BASE>::write_mem(phys_addr_t paddr, unsigned length, | ||||
|                     } | ||||
|                 } else if (tohost_lower) | ||||
|                     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)); | ||||
|                 *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; | ||||
|     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 <typename BASE> uint64_t riscv_hart_m_p<BASE>::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; | ||||
|   | ||||
| @@ -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_info, 2> vm; | ||||
|     uint64_t tohost = tohost_dflt; | ||||
| @@ -377,10 +380,15 @@ protected: | ||||
|     std::unordered_map<unsigned, wr_csr_f> 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 <typename BASE> | ||||
| riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | ||||
| : state() | ||||
| , cycle_offset(0) | ||||
| , 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(""); | ||||
|     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<BASE>::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<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 | ||||
|     // 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<BASE>::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<unsigned, 6> 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<BASE>::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<BASE>::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<BASE>::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<BASE>::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 <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) { | ||||
|     uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::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> 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) { | ||||
|         val = static_cast<reg_t>(time_val); | ||||
|     } else if (addr == timeh) { | ||||
| @@ -785,6 +859,11 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned | ||||
|     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) { | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     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; | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|     reg_t tvm = state.mstatus.TVM; | ||||
|     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> | ||||
| 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); | ||||
|     switch (paddr.val) { | ||||
|     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 | ||||
|          * 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 <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::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; | ||||
|   | ||||
| @@ -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<const reg_t, 4> 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<BASE>::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::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb; | ||||
| @@ -291,21 +319,55 @@ protected: | ||||
| template <typename BASE, features_e FEAT> | ||||
| riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() | ||||
| : state() | ||||
| , cycle_offset(0) | ||||
| , instr_if(*this) { | ||||
|     // reset values | ||||
|     csr[misa] = traits<BASE>::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<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_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<BASE, FEAT>::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<unsigned, 6> 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<BASE, FEAT>::read(const address_type type, const acc | ||||
|                 return iss::Err; | ||||
|             } | ||||
|             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? | ||||
|                         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<BASE, FEAT>::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<BASE, FEAT>::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<BASE, FEAT>::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 <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT | ||||
|     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) { | ||||
|     csr[addr] = val; | ||||
|     return iss::Ok; | ||||
| @@ -601,8 +687,50 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT | ||||
|     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) { | ||||
|     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<reg_t>(time_val); | ||||
|     } 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; | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|     auto req_priv_lvl = (addr >> 8) & 0x3; | ||||
|     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; | ||||
| } | ||||
|  | ||||
| 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> | ||||
| 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); | ||||
|     switch (paddr.val) { | ||||
|     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; | ||||
|     } 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<length; ++offs) { | ||||
|             *(data + offs)=mem[(paddr.val+offs)%mem.size()]; | ||||
|         } | ||||
|     } | ||||
|     } | ||||
|     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> | ||||
| 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); | ||||
|     switch (paddr.val) { | ||||
|     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)); | ||||
|         // tohost handling in case of riscv-test | ||||
|         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 = | ||||
|                 (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) { | ||||
|                 uint64_t hostvar = *reinterpret_cast<uint64_t *>(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<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l | ||||
|                     } | ||||
|                 } else if (tohost_lower) | ||||
|                     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)); | ||||
|                 *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 | ||||
|          * 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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user