|  |  | @@ -95,6 +95,7 @@ protected: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     inline const char *name(size_t index){return traits::reg_aliases.at(index);} |  |  |  |     inline const char *name(size_t index){return traits::reg_aliases.at(index);} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     typename arch::traits<ARCH>::opcode_e decode_inst_id(code_word_t instr); | 
			
		
	
		
		
			
				
					
					|  |  |  |     virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override; |  |  |  |     virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     // some compile time constants |  |  |  |     // some compile time constants | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -111,7 +112,13 @@ protected: | 
			
		
	
		
		
			
				
					
					|  |  |  |     std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10; |  |  |  |     std::array<compile_func, LUT_SIZE_C> lut_00, lut_01, lut_10; | 
			
		
	
		
		
			
				
					
					|  |  |  |     std::array<compile_func, LUT_SIZE> lut_11; |  |  |  |     std::array<compile_func, LUT_SIZE> lut_11; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     std::unique_ptr<instruction_decoder<ARCH>> decoder; |  |  |  |     struct instruction_pattern { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         uint32_t value; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         uint32_t mask; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         typename arch::traits<ARCH>::opcode_e id; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     std::array<std::vector<instruction_pattern>, 4> qlut; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     inline void raise(uint16_t trap_id, uint16_t cause){ |  |  |  |     inline void raise(uint16_t trap_id, uint16_t cause){ | 
			
		
	
		
		
			
				
					
					|  |  |  |         auto trap_val =  0x80ULL << 24 | (cause << 16) | trap_id; |  |  |  |         auto trap_val =  0x80ULL << 24 | (cause << 16) | trap_id; | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -133,7 +140,42 @@ protected: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     template<typename T> |  |  |  |     template<typename T> | 
			
		
	
		
		
			
				
					
					|  |  |  |     T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;} |  |  |  |     T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         auto ret = super::template read_mem<uint8_t>(space, addr); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return ret; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline uint16_t readSpace2(typename super::mem_type_e space, uint64_t addr){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         auto ret = super::template read_mem<uint16_t>(space, addr); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return ret; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline uint32_t readSpace4(typename super::mem_type_e space, uint64_t addr){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         auto ret = super::template read_mem<uint32_t>(space, addr); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return ret; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline uint64_t readSpace8(typename super::mem_type_e space, uint64_t addr){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         auto ret = super::template read_mem<uint64_t>(space, addr); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return ret; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline void writeSpace1(typename super::mem_type_e space, uint64_t addr, uint8_t data){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         super::write_mem(space, addr, data); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline void writeSpace2(typename super::mem_type_e space, uint64_t addr, uint16_t data){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         super::write_mem(space, addr, data); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline void writeSpace4(typename super::mem_type_e space, uint64_t addr, uint32_t data){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         super::write_mem(space, addr, data); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     inline void writeSpace8(typename super::mem_type_e space, uint64_t addr, uint64_t data){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         super::write_mem(space, addr, data); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(this->core.trap_state) throw 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     template<unsigned W, typename U, typename S = typename std::make_signed<U>::type> |  |  |  |     template<unsigned W, typename U, typename S = typename std::make_signed<U>::type> | 
			
		
	
		
		
			
				
					
					|  |  |  |     inline S sext(U from) { |  |  |  |     inline S sext(U from) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         auto mask = (1ULL<<W) - 1; |  |  |  |         auto mask = (1ULL<<W) - 1; | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -153,6 +195,20 @@ protected: | 
			
		
	
		
		
			
				
					
					|  |  |  |     ${it}<%}%> |  |  |  |     ${it}<%}%> | 
			
		
	
		
		
			
				
					
					|  |  |  | <%}%> |  |  |  | <%}%> | 
			
		
	
		
		
			
				
					
					|  |  |  | private: |  |  |  | private: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     /**************************************************************************** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      * start opcode definitions | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |      ****************************************************************************/ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     struct InstructionDesriptor { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         size_t length; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         uint32_t value; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         uint32_t mask; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         typename arch::traits<ARCH>::opcode_e op; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         {${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     }}; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; |  |  |  |     //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; | 
			
		
	
		
		
			
				
					
					|  |  |  |     iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ |  |  |  |     iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -192,7 +248,16 @@ constexpr size_t bit_count(uint32_t u) { | 
			
		
	
		
		
			
				
					
					|  |  |  | template <typename ARCH> |  |  |  | template <typename ARCH> | 
			
		
	
		
		
			
				
					
					|  |  |  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) |  |  |  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | 
			
		
	
		
		
			
				
					
					|  |  |  | : vm_base<ARCH>(core, core_id, cluster_id) { |  |  |  | : vm_base<ARCH>(core, core_id, cluster_id) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     decoder = traits::get_decoder(); |  |  |  |     unsigned id=0; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for (auto instr : instr_descr) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         auto quadrant = instr.value & 0x3; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op}); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for(auto& lut: qlut){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return bit_count(a.mask) > bit_count(b.mask); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | inline bool is_count_limit_enabled(finish_cond_e cond){ |  |  |  | inline bool is_count_limit_enabled(finish_cond_e cond){ | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -203,11 +268,19 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){ | 
			
		
	
		
		
			
				
					
					|  |  |  |     return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; |  |  |  |     return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | template <typename ARCH> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for(auto& e: qlut[instr&0x3]){ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if(!((instr&e.mask) ^ e.value )) return e.id; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return arch::traits<ARCH>::opcode_e::MAX_OPCODE; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | template <typename ARCH> |  |  |  | template <typename ARCH> | 
			
		
	
		
		
			
				
					
					|  |  |  | typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ |  |  |  | typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto pc=start; |  |  |  |     auto pc=start; | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+traits::reg_byte_offsets[traits::PC]); |  |  |  |     auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+traits::reg_byte_offsets[traits::NEXT_PC]); |  |  |  |     auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     auto& trap_state = this->core.trap_state; |  |  |  |     auto& trap_state = this->core.trap_state; | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto& icount = this->core.icount; |  |  |  |     auto& icount = this->core.icount; | 
			
		
	
		
		
			
				
					
					|  |  |  |     auto& cycle = this->core.cycle; |  |  |  |     auto& cycle = this->core.cycle; | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -224,11 +297,11 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | 
			
		
	
		
		
			
				
					
					|  |  |  |         } else { |  |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (is_jump_to_self_enabled(cond) && |  |  |  |             if (is_jump_to_self_enabled(cond) && | 
			
		
	
		
		
			
				
					
					|  |  |  |                     (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' |  |  |  |                     (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | 
			
		
	
		
		
			
				
					
					|  |  |  |             auto inst_id = static_cast<opcode_e>(decoder->decode_instruction(instr)); |  |  |  |             auto inst_id = decode_inst_id(instr); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // pre execution stuff |  |  |  |             // pre execution stuff | 
			
		
	
		
		
			
				
					
					|  |  |  |             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); |  |  |  |             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); | 
			
		
	
		
		
			
				
					
					|  |  |  |             switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %> |  |  |  |             switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %> | 
			
		
	
		
		
			
				
					
					|  |  |  |             case opcode_e::${instr.name}: { |  |  |  |             case arch::traits<ARCH>::opcode_e::${instr.name}: { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 <%instr.fields.eachLine{%>${it} |  |  |  |                 <%instr.fields.eachLine{%>${it} | 
			
		
	
		
		
			
				
					
					|  |  |  |                 <%}%>if(this->disass_enabled){ |  |  |  |                 <%}%>if(this->disass_enabled){ | 
			
		
	
		
		
			
				
					
					|  |  |  |                     /* generate console output when executing the command */<%instr.disass.eachLine{%> |  |  |  |                     /* generate console output when executing the command */<%instr.disass.eachLine{%> | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -236,8 +309,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |                 // used registers<%instr.usedVariables.each{ k,v-> |  |  |  |                 // used registers<%instr.usedVariables.each{ k,v-> | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if(v.isArray) {%> |  |  |  |                 if(v.isArray) {%> | 
			
		
	
		
		
			
				
					
					|  |  |  |                 auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+traits::reg_byte_offsets[traits::${k}0]);<% }else{ %>  |  |  |  |                 auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>  | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+traits::reg_byte_offsets[traits::${k}]); |  |  |  |                 auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]); | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 <%}}%>// calculate next pc value |  |  |  |                 <%}}%>// calculate next pc value | 
			
		
	
		
		
			
				
					
					|  |  |  |                 *NEXT_PC = *PC + ${instr.length/8}; |  |  |  |                 *NEXT_PC = *PC + ${instr.length/8}; | 
			
		
	
		
		
			
				
					
					|  |  |  |                 // execute instruction<%instr.behavior.eachLine{%> |  |  |  |                 // execute instruction<%instr.behavior.eachLine{%> | 
			
		
	
	
		
		
			
				
					
					|  |  |   |