|  |  |  | @@ -146,7 +146,7 @@ public: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         mstatus_t mstatus; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         static const reg_t mstatus_reset_val = 0; | 
		
	
		
			
				|  |  |  |  |         static const reg_t mstatus_reset_val = 0x1800; // MPP set to 1 | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         void write_mstatus(T val, unsigned priv_lvl) { | 
		
	
		
			
				|  |  |  |  |             auto mask = get_mask(priv_lvl); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -543,25 +543,27 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_ | 
		
	
		
			
				|  |  |  |  |     constexpr auto PMP_NA4 =0x2U; | 
		
	
		
			
				|  |  |  |  |     constexpr auto PMP_NAPOT =0x3U; | 
		
	
		
			
				|  |  |  |  |     reg_t base = 0; | 
		
	
		
			
				|  |  |  |  |     auto any_active = false; | 
		
	
		
			
				|  |  |  |  |     for (size_t i = 0; i < 16; i++) { | 
		
	
		
			
				|  |  |  |  |         reg_t tor = csr[pmpaddr0+i] << PMP_SHIFT; | 
		
	
		
			
				|  |  |  |  |         uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4); | 
		
	
		
			
				|  |  |  |  |         if (cfg & PMP_A) { | 
		
	
		
			
				|  |  |  |  |             any_active=true; | 
		
	
		
			
				|  |  |  |  |             auto pmp_a = (cfg & PMP_A) >> 3; | 
		
	
		
			
				|  |  |  |  |             bool is_tor = pmp_a == PMP_TOR; | 
		
	
		
			
				|  |  |  |  |             bool is_na4 = pmp_a == PMP_NA4; | 
		
	
		
			
				|  |  |  |  |             auto is_tor = pmp_a == PMP_TOR; | 
		
	
		
			
				|  |  |  |  |             auto is_na4 = pmp_a == PMP_NA4; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |             reg_t mask = (csr[pmpaddr0+i] << 1) | (!is_na4); | 
		
	
		
			
				|  |  |  |  |             mask = ~(mask & ~(mask + 1)) << PMP_SHIFT; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |             // Check each 4-byte sector of the access | 
		
	
		
			
				|  |  |  |  |             bool any_match = false; | 
		
	
		
			
				|  |  |  |  |             bool all_match = true; | 
		
	
		
			
				|  |  |  |  |             auto any_match = false; | 
		
	
		
			
				|  |  |  |  |             auto all_match = true; | 
		
	
		
			
				|  |  |  |  |             for (reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) { | 
		
	
		
			
				|  |  |  |  |                 reg_t cur_addr = addr + offset; | 
		
	
		
			
				|  |  |  |  |                 bool napot_match = ((cur_addr ^ tor) & mask) == 0; | 
		
	
		
			
				|  |  |  |  |                 bool tor_match = base <= cur_addr && cur_addr < tor; | 
		
	
		
			
				|  |  |  |  |                 bool match = is_tor ? tor_match : napot_match; | 
		
	
		
			
				|  |  |  |  |                 auto napot_match = ((cur_addr ^ tor) & mask) == 0; | 
		
	
		
			
				|  |  |  |  |                 auto tor_match = base <= cur_addr && cur_addr < tor; | 
		
	
		
			
				|  |  |  |  |                 auto match = is_tor ? tor_match : napot_match; | 
		
	
		
			
				|  |  |  |  |                 any_match |= match; | 
		
	
		
			
				|  |  |  |  |                 all_match &= match; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -577,7 +579,7 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_ | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         base = tor; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return this->reg.PRIV == PRIV_M; | 
		
	
		
			
				|  |  |  |  |     return !any_active || this->reg.PRIV == PRIV_M; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -926,8 +928,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) { | 
		
	
		
			
				|  |  |  |  |     auto mask = get_irq_wrmask((addr >> 8) & 0x3); | 
		
	
		
			
				|  |  |  |  |     if(this->reg.PRIV==0) | 
		
	
		
			
				|  |  |  |  |         mask&= ~(0xff<<4); // STIE and UTIE are read only in user and supervisor mode | 
		
	
		
			
				|  |  |  |  |     csr[mie] = (csr[mie] & ~mask) | (val & mask); | 
		
	
		
			
				|  |  |  |  |     check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     return iss::Ok; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1256,27 +1256,33 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>:: | 
		
	
		
			
				|  |  |  |  | template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) { | 
		
	
		
			
				|  |  |  |  |     auto cur_priv = this->reg.PRIV; | 
		
	
		
			
				|  |  |  |  |     auto inst_priv = (flags & 0x3)? 3:0; | 
		
	
		
			
				|  |  |  |  |     auto status = state.mstatus; | 
		
	
		
			
				|  |  |  |  |     // pop the relevant lower-privilege interrupt enable and privilege mode stack | 
		
	
		
			
				|  |  |  |  |     // clear respective yIE | 
		
	
		
			
				|  |  |  |  |     switch (inst_priv) { | 
		
	
		
			
				|  |  |  |  |     case PRIV_M: | 
		
	
		
			
				|  |  |  |  |         this->reg.PRIV = state.mstatus.MPP; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPP = 0; // clear mpp to U mode | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MIE = state.mstatus.MPIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.MPIE = 1; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case PRIV_U: | 
		
	
		
			
				|  |  |  |  |         this->reg.PRIV = 0; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UIE = state.mstatus.UPIE; | 
		
	
		
			
				|  |  |  |  |         state.mstatus.UPIE = 1; | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     if(inst_priv>cur_priv){ | 
		
	
		
			
				|  |  |  |  |         auto trap_val =  0x80ULL << 24 | (2 << 16); // illegal instruction | 
		
	
		
			
				|  |  |  |  |         this->reg.trap_state = trap_val; | 
		
	
		
			
				|  |  |  |  |         this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max(); | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |         auto status = state.mstatus; | 
		
	
		
			
				|  |  |  |  |         // pop the relevant lower-privilege interrupt enable and privilege mode stack | 
		
	
		
			
				|  |  |  |  |         // clear respective yIE | 
		
	
		
			
				|  |  |  |  |         switch (inst_priv) { | 
		
	
		
			
				|  |  |  |  |         case PRIV_M: | 
		
	
		
			
				|  |  |  |  |             this->reg.PRIV = state.mstatus.MPP; | 
		
	
		
			
				|  |  |  |  |             state.mstatus.MPP = 0; // clear mpp to U mode | 
		
	
		
			
				|  |  |  |  |             state.mstatus.MIE = state.mstatus.MPIE; | 
		
	
		
			
				|  |  |  |  |             state.mstatus.MPIE = 1; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case PRIV_U: | 
		
	
		
			
				|  |  |  |  |             this->reg.PRIV = 0; | 
		
	
		
			
				|  |  |  |  |             state.mstatus.UIE = state.mstatus.UPIE; | 
		
	
		
			
				|  |  |  |  |             state.mstatus.UPIE = 1; | 
		
	
		
			
				|  |  |  |  |             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.PRIV]; | 
		
	
		
			
				|  |  |  |  |         check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     // 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.PRIV]; | 
		
	
		
			
				|  |  |  |  |     check_interrupt(); | 
		
	
		
			
				|  |  |  |  |     return this->reg.NEXT_PC; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  |   |