|  |  |  | @@ -66,7 +66,7 @@ | 
		
	
		
			
				|  |  |  |  | namespace iss { | 
		
	
		
			
				|  |  |  |  | namespace arch { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> class riscv_hart_m_p : public BASE { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT=FEAT_NONE> class riscv_hart_m_p : public BASE { | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | 
		
	
		
			
				|  |  |  |  |     const std::array<const char *, 16> trap_str = {{"" | 
		
	
	
		
			
				
					
					|  |  |  | @@ -92,7 +92,7 @@ protected: | 
		
	
		
			
				|  |  |  |  |          "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
		
			
				|  |  |  |  |     using core = BASE; | 
		
	
		
			
				|  |  |  |  |     using this_class = riscv_hart_m_p<BASE>; | 
		
	
		
			
				|  |  |  |  |     using this_class = riscv_hart_m_p<BASE, FEAT>; | 
		
	
		
			
				|  |  |  |  |     using phys_addr_t = typename core::phys_addr_t; | 
		
	
		
			
				|  |  |  |  |     using reg_t = typename core::reg_t; | 
		
	
		
			
				|  |  |  |  |     using addr_t = typename core::addr_t; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -221,7 +221,7 @@ public: | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     struct riscv_instrumentation_if : public iss::instrumentation_if { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         riscv_instrumentation_if(riscv_hart_m_p<BASE> &arch) | 
		
	
		
			
				|  |  |  |  |         riscv_instrumentation_if(riscv_hart_m_p<BASE, FEAT> &arch) | 
		
	
		
			
				|  |  |  |  |         : arch(arch) {} | 
		
	
		
			
				|  |  |  |  |         /** | 
		
	
		
			
				|  |  |  |  |          * get the name of this architecture | 
		
	
	
		
			
				
					
					|  |  |  | @@ -236,7 +236,7 @@ protected: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         riscv_hart_m_p<BASE> &arch; | 
		
	
		
			
				|  |  |  |  |         riscv_hart_m_p<BASE, FEAT> &arch; | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     friend struct riscv_instrumentation_if; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -246,6 +246,9 @@ protected: | 
		
	
		
			
				|  |  |  |  |     virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data); | 
		
	
		
			
				|  |  |  |  |     virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     iss::status read_clic(uint64_t addr, unsigned length, uint8_t *const data); | 
		
	
		
			
				|  |  |  |  |     iss::status write_clic(uint64_t addr, unsigned length, const uint8_t *const data); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     virtual iss::status read_csr(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     virtual iss::status write_csr(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -270,10 +273,23 @@ protected: | 
		
	
		
			
				|  |  |  |  |     std::unordered_map<uint64_t, uint8_t> atomic_reservation; | 
		
	
		
			
				|  |  |  |  |     std::unordered_map<unsigned, rd_csr_f> csr_rd_cb; | 
		
	
		
			
				|  |  |  |  |     std::unordered_map<unsigned, wr_csr_f> csr_wr_cb; | 
		
	
		
			
				|  |  |  |  |     uint8_t clic_cfg_reg{0}; | 
		
	
		
			
				|  |  |  |  |     uint32_t clic_info_reg{0}; | 
		
	
		
			
				|  |  |  |  |     std::array<uint32_t, 32> clic_inttrig_reg; | 
		
	
		
			
				|  |  |  |  |     union clic_int_reg_t { | 
		
	
		
			
				|  |  |  |  |         struct{ | 
		
	
		
			
				|  |  |  |  |             uint8_t ip; | 
		
	
		
			
				|  |  |  |  |             uint8_t ie; | 
		
	
		
			
				|  |  |  |  |             uint8_t attr; | 
		
	
		
			
				|  |  |  |  |             uint8_t ctl; | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  |         uint32_t raw; | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  |     std::vector<clic_int_reg_t> clic_int_reg; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | private: | 
		
	
		
			
				|  |  |  |  |     iss::status read_reg(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_reg(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     iss::status read_csr_reg(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_csr_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); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -291,17 +307,22 @@ private: | 
		
	
		
			
				|  |  |  |  |     iss::status write_ip(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     iss::status read_hartid(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_epc(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     iss::status write_dcsr(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     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, const uint8_t *const)> mem_write_cb; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     void check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); | 
		
	
		
			
				|  |  |  |  |     uint64_t clic_base_addr{0}; | 
		
	
		
			
				|  |  |  |  |     unsigned clic_num_irq{0}; | 
		
	
		
			
				|  |  |  |  |     unsigned clic_num_trigger{0}; | 
		
	
		
			
				|  |  |  |  |     unsigned mcause_max_irq{16}; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> | 
		
	
		
			
				|  |  |  |  | riscv_hart_m_p<BASE>::riscv_hart_m_p() | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> | 
		
	
		
			
				|  |  |  |  | riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p() | 
		
	
		
			
				|  |  |  |  | : state() | 
		
	
		
			
				|  |  |  |  | , instr_if(*this) { | 
		
	
		
			
				|  |  |  |  |     // reset values | 
		
	
	
		
			
				
					
					|  |  |  | @@ -309,32 +330,33 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p() | 
		
	
		
			
				|  |  |  |  |     csr[mvendorid] = 0x669; | 
		
	
		
			
				|  |  |  |  |     csr[marchid] = traits<BASE>::MARCHID_VAL; | 
		
	
		
			
				|  |  |  |  |     csr[mimpid] = 1; | 
		
	
		
			
				|  |  |  |  |     csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     uart_buf.str(""); | 
		
	
		
			
				|  |  |  |  |     for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){ | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[addr] = &this_class::read_null; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_csr_reg; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){ | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[addr] = &this_class::read_null; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_csr_reg; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){ | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[addr] = &this_class::read_null; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_csr_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; | 
		
	
		
			
				|  |  |  |  |         //csr_wr_cb[addr] = &this_class::write_csr_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_rd_cb[addr] = &this_class::read_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[addr] = &this_class::write_csr_reg; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     // special handling & overrides | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[time] = &this_class::read_time; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -362,15 +384,23 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p() | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[mie] = &this_class::read_ie; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[mie] = &this_class::write_ie; | 
		
	
		
			
				|  |  |  |  |     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_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_DEBUG){ | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[dscratch0] = &this_class::write_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[dscratch0] = &this_class::read_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[dscratch1] = &this_class::write_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[dscratch1] = &this_class::read_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[dpc] = &this_class::write_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[dpc] = &this_class::read_csr_reg; | 
		
	
		
			
				|  |  |  |  |         csr_wr_cb[dcsr] = &this_class::write_dcsr; | 
		
	
		
			
				|  |  |  |  |         csr_rd_cb[dcsr] = &this_class::read_csr_reg; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_file(std::string name, int type) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) { | 
		
	
		
			
				|  |  |  |  |     FILE *fp = fopen(name.c_str(), "r"); | 
		
	
		
			
				|  |  |  |  |     if (fp) { | 
		
	
		
			
				|  |  |  |  |         std::array<char, 5> buf; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -436,8 +466,8 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_fi | 
		
	
		
			
				|  |  |  |  |     throw std::runtime_error("memory load file not found"); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_type access, const uint32_t space, | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_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) { | 
		
	
		
			
				|  |  |  |  | #ifndef NDEBUG | 
		
	
		
			
				|  |  |  |  |     if (access && iss::access_type::DEBUG) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -505,8 +535,8 @@ iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_typ | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_type access, const uint32_t space, | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const access_type access, const uint32_t space, | 
		
	
		
			
				|  |  |  |  |         const uint64_t addr, const unsigned length, const uint8_t *const data) { | 
		
	
		
			
				|  |  |  |  | #ifndef NDEBUG | 
		
	
		
			
				|  |  |  |  |     const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -621,7 +651,7 @@ iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_ty | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     if (addr >= csr.size()) return iss::Err; | 
		
	
		
			
				|  |  |  |  |     auto req_priv_lvl = (addr >> 8) & 0x3; | 
		
	
		
			
				|  |  |  |  |     if (this->reg.PRIV < req_priv_lvl) // not having required privileges | 
		
	
	
		
			
				
					
					|  |  |  | @@ -632,7 +662,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned add | 
		
	
		
			
				|  |  |  |  |     return (this->*(it->second))(addr, val); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     if (addr >= csr.size()) return iss::Err; | 
		
	
		
			
				|  |  |  |  |     auto req_priv_lvl = (addr >> 8) & 0x3; | 
		
	
		
			
				|  |  |  |  |     if (this->reg.PRIV < req_priv_lvl) // not having required privileges | 
		
	
	
		
			
				
					
					|  |  |  | @@ -645,22 +675,22 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned ad | 
		
	
		
			
				|  |  |  |  |     return (this->*(it->second))(addr, val); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_reg(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr_reg(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     val = csr[addr]; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_null(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | 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> iss::status riscv_hart_m_p<BASE>::write_reg(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr_reg(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     csr[addr] = val; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     auto cycle_val = this->reg.icount + cycle_offset; | 
		
	
		
			
				|  |  |  |  |     if (addr == mcycle) { | 
		
	
		
			
				|  |  |  |  |         val = static_cast<reg_t>(cycle_val); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -671,7 +701,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | 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; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -687,7 +717,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | 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)) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -697,7 +727,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | 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; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -713,7 +743,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigne | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::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); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -724,50 +754,50 @@ 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_tvec(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     val = csr[mtvec] & ~2; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     val = state.mstatus & hart_state_type::get_mask(); | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     state.write_mstatus(val); | 
		
	
		
			
				|  |  |  |  |     check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cause(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))|0xf); //TODO: make exception code size configurable | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ie(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     val = csr[mie]; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_hartid(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     val = mhartid_reg; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     auto mask = get_irq_mask(); | 
		
	
		
			
				|  |  |  |  |     csr[mie] = (csr[mie] & ~mask) | (val & mask); | 
		
	
		
			
				|  |  |  |  |     check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ip(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     val = csr[mip]; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ip(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     auto mask = get_irq_mask(); | 
		
	
		
			
				|  |  |  |  |     mask &= ~(1 << 7); // MTIP is read only | 
		
	
		
			
				|  |  |  |  |     csr[mip] = (csr[mip] & ~mask) | (val & mask); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -775,13 +805,22 @@ 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_epc(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     csr[addr] = val & get_pc_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) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     //                  +-------------- ebreakm | 
		
	
		
			
				|  |  |  |  |     //                  |   +---------- stepi | 
		
	
		
			
				|  |  |  |  |     //                  |   |  +++----- cause | 
		
	
		
			
				|  |  |  |  |     //                  |   |  |||   +- step | 
		
	
		
			
				|  |  |  |  |     csr[addr] = val & 0b1000100111000100U; | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { | 
		
	
		
			
				|  |  |  |  |     if(mem_read_cb) return mem_read_cb(paddr, length, data); | 
		
	
		
			
				|  |  |  |  |     switch (paddr.val) { | 
		
	
		
			
				|  |  |  |  |     case 0x0200BFF8: { // CLINT base, mtime reg | 
		
	
	
		
			
				
					
					|  |  |  | @@ -805,8 +844,8 @@ iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, u | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { | 
		
	
		
			
				|  |  |  |  |     if(mem_write_cb) return mem_write_cb(paddr, length, data); | 
		
	
		
			
				|  |  |  |  |     switch (paddr.val) { | 
		
	
		
			
				|  |  |  |  |     case 0x10013000: // UART0 base, TXFIFO reg | 
		
	
	
		
			
				
					
					|  |  |  | @@ -883,12 +922,12 @@ iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) { | 
		
	
		
			
				|  |  |  |  |     BASE::reset(address); | 
		
	
		
			
				|  |  |  |  |     state.mstatus = hart_state_type::mstatus_reset_val; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() { | 
		
	
		
			
				|  |  |  |  |     //auto ideleg = csr[mideleg]; | 
		
	
		
			
				|  |  |  |  |     // Multiple simultaneous interrupts and traps at the same privilege level are | 
		
	
		
			
				|  |  |  |  |     // handled in the following decreasing priority order: | 
		
	
	
		
			
				
					
					|  |  |  | @@ -910,14 +949,14 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_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 | 
		
	
		
			
				|  |  |  |  |     auto trap_id = bit_sub<0, 16>(flags); | 
		
	
		
			
				|  |  |  |  |     auto cause = bit_sub<16, 15>(flags); | 
		
	
		
			
				|  |  |  |  |     if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause | 
		
	
		
			
				|  |  |  |  |     // calculate effective privilege level | 
		
	
		
			
				|  |  |  |  |     if (trap_id == 0) { // exception | 
		
	
		
			
				|  |  |  |  |         if (cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause | 
		
	
		
			
				|  |  |  |  |         // store ret addr in xepc register | 
		
	
		
			
				|  |  |  |  |         csr[mepc] = static_cast<reg_t>(addr) & get_pc_mask(); // store actual address instruction of exception | 
		
	
		
			
				|  |  |  |  |         switch(cause){ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -927,6 +966,12 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag | 
		
	
		
			
				|  |  |  |  |         case 2: | 
		
	
		
			
				|  |  |  |  |             csr[mtval] = (instr & 0x3)==3?instr:instr&0xffff; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case 3: | 
		
	
		
			
				|  |  |  |  |             //TODO: implement debug mode behavior | 
		
	
		
			
				|  |  |  |  |             // csr[dpc] = addr; | 
		
	
		
			
				|  |  |  |  |             // csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi) | 
		
	
		
			
				|  |  |  |  |             csr[mtval] = addr; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         default: | 
		
	
		
			
				|  |  |  |  |             csr[mtval] = fault_data; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -969,7 +1014,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag | 
		
	
		
			
				|  |  |  |  |     return this->reg.NEXT_PC; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::leave_trap(uint64_t flags) { | 
		
	
		
			
				|  |  |  |  |     state.mstatus.MIE = state.mstatus.MPIE; | 
		
	
		
			
				|  |  |  |  |     state.mstatus.MPIE = 1; | 
		
	
		
			
				|  |  |  |  |     // sets the pc to the value stored in the x epc register. | 
		
	
	
		
			
				
					
					|  |  |  |   |