| 
							
							
							
						 |  |  | @@ -1,5 +1,5 @@ | 
		
	
		
			
				|  |  |  |  | /******************************************************************************* | 
		
	
		
			
				|  |  |  |  |  * Copyright (C) 2017, MINRES Technologies GmbH | 
		
	
		
			
				|  |  |  |  |  * Copyright (C) 2017, 2018, MINRES Technologies GmbH | 
		
	
		
			
				|  |  |  |  |  * All rights reserved. | 
		
	
		
			
				|  |  |  |  |  * | 
		
	
		
			
				|  |  |  |  |  * Redistribution and use in source and binary forms, with or without | 
		
	
	
		
			
				
					
					|  |  |  | @@ -37,21 +37,26 @@ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #include "iss/arch/traits.h" | 
		
	
		
			
				|  |  |  |  | #include "iss/arch_if.h" | 
		
	
		
			
				|  |  |  |  | #include "iss/instrumentation_if.h" | 
		
	
		
			
				|  |  |  |  | #include "iss/log_categories.h" | 
		
	
		
			
				|  |  |  |  | #include "iss/vm_if.h" | 
		
	
		
			
				|  |  |  |  | #include "iss/instrumentation_if.h" | 
		
	
		
			
				|  |  |  |  | #include <array> | 
		
	
		
			
				|  |  |  |  | #include <elfio/elfio.hpp> | 
		
	
		
			
				|  |  |  |  | #include <iomanip> | 
		
	
		
			
				|  |  |  |  | #include <sstream> | 
		
	
		
			
				|  |  |  |  | #include <type_traits> | 
		
	
		
			
				|  |  |  |  | #include <unordered_map> | 
		
	
		
			
				|  |  |  |  | #include <util/bit_field.h> | 
		
	
		
			
				|  |  |  |  | #include <util/ities.h> | 
		
	
		
			
				|  |  |  |  | #include <util/sparse_array.h> | 
		
	
		
			
				|  |  |  |  | #include <util/bit_field.h> | 
		
	
		
			
				|  |  |  |  | #include <array> | 
		
	
		
			
				|  |  |  |  | #include <type_traits> | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #define likely(x)       __builtin_expect(!!(x), 1) | 
		
	
		
			
				|  |  |  |  | #define unlikely(x)     __builtin_expect(!!(x), 0) | 
		
	
		
			
				|  |  |  |  | #if defined(__GNUC__) | 
		
	
		
			
				|  |  |  |  | #define likely(x) __builtin_expect(!!(x), 1) | 
		
	
		
			
				|  |  |  |  | #define unlikely(x) __builtin_expect(!!(x), 0) | 
		
	
		
			
				|  |  |  |  | #else | 
		
	
		
			
				|  |  |  |  | #define likely(x) x | 
		
	
		
			
				|  |  |  |  | #define unlikely(x) x | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | namespace iss { | 
		
	
		
			
				|  |  |  |  | namespace arch { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -165,29 +170,29 @@ enum riscv_csr { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | namespace { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | std::array<const char, 4> lvl = { { 'U', 'S', 'H', 'M' } }; | 
		
	
		
			
				|  |  |  |  | std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | std::array<const char*, 16> trap_str = { { "" | 
		
	
		
			
				|  |  |  |  | 		"Instruction address misaligned", //0 | 
		
	
		
			
				|  |  |  |  | 		"Instruction access fault", //1 | 
		
	
		
			
				|  |  |  |  | 		"Illegal instruction", //2 | 
		
	
		
			
				|  |  |  |  | 		"Breakpoint", //3 | 
		
	
		
			
				|  |  |  |  | 		"Load address misaligned", //4 | 
		
	
		
			
				|  |  |  |  | 		"Load access fault", //5 | 
		
	
		
			
				|  |  |  |  | 		"Store/AMO address misaligned", //6 | 
		
	
		
			
				|  |  |  |  | 		"Store/AMO access fault", //7 | 
		
	
		
			
				|  |  |  |  | 		"Environment call from U-mode", //8 | 
		
	
		
			
				|  |  |  |  | 		"Environment call from S-mode", //9 | 
		
	
		
			
				|  |  |  |  | 		"Reserved", //a | 
		
	
		
			
				|  |  |  |  | 		"Environment call from M-mode", //b | 
		
	
		
			
				|  |  |  |  | 		"Instruction page fault", //c | 
		
	
		
			
				|  |  |  |  | 		"Load page fault", //d | 
		
	
		
			
				|  |  |  |  | 		"Reserved", //e | 
		
	
		
			
				|  |  |  |  | 		"Store/AMO page fault" } }; | 
		
	
		
			
				|  |  |  |  | std::array<const char*, 12> irq_str = { { | 
		
	
		
			
				|  |  |  |  | 		"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", | 
		
	
		
			
				|  |  |  |  | 		"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", "User external interrupt", | 
		
	
		
			
				|  |  |  |  | 		"Supervisor external interrupt", "Reserved", "Machine external interrupt" } }; | 
		
	
		
			
				|  |  |  |  | std::array<const char *, 16> trap_str = {{"" | 
		
	
		
			
				|  |  |  |  |                                           "Instruction address misaligned", // 0 | 
		
	
		
			
				|  |  |  |  |                                           "Instruction access fault",       // 1 | 
		
	
		
			
				|  |  |  |  |                                           "Illegal instruction",            // 2 | 
		
	
		
			
				|  |  |  |  |                                           "Breakpoint",                     // 3 | 
		
	
		
			
				|  |  |  |  |                                           "Load address misaligned",        // 4 | 
		
	
		
			
				|  |  |  |  |                                           "Load access fault",              // 5 | 
		
	
		
			
				|  |  |  |  |                                           "Store/AMO address misaligned",   // 6 | 
		
	
		
			
				|  |  |  |  |                                           "Store/AMO access fault",         // 7 | 
		
	
		
			
				|  |  |  |  |                                           "Environment call from U-mode",   // 8 | 
		
	
		
			
				|  |  |  |  |                                           "Environment call from S-mode",   // 9 | 
		
	
		
			
				|  |  |  |  |                                           "Reserved",                       // a | 
		
	
		
			
				|  |  |  |  |                                           "Environment call from M-mode",   // b | 
		
	
		
			
				|  |  |  |  |                                           "Instruction page fault",         // c | 
		
	
		
			
				|  |  |  |  |                                           "Load page fault",                // d | 
		
	
		
			
				|  |  |  |  |                                           "Reserved",                       // e | 
		
	
		
			
				|  |  |  |  |                                           "Store/AMO page fault"}}; | 
		
	
		
			
				|  |  |  |  | std::array<const char *, 12> irq_str = { | 
		
	
		
			
				|  |  |  |  |     {"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", | 
		
	
		
			
				|  |  |  |  |      "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", | 
		
	
		
			
				|  |  |  |  |      "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | enum { | 
		
	
		
			
				|  |  |  |  |     PGSHIFT = 12, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -229,7 +234,7 @@ struct vm_info { | 
		
	
		
			
				|  |  |  |  |     int idxbits; | 
		
	
		
			
				|  |  |  |  |     int ptesize; | 
		
	
		
			
				|  |  |  |  |     uint64_t ptbase; | 
		
	
		
			
				|  |  |  |  |     bool is_active() { return levels;} | 
		
	
		
			
				|  |  |  |  |     bool is_active() { return levels; } | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | class trap_load_access_fault : public trap_access { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -272,10 +277,9 @@ public: | 
		
	
		
			
				|  |  |  |  |     using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     // primary template | 
		
	
		
			
				|  |  |  |  |     template<class T, class Enable = void> struct hart_state { }; | 
		
	
		
			
				|  |  |  |  |     template <class T, class Enable = void> struct hart_state {}; | 
		
	
		
			
				|  |  |  |  |     // specialization 32bit | 
		
	
		
			
				|  |  |  |  |     template <typename T> | 
		
	
		
			
				|  |  |  |  |     class hart_state<T, typename std::enable_if<std::is_same<T, uint32_t>::value>::type> { | 
		
	
		
			
				|  |  |  |  |     template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint32_t>::value>::type> { | 
		
	
		
			
				|  |  |  |  |     public: | 
		
	
		
			
				|  |  |  |  |         BEGIN_BF_DECL(mstatus_t, T); | 
		
	
		
			
				|  |  |  |  |         // SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR XS==11))) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -318,10 +322,10 @@ public: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         static const reg_t mstatus_reset_val = 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         void write_mstatus(T val, unsigned priv_lvl){ | 
		
	
		
			
				|  |  |  |  |         void write_mstatus(T val, unsigned priv_lvl) { | 
		
	
		
			
				|  |  |  |  |             auto mask = get_mask(priv_lvl); | 
		
	
		
			
				|  |  |  |  |             auto new_val = (mstatus.st.value & ~mask) | (val & mask); | 
		
	
		
			
				|  |  |  |  |             mstatus=new_val; | 
		
	
		
			
				|  |  |  |  |             mstatus = new_val; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         T satp; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -329,11 +333,15 @@ public: | 
		
	
		
			
				|  |  |  |  |         static constexpr T get_misa() { return (1UL << 30) | ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         static constexpr uint32_t get_mask(unsigned priv_lvl) { | 
		
	
		
			
				|  |  |  |  | #if __cplusplus < 201402L | 
		
	
		
			
				|  |  |  |  |             return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; | 
		
	
		
			
				|  |  |  |  | #else | 
		
	
		
			
				|  |  |  |  |             switch (priv_lvl) { | 
		
	
		
			
				|  |  |  |  |             case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 | 
		
	
		
			
				|  |  |  |  |             case PRIV_S: return 0x800de133UL; // 0b1000 0000 0000 1101 1110 0001 0011 0011 | 
		
	
		
			
				|  |  |  |  |             default:     return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         static inline vm_info decode_vm_info(uint32_t state, T sptbr) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -349,8 +357,7 @@ public: | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  |     // specialization 64bit | 
		
	
		
			
				|  |  |  |  |     template <typename T> | 
		
	
		
			
				|  |  |  |  |     class hart_state<T, typename std::enable_if<std::is_same<T, uint64_t>::value>::type> { | 
		
	
		
			
				|  |  |  |  |     template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint64_t>::value>::type> { | 
		
	
		
			
				|  |  |  |  |     public: | 
		
	
		
			
				|  |  |  |  |         BEGIN_BF_DECL(mstatus_t, T); | 
		
	
		
			
				|  |  |  |  |         // SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR XS==11))) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -397,17 +404,17 @@ public: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         static const reg_t mstatus_reset_val = 0xa00000000; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         void write_mstatus(T val, unsigned priv_lvl){ | 
		
	
		
			
				|  |  |  |  |         void write_mstatus(T val, unsigned priv_lvl) { | 
		
	
		
			
				|  |  |  |  |             T old_val = mstatus; | 
		
	
		
			
				|  |  |  |  |             auto mask = get_mask(priv_lvl); | 
		
	
		
			
				|  |  |  |  |             auto new_val = (old_val & ~mask) | (val & mask); | 
		
	
		
			
				|  |  |  |  |             if((new_val&mstatus.SXL.Mask)==0){ | 
		
	
		
			
				|  |  |  |  |                 new_val |= old_val&mstatus.SXL.Mask; | 
		
	
		
			
				|  |  |  |  |             if ((new_val & mstatus.SXL.Mask) == 0) { | 
		
	
		
			
				|  |  |  |  |                 new_val |= old_val & mstatus.SXL.Mask; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             if((new_val&mstatus.UXL.Mask)==0){ | 
		
	
		
			
				|  |  |  |  |                 new_val |= old_val&mstatus.UXL.Mask; | 
		
	
		
			
				|  |  |  |  |             if ((new_val & mstatus.UXL.Mask) == 0) { | 
		
	
		
			
				|  |  |  |  |                 new_val |= old_val & mstatus.UXL.Mask; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             mstatus=new_val; | 
		
	
		
			
				|  |  |  |  |             mstatus = new_val; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         T satp; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -426,9 +433,9 @@ public: | 
		
	
		
			
				|  |  |  |  |             if (state == PRIV_M) return {0, 0, 0, 0}; | 
		
	
		
			
				|  |  |  |  |             if (state <= PRIV_S) | 
		
	
		
			
				|  |  |  |  |                 switch (bit_sub<60, 4>(sptbr)) { | 
		
	
		
			
				|  |  |  |  |                 case 0: return {0, 0, 0, 0}; // off | 
		
	
		
			
				|  |  |  |  |                 case 8: return {3, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};// SV39 | 
		
	
		
			
				|  |  |  |  |                 case 9: return {4, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};// SV48 | 
		
	
		
			
				|  |  |  |  |                 case 0:  return {0, 0, 0, 0}; // off | 
		
	
		
			
				|  |  |  |  |                 case 8:  return {3, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};// SV39 | 
		
	
		
			
				|  |  |  |  |                 case 9:  return {4, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};// SV48 | 
		
	
		
			
				|  |  |  |  |                 case 10: return {5, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};// SV57 | 
		
	
		
			
				|  |  |  |  |                 case 11: return {6, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};// SV64 | 
		
	
		
			
				|  |  |  |  |                 default: abort(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -442,12 +449,12 @@ public: | 
		
	
		
			
				|  |  |  |  |     const typename super::reg_t PGMASK = PGSIZE - 1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     constexpr reg_t get_irq_mask(size_t mode) { | 
		
	
		
			
				|  |  |  |  | 			std::array<const reg_t,4> m = { { | 
		
	
		
			
				|  |  |  |  | 					0b000100010001,// U mode | 
		
	
		
			
				|  |  |  |  | 					0b001100110011,// S mode | 
		
	
		
			
				|  |  |  |  | 					0, | 
		
	
		
			
				|  |  |  |  | 					0b101110111011 // M mode | 
		
	
		
			
				|  |  |  |  | 					}}; | 
		
	
		
			
				|  |  |  |  |         std::array<const reg_t, 4> m = {{ | 
		
	
		
			
				|  |  |  |  |             0b000100010001, // U mode | 
		
	
		
			
				|  |  |  |  |             0b001100110011, // S mode | 
		
	
		
			
				|  |  |  |  |             0, | 
		
	
		
			
				|  |  |  |  |             0b101110111011 // M mode | 
		
	
		
			
				|  |  |  |  |         }}; | 
		
	
		
			
				|  |  |  |  |         return m[mode]; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -456,7 +463,7 @@ public: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     void reset(uint64_t address) override; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     std::pair<uint64_t,bool> load_file(std::string name, int type = -1) override; | 
		
	
		
			
				|  |  |  |  |     std::pair<uint64_t, bool> load_file(std::string name, int type = -1) override; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     virtual phys_addr_t virt2phys(const iss::addr_t &addr) override; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -468,40 +475,39 @@ public: | 
		
	
		
			
				|  |  |  |  |     virtual uint64_t leave_trap(uint64_t flags) override; | 
		
	
		
			
				|  |  |  |  |     void wait_until(uint64_t flags) override; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     void disass_output(uint64_t pc, const std::string instr) override { | 
		
	
		
			
				|  |  |  |  |         std::stringstream s; | 
		
	
		
			
				|  |  |  |  |         s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0') | 
		
	
		
			
				|  |  |  |  |           << std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]"; | 
		
	
		
			
				|  |  |  |  |         CLOG(INFO, disass) << "0x"<<std::setw(16)<<std::setfill('0')<<std::hex<<pc<<"\t\t"<<instr<<"\t"<<s.str(); | 
		
	
		
			
				|  |  |  |  |         CLOG(INFO, disass) << "0x" << std::setw(16) << std::setfill('0') << std::hex << pc << "\t\t" << instr << "\t" << s.str(); | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     iss::instrumentation_if* get_instrumentation_if() override {return &instr_if;} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } | 
		
	
		
			
				|  |  |  |  |   | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     struct riscv_instrumentation_if : public iss::instrumentation_if{ | 
		
	
		
			
				|  |  |  |  |     struct riscv_instrumentation_if : public iss::instrumentation_if { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     	riscv_instrumentation_if(riscv_hart_msu_vp<BASE>& arch):arch(arch){} | 
		
	
		
			
				|  |  |  |  |         riscv_instrumentation_if(riscv_hart_msu_vp<BASE> &arch) | 
		
	
		
			
				|  |  |  |  |         : arch(arch) {} | 
		
	
		
			
				|  |  |  |  |         /** | 
		
	
		
			
				|  |  |  |  |          * get the name of this architecture | 
		
	
		
			
				|  |  |  |  |          * | 
		
	
		
			
				|  |  |  |  |          * @return the name of this architecture | 
		
	
		
			
				|  |  |  |  |          */ | 
		
	
		
			
				|  |  |  |  |     	const std::string core_type_name() const override {return traits<BASE>::core_type;} | 
		
	
		
			
				|  |  |  |  |         const std::string core_type_name() const override { return traits<BASE>::core_type; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         virtual uint64_t get_pc(){ return arch.get_pc(); }; | 
		
	
		
			
				|  |  |  |  |         virtual uint64_t get_pc() { return arch.get_pc(); }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     	virtual uint64_t get_next_pc(){ return arch.get_next_pc(); }; | 
		
	
		
			
				|  |  |  |  |         virtual uint64_t get_next_pc() { return arch.get_next_pc(); }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     	virtual void set_curr_instr_cycles(unsigned cycles){ arch.cycle_offset+=cycles-1; }; | 
		
	
		
			
				|  |  |  |  |         virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     	riscv_hart_msu_vp<BASE>& arch; | 
		
	
		
			
				|  |  |  |  |         riscv_hart_msu_vp<BASE> &arch; | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     friend struct riscv_instrumentation_if; | 
		
	
		
			
				|  |  |  |  |     addr_t get_pc(){return this->reg.PC;} | 
		
	
		
			
				|  |  |  |  |     addr_t get_next_pc(){return this->reg.NEXT_PC;} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     addr_t get_pc() { return this->reg.PC; } | 
		
	
		
			
				|  |  |  |  |     addr_t get_next_pc() { return this->reg.NEXT_PC; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     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); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -512,7 +518,7 @@ protected: | 
		
	
		
			
				|  |  |  |  |     hart_state<reg_t> state; | 
		
	
		
			
				|  |  |  |  |     uint64_t cycle_offset; | 
		
	
		
			
				|  |  |  |  |     reg_t fault_data; | 
		
	
		
			
				|  |  |  |  |     std::array<vm_info,2> vm; | 
		
	
		
			
				|  |  |  |  |     std::array<vm_info, 2> vm; | 
		
	
		
			
				|  |  |  |  |     uint64_t tohost = tohost_dflt; | 
		
	
		
			
				|  |  |  |  |     uint64_t fromhost = fromhost_dflt; | 
		
	
		
			
				|  |  |  |  |     unsigned to_host_wr_cnt = 0; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -541,15 +547,18 @@ private: | 
		
	
		
			
				|  |  |  |  |     iss::status write_ip(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     iss::status read_satp(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_satp(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |     iss::status read_fcsr(unsigned addr, reg_t& val); | 
		
	
		
			
				|  |  |  |  |     iss::status read_fcsr(unsigned addr, reg_t &val); | 
		
	
		
			
				|  |  |  |  |     iss::status write_fcsr(unsigned addr, reg_t val); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  |     void check_interrupt(); | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> | 
		
	
		
			
				|  |  |  |  | riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | 
		
	
		
			
				|  |  |  |  | : state(), cycle_offset(0), instr_if(*this) { | 
		
	
		
			
				|  |  |  |  | : state() | 
		
	
		
			
				|  |  |  |  | , cycle_offset(0) | 
		
	
		
			
				|  |  |  |  | , instr_if(*this) { | 
		
	
		
			
				|  |  |  |  |     csr[misa] = hart_state<reg_t>::get_misa(); | 
		
	
		
			
				|  |  |  |  |     uart_buf.str(""); | 
		
	
		
			
				|  |  |  |  |     // read-only registers | 
		
	
	
		
			
				
					
					|  |  |  | @@ -591,27 +600,26 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp() | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[fflags] = &riscv_hart_msu_vp<BASE>::write_fcsr; | 
		
	
		
			
				|  |  |  |  |     csr_rd_cb[frm] = &riscv_hart_msu_vp<BASE>::read_fcsr; | 
		
	
		
			
				|  |  |  |  |     csr_wr_cb[frm] = &riscv_hart_msu_vp<BASE>::write_fcsr; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> std::pair<uint64_t,bool> riscv_hart_msu_vp<BASE>::load_file(std::string name, int type) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load_file(std::string name, int type) { | 
		
	
		
			
				|  |  |  |  |     FILE *fp = fopen(name.c_str(), "r"); | 
		
	
		
			
				|  |  |  |  |     if (fp) { | 
		
	
		
			
				|  |  |  |  | 		std::array<char, 5> buf; | 
		
	
		
			
				|  |  |  |  | 		auto n = fread(buf.data(), 1, 4, fp); | 
		
	
		
			
				|  |  |  |  |         std::array<char, 5> buf; | 
		
	
		
			
				|  |  |  |  |         auto n = fread(buf.data(), 1, 4, fp); | 
		
	
		
			
				|  |  |  |  |         if (n != 4) throw std::runtime_error("input file has insufficient size"); | 
		
	
		
			
				|  |  |  |  |         buf[4] = 0; | 
		
	
		
			
				|  |  |  |  | 		if (strcmp(buf.data() + 1, "ELF") == 0) { | 
		
	
		
			
				|  |  |  |  |         if (strcmp(buf.data() + 1, "ELF") == 0) { | 
		
	
		
			
				|  |  |  |  |             fclose(fp); | 
		
	
		
			
				|  |  |  |  |             // Create elfio reader | 
		
	
		
			
				|  |  |  |  |             ELFIO::elfio reader; | 
		
	
		
			
				|  |  |  |  |             // Load ELF data | 
		
	
		
			
				|  |  |  |  |             if (!reader.load(name)) throw std::runtime_error("could not process elf file"); | 
		
	
		
			
				|  |  |  |  |             // check elf properties | 
		
	
		
			
				|  |  |  |  |             if ( reader.get_class() != ELFCLASS32 ) | 
		
	
		
			
				|  |  |  |  |                 if(sizeof(reg_t) == 4) throw std::runtime_error("wrong elf class in file"); | 
		
	
		
			
				|  |  |  |  |             if (reader.get_class() != ELFCLASS32) | 
		
	
		
			
				|  |  |  |  |                 if (sizeof(reg_t) == 4) throw std::runtime_error("wrong elf class in file"); | 
		
	
		
			
				|  |  |  |  |             if (reader.get_type() != ET_EXEC) throw std::runtime_error("wrong elf type in file"); | 
		
	
		
			
				|  |  |  |  |             if ( reader.get_machine() != EM_RISCV ) throw std::runtime_error("wrong elf machine in file"); | 
		
	
		
			
				|  |  |  |  |             if (reader.get_machine() != EM_RISCV) throw std::runtime_error("wrong elf machine in file"); | 
		
	
		
			
				|  |  |  |  |             for (const auto pseg : reader.segments) { | 
		
	
		
			
				|  |  |  |  |                 const auto fsize = pseg->get_file_size(); // 0x42c/0x0 | 
		
	
		
			
				|  |  |  |  |                 const auto seg_data = pseg->get_data(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -642,9 +650,9 @@ template <typename BASE> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned length, uint8_t *const data) { | 
		
	
		
			
				|  |  |  |  | #ifndef NDEBUG | 
		
	
		
			
				|  |  |  |  |     if (addr.access && iss::access_type::DEBUG) { | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << "debug read of " << length << " bytes @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << "debug read of " << length << " bytes @addr " << addr; | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << "read of " << length << " bytes  @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << "read of " << length << " bytes  @addr " << addr; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -716,26 +724,26 @@ iss::status riscv_hart_msu_vp<BASE>::read(const iss::addr_t &addr, unsigned leng | 
		
	
		
			
				|  |  |  |  | template <typename BASE> | 
		
	
		
			
				|  |  |  |  | iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned length, const uint8_t *const data) { | 
		
	
		
			
				|  |  |  |  | #ifndef NDEBUG | 
		
	
		
			
				|  |  |  |  |     const char *prefix = (addr.access && iss::access_type::DEBUG)? "debug " : ""; | 
		
	
		
			
				|  |  |  |  |     const char *prefix = (addr.access && iss::access_type::DEBUG) ? "debug " : ""; | 
		
	
		
			
				|  |  |  |  |     switch (length) { | 
		
	
		
			
				|  |  |  |  |     case 8: | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |                    << ") @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 4: | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t *)&data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t *)&data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |                    << ") @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 2: | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t *)&data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t *)&data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |                    << ") @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 1: | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec | 
		
	
		
			
				|  |  |  |  |                    << ") @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     default: | 
		
	
		
			
				|  |  |  |  |         LOG(DEBUG) << prefix << "write of " << length << " bytes @addr " << addr; | 
		
	
		
			
				|  |  |  |  |         LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -760,7 +768,8 @@ iss::status riscv_hart_msu_vp<BASE>::write(const iss::addr_t &addr, unsigned len | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 auto res = write_mem(BASE::v2p(addr), length, data); | 
		
	
		
			
				|  |  |  |  |                 if (unlikely(res != iss::Ok)) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault) | 
		
	
		
			
				|  |  |  |  |                 if (unlikely(res != iss::Ok)) | 
		
	
		
			
				|  |  |  |  |                     this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault) | 
		
	
		
			
				|  |  |  |  |                 return res; | 
		
	
		
			
				|  |  |  |  |             } catch (trap_access &ta) { | 
		
	
		
			
				|  |  |  |  |                 this->reg.trap_state = (1 << 31) | ta.id; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -857,7 +866,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_csr(unsigned | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     auto cycle_val= this->reg.icount + cycle_offset; | 
		
	
		
			
				|  |  |  |  |     auto cycle_val = this->reg.icount + cycle_offset; | 
		
	
		
			
				|  |  |  |  |     if (addr == mcycle) { | 
		
	
		
			
				|  |  |  |  |         val = static_cast<reg_t>(cycle_val); | 
		
	
		
			
				|  |  |  |  |     } else if (addr == mcycleh) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -868,7 +877,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigne | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  | 	uint64_t time_val=(this->reg.icount + cycle_offset) / (100000000/32768-1); //-> ~3052; | 
		
	
		
			
				|  |  |  |  |     uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; | 
		
	
		
			
				|  |  |  |  |     if (addr == time) { | 
		
	
		
			
				|  |  |  |  |         val = static_cast<reg_t>(time_val); | 
		
	
		
			
				|  |  |  |  |     } else if (addr == timeh) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -925,7 +934,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_ip(unsigned | 
		
	
		
			
				|  |  |  |  |     auto req_priv_lvl = addr >> 8; | 
		
	
		
			
				|  |  |  |  |     if (this->reg.machine_state < req_priv_lvl) throw illegal_instruction_fault(this->fault_data); | 
		
	
		
			
				|  |  |  |  |     auto mask = get_irq_mask(req_priv_lvl); | 
		
	
		
			
				|  |  |  |  |     mask &= ~(1<<7); // MTIP is read only | 
		
	
		
			
				|  |  |  |  |     mask &= ~(1 << 7); // MTIP is read only | 
		
	
		
			
				|  |  |  |  |     csr[mip] = (csr[mip] & ~mask) | (val & mask); | 
		
	
		
			
				|  |  |  |  |     check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -953,16 +962,16 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigne | 
		
	
		
			
				|  |  |  |  |     update_vm_info(); | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | template<typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_fcsr(unsigned addr, reg_t& val) { | 
		
	
		
			
				|  |  |  |  |     switch(addr){ | 
		
	
		
			
				|  |  |  |  |     case 1: //fflags, 4:0 | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_fcsr(unsigned addr, reg_t &val) { | 
		
	
		
			
				|  |  |  |  |     switch (addr) { | 
		
	
		
			
				|  |  |  |  |     case 1: // fflags, 4:0 | 
		
	
		
			
				|  |  |  |  |         val = bit_sub<0, 5>(this->get_fcsr()); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 2: // frm, 7:5 | 
		
	
		
			
				|  |  |  |  |         val = bit_sub<5, 3>(this->get_fcsr()); | 
		
	
		
			
				|  |  |  |  |        break; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 3: // fcsr | 
		
	
		
			
				|  |  |  |  |         val=this->get_fcsr(); | 
		
	
		
			
				|  |  |  |  |         val = this->get_fcsr(); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     default: | 
		
	
		
			
				|  |  |  |  |         return iss::Err; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -970,16 +979,16 @@ template<typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_fcsr(unsigned | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template<typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_fcsr(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     switch(addr){ | 
		
	
		
			
				|  |  |  |  |     case 1: //fflags, 4:0 | 
		
	
		
			
				|  |  |  |  |         this->set_fcsr( (this->get_fcsr() & 0xffffffe0) | (val&0x1f)); | 
		
	
		
			
				|  |  |  |  | template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_fcsr(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     switch (addr) { | 
		
	
		
			
				|  |  |  |  |     case 1: // fflags, 4:0 | 
		
	
		
			
				|  |  |  |  |         this->set_fcsr((this->get_fcsr() & 0xffffffe0) | (val & 0x1f)); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 2: // frm, 7:5 | 
		
	
		
			
				|  |  |  |  |         this->set_fcsr( (this->get_fcsr() & 0xffffff1f) | ((val&0x7)<<5)); | 
		
	
		
			
				|  |  |  |  |        break; | 
		
	
		
			
				|  |  |  |  |         this->set_fcsr((this->get_fcsr() & 0xffffff1f) | ((val & 0x7) << 5)); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 3: // fcsr | 
		
	
		
			
				|  |  |  |  |         this->set_fcsr(val&0xff); | 
		
	
		
			
				|  |  |  |  |         this->set_fcsr(val & 0xff); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     default: | 
		
	
		
			
				|  |  |  |  |         return iss::Err; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -992,7 +1001,7 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length | 
		
	
		
			
				|  |  |  |  |     if ((paddr.val + length) > mem.size()) return iss::Err; | 
		
	
		
			
				|  |  |  |  |     switch (paddr.val) { | 
		
	
		
			
				|  |  |  |  |     case 0x0200BFF8: { // CLINT base, mtime reg | 
		
	
		
			
				|  |  |  |  |         if(sizeof(reg_t)<length) return iss::Err; | 
		
	
		
			
				|  |  |  |  |         if (sizeof(reg_t) < length) return iss::Err; | 
		
	
		
			
				|  |  |  |  |         reg_t time_val; | 
		
	
		
			
				|  |  |  |  |         this->read_csr(time, time_val); | 
		
	
		
			
				|  |  |  |  |         std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1054,10 +1063,10 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt | 
		
	
		
			
				|  |  |  |  |                 if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) { | 
		
	
		
			
				|  |  |  |  |                     switch (hostvar >> 48) { | 
		
	
		
			
				|  |  |  |  |                     case 0: | 
		
	
		
			
				|  |  |  |  |                         if (hostvar != 0x1){ | 
		
	
		
			
				|  |  |  |  |                         if (hostvar != 0x1) { | 
		
	
		
			
				|  |  |  |  |                             LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar | 
		
	
		
			
				|  |  |  |  |                                        << "), stopping simulation"; | 
		
	
		
			
				|  |  |  |  |                         }else{ | 
		
	
		
			
				|  |  |  |  |                         } else { | 
		
	
		
			
				|  |  |  |  |                             LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar | 
		
	
		
			
				|  |  |  |  |                                       << "), stopping simulation"; | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1087,22 +1096,20 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template<typename BASE> | 
		
	
		
			
				|  |  |  |  | inline void riscv_hart_msu_vp<BASE>::reset(uint64_t address) { | 
		
	
		
			
				|  |  |  |  | template <typename BASE> inline void riscv_hart_msu_vp<BASE>::reset(uint64_t address) { | 
		
	
		
			
				|  |  |  |  |     BASE::reset(address); | 
		
	
		
			
				|  |  |  |  |     state.mstatus = hart_state<reg_t>::mstatus_reset_val; | 
		
	
		
			
				|  |  |  |  |     update_vm_info(); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template<typename BASE> | 
		
	
		
			
				|  |  |  |  | inline void riscv_hart_msu_vp<BASE>::update_vm_info() { | 
		
	
		
			
				|  |  |  |  | template <typename BASE> inline void riscv_hart_msu_vp<BASE>::update_vm_info() { | 
		
	
		
			
				|  |  |  |  |     vm[1] = hart_state<reg_t>::decode_vm_info(this->reg.machine_state, state.satp); | 
		
	
		
			
				|  |  |  |  |     BASE::addr_mode[3]=BASE::addr_mode[2]=vm[1].is_active()?iss::address_type::VIRTUAL:iss::address_type::PHYSICAL; | 
		
	
		
			
				|  |  |  |  |     if(state.mstatus.MPRV) | 
		
	
		
			
				|  |  |  |  |     BASE::addr_mode[3]=BASE::addr_mode[2] = vm[1].is_active()? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; | 
		
	
		
			
				|  |  |  |  |     if (state.mstatus.MPRV) | 
		
	
		
			
				|  |  |  |  |         vm[0] = hart_state<reg_t>::decode_vm_info(state.mstatus.MPP, state.satp); | 
		
	
		
			
				|  |  |  |  |     else | 
		
	
		
			
				|  |  |  |  |         vm[0] = vm[1]; | 
		
	
		
			
				|  |  |  |  |     BASE::addr_mode[1]=BASE::addr_mode[0]=vm[0].is_active()?iss::address_type::VIRTUAL:iss::address_type::PHYSICAL; | 
		
	
		
			
				|  |  |  |  |     BASE::addr_mode[1] = BASE::addr_mode[0]=vm[0].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; | 
		
	
		
			
				|  |  |  |  |     ptw.clear(); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1117,7 +1124,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() { | 
		
	
		
			
				|  |  |  |  |     // any synchronous traps. | 
		
	
		
			
				|  |  |  |  |     auto ena_irq = ip & ie; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     auto mie = state.mstatus.MIE; | 
		
	
		
			
				|  |  |  |  |     bool mie = state.mstatus.MIE; | 
		
	
		
			
				|  |  |  |  |     auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie); | 
		
	
		
			
				|  |  |  |  |     auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1153,10 +1160,10 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::virt2phys | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |         uint32_t mode = type != iss::access_type::FETCH && state.mstatus.MPRV ? // MPRV | 
		
	
		
			
				|  |  |  |  |                             state.mstatus.MPP: | 
		
	
		
			
				|  |  |  |  |                             state.mstatus.MPP : | 
		
	
		
			
				|  |  |  |  |                             this->reg.machine_state; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         const vm_info& vm = this->vm[static_cast<uint16_t>(type)/2]; | 
		
	
		
			
				|  |  |  |  |         const vm_info &vm = this->vm[static_cast<uint16_t>(type) / 2]; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         const bool s_mode = mode == PRIV_S; | 
		
	
		
			
				|  |  |  |  |         const bool sum = state.mstatus.SUM; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1175,8 +1182,8 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::virt2phys | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |             // check that physical address of PTE is legal | 
		
	
		
			
				|  |  |  |  |             reg_t pte = 0; | 
		
	
		
			
				|  |  |  |  |             const uint8_t res = | 
		
	
		
			
				|  |  |  |  |                 this->read(phys_addr_t{addr.access, traits<BASE>::MEM, base + idx * vm.ptesize}, vm.ptesize, (uint8_t *)&pte); | 
		
	
		
			
				|  |  |  |  |             const uint8_t res = this->read(phys_addr_t{addr.access, traits<BASE>::MEM, base + idx * vm.ptesize}, | 
		
	
		
			
				|  |  |  |  |                                            vm.ptesize, (uint8_t *)&pte); | 
		
	
		
			
				|  |  |  |  |             if (res != 0) throw trap_load_access_fault(addr.val); | 
		
	
		
			
				|  |  |  |  |             const reg_t ppn = pte >> PTE_PPN_SHIFT; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1186,9 +1193,10 @@ typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_hart_msu_vp<BASE>::virt2phys | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |             } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |             } else if (type == iss::access_type::FETCH ? !(pte & PTE_X) | 
		
	
		
			
				|  |  |  |  |                                           : type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) | 
		
	
		
			
				|  |  |  |  |                                                               : !((pte & PTE_R) && (pte & PTE_W))) { | 
		
	
		
			
				|  |  |  |  |             } else if (type == iss::access_type::FETCH | 
		
	
		
			
				|  |  |  |  |                            ? !(pte & PTE_X) | 
		
	
		
			
				|  |  |  |  |                            : type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) | 
		
	
		
			
				|  |  |  |  |                                                             : !((pte & PTE_R) && (pte & PTE_W))) { | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |             } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1254,8 +1262,8 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f | 
		
	
		
			
				|  |  |  |  |         csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt | 
		
	
		
			
				|  |  |  |  |         this->reg.pending_trap = 0; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     size_t adr=ucause | (new_priv << 8); | 
		
	
		
			
				|  |  |  |  |     csr[adr] = (trap_id<<31)+cause; | 
		
	
		
			
				|  |  |  |  |     size_t adr = ucause | (new_priv << 8); | 
		
	
		
			
				|  |  |  |  |     csr[adr] = (trap_id << 31) + cause; | 
		
	
		
			
				|  |  |  |  |     // update mstatus | 
		
	
		
			
				|  |  |  |  |     // xPP field of mstatus is written with the active privilege mode at the time | 
		
	
		
			
				|  |  |  |  |     // of the trap; the x PIE field of mstatus | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1265,15 +1273,18 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f | 
		
	
		
			
				|  |  |  |  |     // store the actual privilege level in yPP and store interrupt enable flags | 
		
	
		
			
				|  |  |  |  |     switch (new_priv) { | 
		
	
		
			
				|  |  |  |  |     case PRIV_M: | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPP=cur_priv; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPIE=state.mstatus.MIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPP = cur_priv; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPIE = state.mstatus.MIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MIE = false; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case PRIV_S: | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SPP = cur_priv; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SPIE=state.mstatus.SIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SPIE = state.mstatus.SIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SIE = false; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case PRIV_U: | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UPIE=state.mstatus.UIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UPIE = state.mstatus.UIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UIE = false; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     default: | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1288,11 +1299,12 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f | 
		
	
		
			
				|  |  |  |  |     // reset trap state | 
		
	
		
			
				|  |  |  |  |     this->reg.machine_state = new_priv; | 
		
	
		
			
				|  |  |  |  |     this->reg.trap_state = 0; | 
		
	
		
			
				|  |  |  |  | 	std::array<char, 32> buffer; | 
		
	
		
			
				|  |  |  |  | 	sprintf(buffer.data(), "0x%016lx", addr); | 
		
	
		
			
				|  |  |  |  |     CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause])<<"' ("<<trap_id<<")" | 
		
	
		
			
				|  |  |  |  |                        << " at address " << buffer.data() << " occurred, changing privilege level from " << lvl[cur_priv] | 
		
	
		
			
				|  |  |  |  |                        << " to " << lvl[new_priv]; | 
		
	
		
			
				|  |  |  |  |     std::array<char, 32> buffer; | 
		
	
		
			
				|  |  |  |  |     sprintf(buffer.data(), "0x%016lx", addr); | 
		
	
		
			
				|  |  |  |  |     CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" | 
		
	
		
			
				|  |  |  |  |                        << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << trap_id << ")" | 
		
	
		
			
				|  |  |  |  |                        << " at address " << buffer.data() << " occurred, changing privilege level from " | 
		
	
		
			
				|  |  |  |  |                        << lvl[cur_priv] << " to " << lvl[new_priv]; | 
		
	
		
			
				|  |  |  |  |     update_vm_info(); | 
		
	
		
			
				|  |  |  |  |     return this->reg.NEXT_PC; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1314,22 +1326,23 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::leave_trap(uint64_t f | 
		
	
		
			
				|  |  |  |  |     switch (inst_priv) { | 
		
	
		
			
				|  |  |  |  |     case PRIV_M: | 
		
	
		
			
				|  |  |  |  |         this->reg.machine_state = state.mstatus.MPP; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPP=0; // clear mpp to U mode | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MIE=state.mstatus.MPIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPP = 0; // clear mpp to U mode | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MIE = state.mstatus.MPIE; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case PRIV_S: | 
		
	
		
			
				|  |  |  |  |         this->reg.machine_state = state.mstatus.SPP; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SPP= 0; // clear spp to U mode | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SIE=state.mstatus.SPIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SPP = 0; // clear spp to U mode | 
		
	
		
			
				|  |  |  |  |         state.mstatus.SIE = state.mstatus.SPIE; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case PRIV_U: | 
		
	
		
			
				|  |  |  |  |         this->reg.machine_state = 0; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UIE=state.mstatus.UPIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UIE = state.mstatus.UPIE; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     // sets the pc to the value stored in the x epc register. | 
		
	
		
			
				|  |  |  |  |     this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; | 
		
	
		
			
				|  |  |  |  |     CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " << lvl[this->reg.machine_state]; | 
		
	
		
			
				|  |  |  |  |     CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " | 
		
	
		
			
				|  |  |  |  |                        << lvl[this->reg.machine_state]; | 
		
	
		
			
				|  |  |  |  |     update_vm_info(); | 
		
	
		
			
				|  |  |  |  |     return this->reg.NEXT_PC; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1345,5 +1358,4 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::wait_until(uint64_t flags | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #endif /* _RISCV_CORE_H_ */ | 
		
	
	
		
			
				
					
					| 
							
							
							
						 |  |  |   |