Compare commits
	
		
			1 Commits
		
	
	
		
			af887c286f
			...
			d95846a849
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d95846a849 | 
| @@ -296,6 +296,10 @@ inline bool is_count_limit_enabled(finish_cond_e cond){ | ||||
|     return (cond & finish_cond_e::COUNT_LIMIT) == finish_cond_e::COUNT_LIMIT; | ||||
| } | ||||
|  | ||||
| inline bool is_jump_to_self_enabled(finish_cond_e cond){ | ||||
|     return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; | ||||
| } | ||||
|  | ||||
| template <typename ARCH> | ||||
| typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){ | ||||
|     for(auto& e: qlut[instr&0x3]){ | ||||
| @@ -307,7 +311,6 @@ typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t inst | ||||
| template <typename ARCH> | ||||
| typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ | ||||
|     // we fetch at max 4 byte, alignment is 2 | ||||
|     enum {TRAP_ID=1<<16}; | ||||
|     code_word_t insn = 0; | ||||
|     auto *const data = (uint8_t *)&insn; | ||||
|     auto pc=start; | ||||
| @@ -315,15 +318,15 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | ||||
|             !(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){ | ||||
|         auto res = fetch_ins(pc, data); | ||||
|         if(res!=iss::Ok){ | ||||
|             auto new_pc = super::core.enter_trap(TRAP_ID, pc.val, 0); | ||||
|             res = fetch_ins(virt_addr_t{access_type::FETCH, new_pc}, data); | ||||
|             if(res!=iss::Ok) throw simulation_stopped(0); | ||||
|         } | ||||
|         if ((cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF && | ||||
|             this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max()); | ||||
|             pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0); | ||||
|         } else { | ||||
|             if (is_jump_to_self_enabled(cond) && | ||||
|                     (insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | ||||
|             auto f = decode_inst(insn); | ||||
|             pc = (this->*f)(pc, insn); | ||||
|         } | ||||
|     } | ||||
|     return pc; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -280,7 +280,7 @@ private: | ||||
|     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_tvec(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); | ||||
| @@ -290,7 +290,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 write_epc(unsigned addr, reg_t val); | ||||
|  | ||||
|     reg_t mhartid_reg{0x0}; | ||||
|     std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb; | ||||
| @@ -355,6 +355,8 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p() | ||||
|     csr_rd_cb[mstatus] = &this_class::read_status; | ||||
|     csr_wr_cb[mstatus] = &this_class::write_status; | ||||
|     csr_wr_cb[mcause] = &this_class::write_cause; | ||||
|     csr_rd_cb[mtvec] = &this_class::read_tvec; | ||||
|     csr_wr_cb[mepc] = &this_class::write_epc; | ||||
|     csr_rd_cb[mip] = &this_class::read_ip; | ||||
|     csr_wr_cb[mip] = &this_class::write_ip; | ||||
|     csr_rd_cb[mie] = &this_class::read_ie; | ||||
| @@ -362,8 +364,6 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p() | ||||
|     csr_rd_cb[mhartid] = &this_class::read_hartid; | ||||
|     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; | ||||
| @@ -702,7 +702,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_mtvec(unsigned addr, reg_t &val) { | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) { | ||||
|     val = csr[mtvec] & ~2; | ||||
|     return iss::Ok; | ||||
| } | ||||
| @@ -753,7 +753,7 @@ 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) { | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_epc(unsigned addr, reg_t val) { | ||||
|     csr[addr] = val & get_pc_mask(); | ||||
|     return iss::Ok; | ||||
| } | ||||
|   | ||||
| @@ -478,6 +478,12 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | ||||
|     csr_rd_cb[ustatus] = &this_class::read_status; | ||||
|     csr_wr_cb[ustatus] = &this_class::write_status; | ||||
|     csr_wr_cb[ucause] = &this_class::write_cause; | ||||
|     csr_rd_cb[mtvec] = &this_class::read_tvec; | ||||
|     csr_rd_cb[stvec] = &this_class::read_tvec; | ||||
|     csr_rd_cb[utvec] = &this_class::read_tvec; | ||||
|     csr_wr_cb[mepc] = &this_class::write_epc; | ||||
|     csr_wr_cb[sepc] = &this_class::write_epc; | ||||
|     csr_wr_cb[uepc] = &this_class::write_epc; | ||||
|     csr_rd_cb[mip] = &this_class::read_ip; | ||||
|     csr_wr_cb[mip] = &this_class::write_ip; | ||||
|     csr_rd_cb[sip] = &this_class::read_ip; | ||||
| @@ -493,8 +499,6 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | ||||
|     csr_rd_cb[mhartid] = &this_class::read_hartid; | ||||
|     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; | ||||
| @@ -868,8 +872,8 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_mtvec(unsigned addr, reg_t &val) { | ||||
|     val = csr[mtvec] & ~2; | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) { | ||||
|     val = csr[addr] & ~2; | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| @@ -928,9 +932,8 @@ 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); | ||||
| template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_epc(unsigned addr, reg_t val) { | ||||
|      csr[addr] = val & get_pc_mask(); | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -297,7 +297,7 @@ private: | ||||
|     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_tvec(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); | ||||
| @@ -307,7 +307,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 write_epc(unsigned addr, reg_t val); | ||||
|  | ||||
|     reg_t mhartid_reg{0x0}; | ||||
|     std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb; | ||||
| @@ -315,6 +315,7 @@ private: | ||||
|  | ||||
| protected: | ||||
|     void check_interrupt(); | ||||
|     bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); | ||||
| }; | ||||
|  | ||||
| template <typename BASE, features_e FEAT> | ||||
| @@ -326,6 +327,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() | ||||
|     csr[mvendorid] = 0x669; | ||||
|     csr[marchid] = 0x80000003; | ||||
|     csr[mimpid] = 1; | ||||
|     csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file | ||||
|  | ||||
|     uart_buf.str(""); | ||||
|     for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){ | ||||
| @@ -348,7 +350,11 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() | ||||
|         //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}}; | ||||
|     const std::array<unsigned, 14> addrs{{ | ||||
|         misa, mvendorid, marchid, mimpid, | ||||
|         mepc, mtvec, mscratch, mcause, mtval, | ||||
|         uepc, utvec, uscratch, ucause, utval, | ||||
|     }}; | ||||
|     for(auto addr: addrs) { | ||||
|         csr_rd_cb[addr] = &this_class::read_reg; | ||||
|         csr_wr_cb[addr] = &this_class::write_reg; | ||||
| @@ -375,6 +381,10 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() | ||||
|     csr_rd_cb[ustatus] = &this_class::read_status; | ||||
|     csr_wr_cb[ustatus] = &this_class::write_status; | ||||
|     csr_wr_cb[ucause] = &this_class::write_cause; | ||||
|     csr_rd_cb[mtvec] = &this_class::read_tvec; | ||||
|     csr_rd_cb[utvec] = &this_class::read_tvec; | ||||
|     csr_wr_cb[mepc] = &this_class::write_epc; | ||||
|     csr_wr_cb[uepc] = &this_class::write_epc; | ||||
|     csr_rd_cb[mip] = &this_class::read_ip; | ||||
|     csr_wr_cb[mip] = &this_class::write_ip; | ||||
|     csr_rd_cb[uip] = &this_class::read_ip; | ||||
| @@ -386,8 +396,6 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() | ||||
|     csr_rd_cb[mhartid] = &this_class::read_hartid; | ||||
|     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; | ||||
| @@ -423,7 +431,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p() | ||||
|         csr_rd_cb[mintthresh] = &this_class::read_reg; | ||||
|         csr_wr_cb[mintthresh] = &this_class::write_reg; | ||||
|         csr_rd_cb[mclicbase] = &this_class::read_reg; | ||||
|         csr_wr_cb[mclicbase] = &this_class::write_reg; | ||||
|         csr_wr_cb[mclicbase] = &this_class::write_null; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -471,6 +479,54 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m | ||||
|     throw std::runtime_error("memory load file not found"); | ||||
| } | ||||
|  | ||||
| template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) { | ||||
|     constexpr auto PMP_SHIFT=2U; | ||||
|     constexpr auto PMP_R = 0x1U; | ||||
|     constexpr auto PMP_W = 0x2U; | ||||
|     constexpr auto PMP_X = 0x4U; | ||||
|     constexpr auto PMP_A = 0x18U; | ||||
|     constexpr auto PMP_L = 0x80U; | ||||
|     constexpr auto PMP_TOR =0x1U; | ||||
|     constexpr auto PMP_NA4 =0x2U; | ||||
|     constexpr auto PMP_NAPOT =0x3U; | ||||
|     reg_t base = 0; | ||||
|     for (size_t i = 0; i < 16; i++) { | ||||
|         reg_t tor = csr[pmpaddr0+i] << PMP_SHIFT; | ||||
|         uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4); | ||||
|         if (cfg & PMP_A) { | ||||
|             bool is_tor = (cfg & PMP_A) == PMP_TOR; | ||||
|             bool is_na4 = (cfg & PMP_A) == PMP_NA4; | ||||
|  | ||||
|             reg_t mask = (csr[pmpaddr0+i] << 1) | (!is_na4); | ||||
|             mask = ~(mask & ~(mask + 1)) << PMP_SHIFT; | ||||
|  | ||||
|             // Check each 4-byte sector of the access | ||||
|             bool any_match = false; | ||||
|             bool all_match = true; | ||||
|             for (reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) { | ||||
|                 reg_t cur_addr = addr + offset; | ||||
|                 bool napot_match = ((cur_addr ^ tor) & mask) == 0; | ||||
|                 bool tor_match = base <= cur_addr && cur_addr < tor; | ||||
|                 bool match = is_tor ? tor_match : napot_match; | ||||
|                 any_match |= match; | ||||
|                 all_match &= match; | ||||
|             } | ||||
|             if (any_match) { | ||||
|                 // If the PMP matches only a strict subset of the access, fail it | ||||
|                 if (!all_match) | ||||
|                     return false; | ||||
|                 return  (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) || | ||||
|                         (type == access_type::READ && (cfg & PMP_R)) || | ||||
|                         (type == access_type::WRITE && (cfg & PMP_W)) || | ||||
|                         (type == access_type::FETCH && (cfg & PMP_X)); | ||||
|             } | ||||
|         } | ||||
|         base = tor; | ||||
|     } | ||||
|     return this->reg.PRIV == PRIV_M; | ||||
| } | ||||
|  | ||||
|  | ||||
| template <typename BASE, features_e FEAT> | ||||
| iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space, | ||||
|         const uint64_t addr, const unsigned length, uint8_t *const data) { | ||||
| @@ -486,6 +542,14 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc | ||||
|     try { | ||||
|         switch (space) { | ||||
|         case traits<BASE>::MEM: { | ||||
|             if(FEAT & FEAT_PMP){ | ||||
|                 if(!pmp_check(access, addr, length)) { | ||||
|                     fault_data = addr; | ||||
|                     if (access && iss::access_type::DEBUG) throw trap_access(0, addr); | ||||
|                     this->reg.trap_state = (1 << 31) | (1 << 16); // issue trap 1 | ||||
|                     return iss::Err; | ||||
|                 } | ||||
|             } | ||||
|             if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) { | ||||
|                 fault_data = addr; | ||||
|                 if (access && iss::access_type::DEBUG) throw trap_access(0, addr); | ||||
| @@ -569,6 +633,14 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac | ||||
|     try { | ||||
|         switch (space) { | ||||
|         case traits<BASE>::MEM: { | ||||
|             if(FEAT & FEAT_PMP){ | ||||
|                 if(!pmp_check(access, addr, length)) { | ||||
|                     fault_data = addr; | ||||
|                     if (access && iss::access_type::DEBUG) throw trap_access(0, addr); | ||||
|                     this->reg.trap_state = (1 << 31) | (1 << 16); // issue trap 1 | ||||
|                     return iss::Err; | ||||
|                 } | ||||
|             } | ||||
|             if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) { | ||||
|                 fault_data = addr; | ||||
|                 if (access && iss::access_type::DEBUG) throw trap_access(0, addr); | ||||
| @@ -759,8 +831,8 @@ 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_mu_p<BASE, FEAT>::read_mtvec(unsigned addr, reg_t &val) { | ||||
|     val = csr[mtvec] & ~2; | ||||
| template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) { | ||||
|     val = csr[addr] & ~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) { | ||||
| @@ -815,9 +887,8 @@ 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_mu_p<BASE, FEAT>::write_mepc(unsigned addr, reg_t val) { | ||||
|     auto mask = get_pc_mask(); | ||||
|     csr[addr] = val;//(csr[addr] & ~mask) | (val & mask); | ||||
| template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) { | ||||
|     csr[addr] = val & get_pc_mask(); | ||||
|     return iss::Ok; | ||||
| } | ||||
|  | ||||
| @@ -954,6 +1025,7 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec | ||||
| template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) { | ||||
|     // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] | ||||
|     // calculate and write mcause val | ||||
|     if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.trap_state; | ||||
|     auto trap_id = bit_sub<0, 16>(flags); | ||||
|     auto cause = bit_sub<16, 15>(flags); | ||||
|     if (trap_id == 0 && cause == 11) cause = 0x8 + this->reg.PRIV; // adjust environment call cause | ||||
|   | ||||
		Reference in New Issue
	
	Block a user