|  |  |  | @@ -316,6 +316,9 @@ public: | 
		
	
		
			
				|  |  |  |  |         csr[addr & csr.page_addr_mask] = val; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     void set_irq_num(unsigned i) { | 
		
	
		
			
				|  |  |  |  |         mcause_max_irq=1<<util::ilog2(i); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     struct riscv_instrumentation_if : public iss::instrumentation_if { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -328,21 +331,21 @@ protected: | 
		
	
		
			
				|  |  |  |  |          */ | 
		
	
		
			
				|  |  |  |  |         const std::string core_type_name() const override { return traits<BASE>::core_type; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         virtual uint64_t get_pc() { return arch.get_pc(); }; | 
		
	
		
			
				|  |  |  |  |         uint64_t get_pc() override { return arch.reg.PC; }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         virtual uint64_t get_next_pc() { return arch.get_next_pc(); }; | 
		
	
		
			
				|  |  |  |  |         uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         uint64_t get_instr_word() override { return arch.instruction; } | 
		
	
		
			
				|  |  |  |  |         uint64_t get_instr_word() override { return arch.reg.instruction; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         uint64_t get_instr_count() { return arch.icount; } | 
		
	
		
			
				|  |  |  |  |         uint64_t get_instr_count() override { return arch.reg.icount; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         uint64_t get_pendig_traps() override { return arch.trap_state; } | 
		
	
		
			
				|  |  |  |  |         uint64_t get_pendig_traps() override { return arch.reg.trap_state; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } | 
		
	
		
			
				|  |  |  |  |         uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         bool is_branch_taken() override { return arch.last_branch; }; | 
		
	
		
			
				|  |  |  |  |         bool is_branch_taken() override { return arch.reg.last_branch; }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         riscv_hart_msu_vp<BASE> &arch; | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -381,16 +384,17 @@ protected: | 
		
	
		
			
				|  |  |  |  |     std::unordered_map<unsigned, rd_csr_f> csr_rd_cb; | 
		
	
		
			
				|  |  |  |  |     std::unordered_map<unsigned, wr_csr_f> csr_wr_cb; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | private: | 
		
	
		
			
				|  |  |  |  |     iss::status read_reg(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_reg(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     std::vector<uint8_t> tcm; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     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); | 
		
	
		
			
				|  |  |  |  |     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); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -398,6 +402,8 @@ private: | 
		
	
		
			
				|  |  |  |  |     iss::status read_ie(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_ie(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     iss::status read_ip(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_ideleg(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_edeleg(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 read_satp(unsigned addr, reg_t &val); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -417,7 +423,6 @@ private: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     reg_t mhartid_reg{0x0}; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     void check_interrupt(); | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -434,22 +439,22 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | 
		
	
		
			
				|  |  |  |  |     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 = cycleh; 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, 22> addrs{{ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -459,25 +464,25 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | 
		
	
		
			
				|  |  |  |  |         uepc, utvec, uscratch, ucause, utval, uscratch | 
		
	
		
			
				|  |  |  |  |     }}; | 
		
	
		
			
				|  |  |  |  |     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; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[timeh] = &this_class::read_time; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32)  csr_rd_cb[timeh] = &this_class::read_time; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[cycle] = &this_class::read_cycle; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[cycleh] = &this_class::read_cycle; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32) csr_rd_cb[cycleh] = &this_class::read_cycle; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[instret] = &this_class::read_instret; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[instreth] = &this_class::read_instret; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32) csr_rd_cb[instreth] = &this_class::read_instret; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[mcycle] = &this_class::read_cycle; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[mcycle] = &this_class::write_cycle; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[mcycleh] = &this_class::read_cycle; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[mcycleh] = &this_class::write_cycle; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32) csr_rd_cb[mcycleh] = &this_class::read_cycle; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32) csr_wr_cb[mcycleh] = &this_class::write_cycle; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[minstret] = &this_class::read_instret; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[minstret] = &this_class::write_instret; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[minstreth] = &this_class::read_instret; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[minstreth] = &this_class::write_instret; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32) csr_rd_cb[minstreth] = &this_class::read_instret; | 
		
	
		
			
				|  |  |  |  |     if(traits<BASE>::XLEN==32) csr_wr_cb[minstreth] = &this_class::write_instret; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[mstatus] = &this_class::read_status; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[mstatus] = &this_class::write_status; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[mcause] = &this_class::write_cause; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -527,10 +532,10 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load | 
		
	
		
			
				|  |  |  |  |     if (fp) { | 
		
	
		
			
				|  |  |  |  |         std::array<char, 5> buf; | 
		
	
		
			
				|  |  |  |  |         auto n = fread(buf.data(), 1, 4, fp); | 
		
	
		
			
				|  |  |  |  |         fclose(fp); | 
		
	
		
			
				|  |  |  |  |         if (n != 4) throw std::runtime_error("input file has insufficient size"); | 
		
	
		
			
				|  |  |  |  |         buf[4] = 0; | 
		
	
		
			
				|  |  |  |  |         if (strcmp(buf.data() + 1, "ELF") == 0) { | 
		
	
		
			
				|  |  |  |  |             fclose(fp); | 
		
	
		
			
				|  |  |  |  |             // Create elfio reader | 
		
	
		
			
				|  |  |  |  |             ELFIO::elfio reader; | 
		
	
		
			
				|  |  |  |  |             // Load ELF data | 
		
	
	
		
			
				
					
					|  |  |  | @@ -549,7 +554,7 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load | 
		
	
		
			
				|  |  |  |  |                             traits<BASE>::MEM, pseg->get_physical_address(), | 
		
	
		
			
				|  |  |  |  |                             fsize, reinterpret_cast<const uint8_t *const>(seg_data)); | 
		
	
		
			
				|  |  |  |  |                     if (res != iss::Ok) | 
		
	
		
			
				|  |  |  |  |                         LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex | 
		
	
		
			
				|  |  |  |  |                         LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex | 
		
	
		
			
				|  |  |  |  |                                    << pseg->get_physical_address(); | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -673,7 +678,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_ | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         return iss::Ok; | 
		
	
		
			
				|  |  |  |  |     } catch (trap_access &ta) { | 
		
	
		
			
				|  |  |  |  |         this->reg.trap_state = (1 << 31) | ta.id; | 
		
	
		
			
				|  |  |  |  |         this->reg.trap_state = (1UL << 31) | ta.id; | 
		
	
		
			
				|  |  |  |  |         fault_data=ta.addr; | 
		
	
		
			
				|  |  |  |  |         return iss::Err; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -730,12 +735,12 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access | 
		
	
		
			
				|  |  |  |  |                         write_mem(phys_addr_t{access, space, addr}, length, data): | 
		
	
		
			
				|  |  |  |  |                         write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); | 
		
	
		
			
				|  |  |  |  |                 if (unlikely(res != iss::Ok)) { | 
		
	
		
			
				|  |  |  |  |                     this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) | 
		
	
		
			
				|  |  |  |  |                     this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault) | 
		
	
		
			
				|  |  |  |  |                     fault_data=addr; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 return res; | 
		
	
		
			
				|  |  |  |  |             } catch (trap_access &ta) { | 
		
	
		
			
				|  |  |  |  |                 this->reg.trap_state = (1 << 31) | ta.id; | 
		
	
		
			
				|  |  |  |  |                 this->reg.trap_state = (1UL << 31) | ta.id; | 
		
	
		
			
				|  |  |  |  |                 fault_data=ta.addr; | 
		
	
		
			
				|  |  |  |  |                 return iss::Err; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -800,7 +805,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         return iss::Ok; | 
		
	
		
			
				|  |  |  |  |     } catch (trap_access &ta) { | 
		
	
		
			
				|  |  |  |  |         this->reg.trap_state = (1 << 31) | ta.id; | 
		
	
		
			
				|  |  |  |  |         this->reg.trap_state = (1UL << 31) | ta.id; | 
		
	
		
			
				|  |  |  |  |         fault_data=ta.addr; | 
		
	
		
			
				|  |  |  |  |         return iss::Err; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -858,8 +863,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigne | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     if (sizeof(typename traits<BASE>::reg_t) != 4) { | 
		
	
		
			
				|  |  |  |  |         if (addr == mcycleh) | 
		
	
		
			
				|  |  |  |  |             return iss::Err; | 
		
	
		
			
				|  |  |  |  |         mcycle_csr = static_cast<uint64_t>(val); | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |         if (addr == mcycle) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -876,7 +879,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_instret(unsig | 
		
	
		
			
				|  |  |  |  |     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; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -884,8 +886,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_instret(unsig | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_msu_vp<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)) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1234,6 +1234,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f | 
		
	
		
			
				|  |  |  |  |     auto cur_priv = this->reg.PRIV; | 
		
	
		
			
				|  |  |  |  |     // 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 + cur_priv; // adjust environment call cause | 
		
	
	
		
			
				
					
					|  |  |  |   |