Compare commits
	
		
			1 Commits
		
	
	
		
			2f4b5bd9b2
			...
			473f8a5a17
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user