|  |  |  | @@ -94,7 +94,7 @@ protected: | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     inline const char *name(size_t index){return traits::reg_aliases.at(index);} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     compile_func decode_inst(code_word_t instr) ; | 
		
	
		
			
				|  |  |  |  |     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; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     // some compile time constants | 
		
	
	
		
			
				
					
					|  |  |  | @@ -114,7 +114,7 @@ protected: | 
		
	
		
			
				|  |  |  |  |     struct instruction_pattern { | 
		
	
		
			
				|  |  |  |  |         uint32_t value; | 
		
	
		
			
				|  |  |  |  |         uint32_t mask; | 
		
	
		
			
				|  |  |  |  |         compile_func opc; | 
		
	
		
			
				|  |  |  |  |         typename arch::traits<ARCH>::opcode_e id; | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     std::array<std::vector<instruction_pattern>, 4> qlut; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -201,74 +201,14 @@ private: | 
		
	
		
			
				|  |  |  |  |         size_t length; | 
		
	
		
			
				|  |  |  |  |         uint32_t value; | 
		
	
		
			
				|  |  |  |  |         uint32_t mask; | 
		
	
		
			
				|  |  |  |  |         compile_func op; | 
		
	
		
			
				|  |  |  |  |         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 -> %> | 
		
	
		
			
				|  |  |  |  |         /* instruction ${instr.instruction.name} */ | 
		
	
		
			
				|  |  |  |  |         {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> | 
		
	
		
			
				|  |  |  |  |         {${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%> | 
		
	
		
			
				|  |  |  |  |     }}; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> | 
		
	
		
			
				|  |  |  |  |     /* instruction ${idx}: ${instr.name} */ | 
		
	
		
			
				|  |  |  |  |     compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){ | 
		
	
		
			
				|  |  |  |  |         // pre execution stuff | 
		
	
		
			
				|  |  |  |  |         if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx}); | 
		
	
		
			
				|  |  |  |  |         <%instr.fields.eachLine{%>${it} | 
		
	
		
			
				|  |  |  |  |         <%}%>if(this->disass_enabled){ | 
		
	
		
			
				|  |  |  |  |             /* generate console output when executing the command */ | 
		
	
		
			
				|  |  |  |  |             <%instr.disass.eachLine{%>${it} | 
		
	
		
			
				|  |  |  |  |             <%}%> | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); | 
		
	
		
			
				|  |  |  |  |         auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); | 
		
	
		
			
				|  |  |  |  |         auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]); | 
		
	
		
			
				|  |  |  |  |         // used registers<%instr.usedVariables.each{ k,v-> | 
		
	
		
			
				|  |  |  |  |             if(v.isArray) {%> | 
		
	
		
			
				|  |  |  |  |         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+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]); | 
		
	
		
			
				|  |  |  |  |         <%}}%>// calculate next pc value | 
		
	
		
			
				|  |  |  |  |         *NEXT_PC = *PC + ${instr.length/8}; | 
		
	
		
			
				|  |  |  |  |         // execute instruction | 
		
	
		
			
				|  |  |  |  |         try { | 
		
	
		
			
				|  |  |  |  |         <%instr.behavior.eachLine{%>${it} | 
		
	
		
			
				|  |  |  |  |         <%}%>} catch(...){} | 
		
	
		
			
				|  |  |  |  |         // post execution stuff | 
		
	
		
			
				|  |  |  |  |         process_spawn_blocks(); | 
		
	
		
			
				|  |  |  |  |         if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx}); | 
		
	
		
			
				|  |  |  |  |         // trap check | 
		
	
		
			
				|  |  |  |  |         if(*trap_state!=0){ | 
		
	
		
			
				|  |  |  |  |             super::core.enter_trap(*trap_state, pc.val, instr); | 
		
	
		
			
				|  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |             (*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]))++; | 
		
	
		
			
				|  |  |  |  |             (*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]))++; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         (*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++; | 
		
	
		
			
				|  |  |  |  |         pc.val=*NEXT_PC; | 
		
	
		
			
				|  |  |  |  |         return pc; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     <%}%> | 
		
	
		
			
				|  |  |  |  |     /**************************************************************************** | 
		
	
		
			
				|  |  |  |  |      * end opcode definitions | 
		
	
		
			
				|  |  |  |  |      ****************************************************************************/ | 
		
	
		
			
				|  |  |  |  |     compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) { | 
		
	
		
			
				|  |  |  |  |         this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE)); | 
		
	
		
			
				|  |  |  |  |         uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); | 
		
	
		
			
				|  |  |  |  |         uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); | 
		
	
		
			
				|  |  |  |  |         *NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2); | 
		
	
		
			
				|  |  |  |  |         raise(0,  2); | 
		
	
		
			
				|  |  |  |  |         // post execution stuff | 
		
	
		
			
				|  |  |  |  |         if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE)); | 
		
	
		
			
				|  |  |  |  |         auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]); | 
		
	
		
			
				|  |  |  |  |         // trap check | 
		
	
		
			
				|  |  |  |  |         if(*trap_state!=0){ | 
		
	
		
			
				|  |  |  |  |             super::core.enter_trap(*trap_state, pc.val, instr); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         pc.val=*NEXT_PC; | 
		
	
		
			
				|  |  |  |  |         return pc; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; | 
		
	
		
			
				|  |  |  |  |     iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ | 
		
	
		
			
				|  |  |  |  |         auto phys_pc = this->core.v2p(pc); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -307,6 +247,7 @@ constexpr size_t bit_count(uint32_t u) { | 
		
	
		
			
				|  |  |  |  | template <typename ARCH> | 
		
	
		
			
				|  |  |  |  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | 
		
	
		
			
				|  |  |  |  | : vm_base<ARCH>(core, core_id, cluster_id) { | 
		
	
		
			
				|  |  |  |  |     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}); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -327,31 +268,74 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){ | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename ARCH> | 
		
	
		
			
				|  |  |  |  | typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){ | 
		
	
		
			
				|  |  |  |  | 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.opc; | 
		
	
		
			
				|  |  |  |  |         if(!((instr&e.mask) ^ e.value )) return e.id; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return &this_class::illegal_intruction; | 
		
	
		
			
				|  |  |  |  |     return arch::traits<ARCH>::opcode_e::MAX_OPCODE; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 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){ | 
		
	
		
			
				|  |  |  |  |     // we fetch at max 4 byte, alignment is 2 | 
		
	
		
			
				|  |  |  |  |     code_word_t insn = 0; | 
		
	
		
			
				|  |  |  |  |     auto *const data = (uint8_t *)&insn; | 
		
	
		
			
				|  |  |  |  |     code_word_t instr = 0; | 
		
	
		
			
				|  |  |  |  |     auto *const data = (uint8_t *)&instr; | 
		
	
		
			
				|  |  |  |  |     auto pc=start; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     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+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); | 
		
	
		
			
				|  |  |  |  |     auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]); | 
		
	
		
			
				|  |  |  |  |     auto* icount = reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]); | 
		
	
		
			
				|  |  |  |  |     auto* instret = reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     while(!this->core.should_stop() && | 
		
	
		
			
				|  |  |  |  |             !(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){ | 
		
	
		
			
				|  |  |  |  |         auto res = fetch_ins(pc, data); | 
		
	
		
			
				|  |  |  |  |         if(res!=iss::Ok){ | 
		
	
		
			
				|  |  |  |  |         if(fetch_ins(pc, data)!=iss::Ok){ | 
		
	
		
			
				|  |  |  |  |             this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max()); | 
		
	
		
			
				|  |  |  |  |             pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0); | 
		
	
		
			
				|  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |             if (is_jump_to_self_enabled(cond) && | 
		
	
		
			
				|  |  |  |  |                     (insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | 
		
	
		
			
				|  |  |  |  |             auto f = decode_inst(insn); | 
		
	
		
			
				|  |  |  |  |             auto old_pc = pc.val; | 
		
	
		
			
				|  |  |  |  |             pc = (this->*f)(pc, insn); | 
		
	
		
			
				|  |  |  |  |                     (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | 
		
	
		
			
				|  |  |  |  |             auto inst_id = decode_inst_id(instr); | 
		
	
		
			
				|  |  |  |  |             // pre execution stuff | 
		
	
		
			
				|  |  |  |  |             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); | 
		
	
		
			
				|  |  |  |  |             switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %> | 
		
	
		
			
				|  |  |  |  |             case arch::traits<ARCH>::opcode_e::${instr.name}: { | 
		
	
		
			
				|  |  |  |  | 		        <%instr.fields.eachLine{%>${it} | 
		
	
		
			
				|  |  |  |  | 		        <%}%>if(this->disass_enabled){ | 
		
	
		
			
				|  |  |  |  | 		            /* generate console output when executing the command */ | 
		
	
		
			
				|  |  |  |  | 		            <%instr.disass.eachLine{%>${it} | 
		
	
		
			
				|  |  |  |  | 		            <%}%> | 
		
	
		
			
				|  |  |  |  | 		        } | 
		
	
		
			
				|  |  |  |  | 		        // used registers<%instr.usedVariables.each{ k,v-> | 
		
	
		
			
				|  |  |  |  | 		        if(v.isArray) {%> | 
		
	
		
			
				|  |  |  |  | 		        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+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]); | 
		
	
		
			
				|  |  |  |  | 		        <%}}%>// calculate next pc value | 
		
	
		
			
				|  |  |  |  | 		        *NEXT_PC = *PC + ${instr.length/8}; | 
		
	
		
			
				|  |  |  |  | 		        // execute instruction | 
		
	
		
			
				|  |  |  |  | 		        try { | 
		
	
		
			
				|  |  |  |  | 		        <%instr.behavior.eachLine{%>${it} | 
		
	
		
			
				|  |  |  |  | 		        <%}%>} catch(...){} | 
		
	
		
			
				|  |  |  |  | 	    	} | 
		
	
		
			
				|  |  |  |  | 	    	break;<%}%> | 
		
	
		
			
				|  |  |  |  |             default: { | 
		
	
		
			
				|  |  |  |  |                 *NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2); | 
		
	
		
			
				|  |  |  |  |                 raise(0,  2); | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             // post execution stuff | 
		
	
		
			
				|  |  |  |  |             process_spawn_blocks(); | 
		
	
		
			
				|  |  |  |  |             if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id)); | 
		
	
		
			
				|  |  |  |  |             // trap check | 
		
	
		
			
				|  |  |  |  |             if(*trap_state!=0){ | 
		
	
		
			
				|  |  |  |  |                 super::core.enter_trap(*trap_state, pc.val, instr); | 
		
	
		
			
				|  |  |  |  |             } else { | 
		
	
		
			
				|  |  |  |  |                 (*icount)++; | 
		
	
		
			
				|  |  |  |  |                 (*instret)++; | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             (*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++; | 
		
	
		
			
				|  |  |  |  |             pc.val=*NEXT_PC; | 
		
	
		
			
				|  |  |  |  |             this->core.reg.PC = this->core.reg.NEXT_PC; | 
		
	
		
			
				|  |  |  |  |             this->core.reg.trap_state = this->core.reg.pending_trap; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -359,7 +343,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | 
		
	
		
			
				|  |  |  |  |     return pc; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | } // namespace mnrv32 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <> | 
		
	
		
			
				|  |  |  |  | std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { | 
		
	
	
		
			
				
					
					|  |  |  |   |