[WIP] started to add TinyCC backend
This commit is contained in:
		| @@ -44,15 +44,17 @@ add_subdirectory(softfloat) | |||||||
| FILE(GLOB RiscVSCHeaders ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*/*.h) | FILE(GLOB RiscVSCHeaders ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*/*.h) | ||||||
| set(LIB_HEADERS ${RiscVSCHeaders} ) | set(LIB_HEADERS ${RiscVSCHeaders} ) | ||||||
| set(LIB_SOURCES  | set(LIB_SOURCES  | ||||||
| 	src/iss/rv32gc.cpp | 	#src/iss/rv32gc.cpp | ||||||
| 	src/iss/rv32imac.cpp | 	src/iss/rv32imac.cpp | ||||||
| 	src/iss/rv64i.cpp | 	#src/iss/rv64i.cpp | ||||||
| 	src/iss/rv64gc.cpp | 	#src/iss/rv64gc.cpp | ||||||
| 	src/internal/fp_functions.cpp | 	src/iss/mnrv32.cpp | ||||||
| 	src/internal/vm_rv32gc.cpp | 	src/vm/llvm/fp_functions.cpp | ||||||
| 	src/internal/vm_rv32imac.cpp | 	#src/vm/llvm/vm_rv32gc.cpp | ||||||
| 	src/internal/vm_rv64i.cpp | 	src/vm/llvm/vm_rv32imac.cpp | ||||||
| 	src/internal/vm_rv64gc.cpp | 	#src/vm/llvm/vm_rv64i.cpp | ||||||
|  | 	#src/vm/llvm/vm_rv64gc.cpp | ||||||
|  | 	src/vm/tcc/vm_mnrv32.cpp | ||||||
|     src/plugin/instruction_count.cpp |     src/plugin/instruction_count.cpp | ||||||
|     src/plugin/cycle_estimate.cpp) |     src/plugin/cycle_estimate.cpp) | ||||||
|  |  | ||||||
| @@ -62,15 +64,12 @@ set(LIBRARY_NAME riscv) | |||||||
| # Define the library | # Define the library | ||||||
| add_library(${LIBRARY_NAME} ${LIB_SOURCES}) | add_library(${LIBRARY_NAME} ${LIB_SOURCES}) | ||||||
| SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive) | SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive) | ||||||
| target_link_libraries(${LIBRARY_NAME} softfloat) | target_link_libraries(${LIBRARY_NAME} softfloat dbt-core tinycc scc-util) | ||||||
| target_link_libraries(${LIBRARY_NAME} dbt-core) |  | ||||||
| target_link_libraries(${LIBRARY_NAME} scc-util) |  | ||||||
| set_target_properties(${LIBRARY_NAME} PROPERTIES | set_target_properties(${LIBRARY_NAME} PROPERTIES | ||||||
|   VERSION ${VERSION}  # ${VERSION} was defined in the main CMakeLists. |   VERSION ${VERSION}  # ${VERSION} was defined in the main CMakeLists. | ||||||
|   FRAMEWORK FALSE |   FRAMEWORK FALSE | ||||||
|   PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers |   PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers | ||||||
| ) | ) | ||||||
| #set_property(TARGET ${LIBRARY_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) |  | ||||||
|  |  | ||||||
| if(SystemC_FOUND) | if(SystemC_FOUND) | ||||||
| 	set(SC_LIBRARY_NAME riscv_sc) | 	set(SC_LIBRARY_NAME riscv_sc) | ||||||
|   | |||||||
| @@ -6,6 +6,18 @@ import "RVC.core_desc" | |||||||
| import "RVF.core_desc" | import "RVF.core_desc" | ||||||
| import "RVD.core_desc" | import "RVD.core_desc" | ||||||
|  |  | ||||||
|  | Core MNRV32 provides RV32I/*, RV32IC */ { | ||||||
|  |     constants { | ||||||
|  |         XLEN:=32; | ||||||
|  |         PCLEN:=32; | ||||||
|  |         // definitions for the architecture wrapper | ||||||
|  |         //          XL    ZYXWVUTSRQPONMLKJIHGFEDCBA | ||||||
|  |         MISA_VAL:=0b01000000000101000001000100000101; | ||||||
|  |         PGSIZE := 0x1000; //1 << 12; | ||||||
|  |         PGMASK := 0xfff; //PGSIZE-1 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC { | Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC { | ||||||
|     constants { |     constants { | ||||||
|         XLEN:=32; |         XLEN:=32; | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								gen_input/templates/tcc/CORENAME_cyles.txt.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								gen_input/templates/tcc/CORENAME_cyles.txt.gtl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | {  | ||||||
|  | 	"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","} | ||||||
|  | 		{ | ||||||
|  | 			"name"  : "${instr.name}", | ||||||
|  | 			"size"  : ${instr.length}, | ||||||
|  | 			"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1} | ||||||
|  | 		}<%}%> | ||||||
|  | 	] | ||||||
|  | } | ||||||
							
								
								
									
										221
									
								
								gen_input/templates/tcc/incl-CORENAME.h.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								gen_input/templates/tcc/incl-CORENAME.h.gtl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2017, 2018 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  | ||||||
|  | <%  | ||||||
|  | import com.minres.coredsl.coreDsl.Register | ||||||
|  | import com.minres.coredsl.coreDsl.RegisterFile | ||||||
|  | import com.minres.coredsl.coreDsl.RegisterAlias | ||||||
|  | def getTypeSize(size){ | ||||||
|  | 	if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8 | ||||||
|  | } | ||||||
|  | def getOriginalName(reg){ | ||||||
|  |     if( reg.original instanceof RegisterFile) { | ||||||
|  |     	if( reg.index != null ) { | ||||||
|  |         	return reg.original.name+generator.generateHostCode(reg.index) | ||||||
|  |         } else { | ||||||
|  |         	return reg.original.name | ||||||
|  |         } | ||||||
|  |     } else if(reg.original instanceof Register){ | ||||||
|  |         return reg.original.name | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | def getRegisterNames(){ | ||||||
|  | 	def regNames = [] | ||||||
|  |  	allRegs.each { reg ->  | ||||||
|  | 		if( reg instanceof RegisterFile) { | ||||||
|  | 			(reg.range.right..reg.range.left).each{ | ||||||
|  |     			regNames+=reg.name.toLowerCase()+it | ||||||
|  |             } | ||||||
|  |         } else if(reg instanceof Register){ | ||||||
|  |     		regNames+=reg.name.toLowerCase() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return regNames | ||||||
|  | } | ||||||
|  | def getRegisterAliasNames(){ | ||||||
|  | 	def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]} | ||||||
|  |  	return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg -> | ||||||
|  | 		if( reg instanceof RegisterFile) { | ||||||
|  | 			return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() } | ||||||
|  |         } else if(reg instanceof Register){ | ||||||
|  |     		regMap[reg.name]?:reg.name.toLowerCase() | ||||||
|  |         } | ||||||
|  |  	}.flatten() | ||||||
|  | } | ||||||
|  | %> | ||||||
|  | #ifndef _${coreDef.name.toUpperCase()}_H_ | ||||||
|  | #define _${coreDef.name.toUpperCase()}_H_ | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <iss/arch/traits.h> | ||||||
|  | #include <iss/arch_if.h> | ||||||
|  | #include <iss/vm_if.h> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace arch { | ||||||
|  |  | ||||||
|  | struct ${coreDef.name.toLowerCase()}; | ||||||
|  |  | ||||||
|  | template <> struct traits<${coreDef.name.toLowerCase()}> { | ||||||
|  |  | ||||||
|  | 	constexpr static char const* const core_type = "${coreDef.name}"; | ||||||
|  |      | ||||||
|  |   	static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{ | ||||||
|  |  		{"${getRegisterNames().join("\", \"")}"}}; | ||||||
|  |   | ||||||
|  |   	static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{ | ||||||
|  |  		{"${getRegisterAliasNames().join("\", \"")}"}}; | ||||||
|  |  | ||||||
|  |     enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}}; | ||||||
|  |  | ||||||
|  |     constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0}; | ||||||
|  |  | ||||||
|  |     enum reg_e {<% | ||||||
|  |      	allRegs.each { reg ->  | ||||||
|  |     		if( reg instanceof RegisterFile) { | ||||||
|  |     			(reg.range.right..reg.range.left).each{%> | ||||||
|  |         ${reg.name}${it},<% | ||||||
|  |                 } | ||||||
|  |             } else if(reg instanceof Register){ %> | ||||||
|  |         ${reg.name},<%   | ||||||
|  |             } | ||||||
|  |         }%> | ||||||
|  |         NUM_REGS, | ||||||
|  |         NEXT_${pc.name}=NUM_REGS, | ||||||
|  |         TRAP_STATE, | ||||||
|  |         PENDING_TRAP, | ||||||
|  |         MACHINE_STATE, | ||||||
|  |         LAST_BRANCH, | ||||||
|  |         ICOUNT<%  | ||||||
|  |      	allRegs.each { reg ->  | ||||||
|  |     		if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>, | ||||||
|  |         ${reg.name} = ${aliasname}<% | ||||||
|  |             } | ||||||
|  |         }%> | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     using reg_t = uint${regDataWidth}_t; | ||||||
|  |  | ||||||
|  |     using addr_t = uint${addrDataWidth}_t; | ||||||
|  |  | ||||||
|  |     using code_word_t = uint${addrDataWidth}_t; //TODO: check removal | ||||||
|  |  | ||||||
|  |     using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>; | ||||||
|  |  | ||||||
|  |     using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>; | ||||||
|  |  | ||||||
|  |  	static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{ | ||||||
|  |  		{${regSizes.join(",")}}}; | ||||||
|  |  | ||||||
|  |     static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{ | ||||||
|  |     	{${regOffsets.join(",")}}}; | ||||||
|  |  | ||||||
|  |     static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); | ||||||
|  |  | ||||||
|  |     enum sreg_flag_e { FLAGS }; | ||||||
|  |  | ||||||
|  |     enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct ${coreDef.name.toLowerCase()}: public arch_if { | ||||||
|  |  | ||||||
|  |     using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t; | ||||||
|  |     using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t; | ||||||
|  |     using reg_t =  typename traits<${coreDef.name.toLowerCase()}>::reg_t; | ||||||
|  |     using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t; | ||||||
|  |  | ||||||
|  |     ${coreDef.name.toLowerCase()}(); | ||||||
|  |     ~${coreDef.name.toLowerCase()}(); | ||||||
|  |  | ||||||
|  |     void reset(uint64_t address=0) override; | ||||||
|  |  | ||||||
|  |     uint8_t* get_regs_base_ptr() override; | ||||||
|  |     /// deprecated | ||||||
|  |     void get_reg(short idx, std::vector<uint8_t>& value) override {} | ||||||
|  |     void set_reg(short idx, const std::vector<uint8_t>& value) override {} | ||||||
|  |     /// deprecated | ||||||
|  |     bool get_flag(int flag) override {return false;} | ||||||
|  |     void set_flag(int, bool value) override {}; | ||||||
|  |     /// deprecated | ||||||
|  |     void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {}; | ||||||
|  |  | ||||||
|  |     inline uint64_t get_icount() { return reg.icount; } | ||||||
|  |  | ||||||
|  |     inline bool should_stop() { return interrupt_sim; } | ||||||
|  |  | ||||||
|  |     inline phys_addr_t v2p(const iss::addr_t& addr){ | ||||||
|  |         if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL || | ||||||
|  |                 addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) { | ||||||
|  |             return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask); | ||||||
|  |         } else | ||||||
|  |             return virt2phys(addr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     virtual phys_addr_t virt2phys(const iss::addr_t& addr); | ||||||
|  |  | ||||||
|  |     virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } | ||||||
|  |  | ||||||
|  |     inline uint32_t get_last_branch() { return reg.last_branch; } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     struct ${coreDef.name}_regs {<% | ||||||
|  |      	allRegs.each { reg ->  | ||||||
|  |     		if( reg instanceof RegisterFile) { | ||||||
|  |     			(reg.range.right..reg.range.left).each{%> | ||||||
|  |         uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<% | ||||||
|  |                 } | ||||||
|  |             } else if(reg instanceof Register){ %> | ||||||
|  |         uint${generator.getSize(reg)}_t ${reg.name} = 0;<% | ||||||
|  |             } | ||||||
|  |         }%> | ||||||
|  |         uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0; | ||||||
|  |         uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0; | ||||||
|  |         uint64_t icount = 0; | ||||||
|  |     } reg; | ||||||
|  |  | ||||||
|  |     std::array<address_type, 4> addr_mode; | ||||||
|  |      | ||||||
|  |     bool interrupt_sim=false; | ||||||
|  | <% | ||||||
|  | def fcsr = allRegs.find {it.name=='FCSR'} | ||||||
|  | if(fcsr != null) {%> | ||||||
|  | 	uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;} | ||||||
|  | 	void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}		 | ||||||
|  | <%} else { %> | ||||||
|  | 	uint32_t get_fcsr(){return 0;} | ||||||
|  | 	void set_fcsr(uint32_t val){} | ||||||
|  | <%}%> | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | }             | ||||||
|  | #endif /* _${coreDef.name.toUpperCase()}_H_ */ | ||||||
							
								
								
									
										117
									
								
								gen_input/templates/tcc/src-CORENAME.cpp.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								gen_input/templates/tcc/src-CORENAME.cpp.gtl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2017, 2018 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  <%  | ||||||
|  | import com.minres.coredsl.coreDsl.Register | ||||||
|  | import com.minres.coredsl.coreDsl.RegisterFile | ||||||
|  | import com.minres.coredsl.coreDsl.RegisterAlias | ||||||
|  | def getOriginalName(reg){ | ||||||
|  |     if( reg.original instanceof RegisterFile) { | ||||||
|  |     	if( reg.index != null ) { | ||||||
|  |         	return reg.original.name+generator.generateHostCode(reg.index) | ||||||
|  |         } else { | ||||||
|  |         	return reg.original.name | ||||||
|  |         } | ||||||
|  |     } else if(reg.original instanceof Register){ | ||||||
|  |         return reg.original.name | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | def getRegisterNames(){ | ||||||
|  | 	def regNames = [] | ||||||
|  |  	allRegs.each { reg ->  | ||||||
|  | 		if( reg instanceof RegisterFile) { | ||||||
|  | 			(reg.range.right..reg.range.left).each{ | ||||||
|  |     			regNames+=reg.name.toLowerCase()+it | ||||||
|  |             } | ||||||
|  |         } else if(reg instanceof Register){ | ||||||
|  |     		regNames+=reg.name.toLowerCase() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return regNames | ||||||
|  | } | ||||||
|  | def getRegisterAliasNames(){ | ||||||
|  | 	def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]} | ||||||
|  |  	return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg -> | ||||||
|  | 		if( reg instanceof RegisterFile) { | ||||||
|  | 			return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() } | ||||||
|  |         } else if(reg instanceof Register){ | ||||||
|  |     		regMap[reg.name]?:reg.name.toLowerCase() | ||||||
|  |         } | ||||||
|  |  	}.flatten() | ||||||
|  | } | ||||||
|  | %> | ||||||
|  | #include "util/ities.h" | ||||||
|  | #include <util/logging.h> | ||||||
|  |  | ||||||
|  | #include <elfio/elfio.hpp> | ||||||
|  | #include <iss/arch/${coreDef.name.toLowerCase()}.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | #include <ihex.h> | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #include <cstdio> | ||||||
|  | #include <cstring> | ||||||
|  | #include <fstream> | ||||||
|  |  | ||||||
|  | using namespace iss::arch; | ||||||
|  |  | ||||||
|  | constexpr std::array<const char*, ${getRegisterNames().size}>    iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names; | ||||||
|  | constexpr std::array<const char*, ${getRegisterAliasNames().size}>    iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases; | ||||||
|  | constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths; | ||||||
|  | constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets; | ||||||
|  |  | ||||||
|  | ${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() { | ||||||
|  |     reg.icount = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default; | ||||||
|  |  | ||||||
|  | void ${coreDef.name.toLowerCase()}::reset(uint64_t address) { | ||||||
|  |     for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0)); | ||||||
|  |     reg.PC=address; | ||||||
|  |     reg.NEXT_PC=reg.PC; | ||||||
|  |     reg.trap_state=0; | ||||||
|  |     reg.machine_state=0x3; | ||||||
|  |     reg.icount=0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() { | ||||||
|  | 	return reinterpret_cast<uint8_t*>(®); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) { | ||||||
|  |     return phys_addr_t(pc); // change logical address to physical address | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										327
									
								
								gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,327 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2020 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  | ||||||
|  | #include <iss/arch/${coreDef.name.toLowerCase()}.h> | ||||||
|  | #include <iss/arch/riscv_hart_msu_vp.h> | ||||||
|  | #include <iss/debugger/gdb_session.h> | ||||||
|  | #include <iss/debugger/server.h> | ||||||
|  | #include <iss/iss.h> | ||||||
|  | #include <iss/llvm/vm_base.h> | ||||||
|  | #include <util/logging.h> | ||||||
|  | #include <strstream> | ||||||
|  |  | ||||||
|  | #ifndef FMT_HEADER_ONLY | ||||||
|  | #define FMT_HEADER_ONLY | ||||||
|  | #endif | ||||||
|  | #include <fmt/format.h> | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <iss/debugger/riscv_target_adapter.h> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace vm { | ||||||
|  | namespace fp_impl { | ||||||
|  | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace tcc { | ||||||
|  | namespace ${coreDef.name.toLowerCase()} { | ||||||
|  | using namespace iss::arch; | ||||||
|  | using namespace iss::debugger; | ||||||
|  | using namespace iss::vm::llvm; | ||||||
|  |  | ||||||
|  | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
|  | public: | ||||||
|  |     using super = typename iss::vm::llvm::vm_base<ARCH>; | ||||||
|  |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|  |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|  |     using code_word_t = typename super::code_word_t; | ||||||
|  |     using addr_t = typename super::addr_t; | ||||||
|  |  | ||||||
|  |     vm_impl(); | ||||||
|  |  | ||||||
|  |     vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0); | ||||||
|  |  | ||||||
|  |     void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; } | ||||||
|  |  | ||||||
|  |     target_adapter_if *accquire_target_adapter(server_if *srv) override { | ||||||
|  |         debugger_if::dbg_enabled = true; | ||||||
|  |         if (vm_base<ARCH>::tgt_adapter == nullptr) | ||||||
|  |             vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch()); | ||||||
|  |         return vm_base<ARCH>::tgt_adapter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     using vm_base<ARCH>::get_reg_ptr; | ||||||
|  |  | ||||||
|  |     using this_class = vm_impl<ARCH>; | ||||||
|  |     using compile_ret_t = std::tuple<continuation_e>; | ||||||
|  |     using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&); | ||||||
|  |  | ||||||
|  |     inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);} | ||||||
|  |  | ||||||
|  |     template <typename T> inline ConstantInt *size(T type) { | ||||||
|  |         return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setup_module(Module* m) override { | ||||||
|  |         super::setup_module(m); | ||||||
|  |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
|  |         return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override; | ||||||
|  |  | ||||||
|  |     void gen_leave_behavior(BasicBlock *leave_blk) override; | ||||||
|  |  | ||||||
|  |     void gen_raise_trap(uint16_t trap_id, uint16_t cause); | ||||||
|  |  | ||||||
|  |     void gen_leave_trap(unsigned lvl); | ||||||
|  |  | ||||||
|  |     void gen_wait(unsigned type); | ||||||
|  |  | ||||||
|  |     void gen_trap_behavior(BasicBlock *) override; | ||||||
|  |  | ||||||
|  |     void gen_trap_check(BasicBlock *bb); | ||||||
|  |  | ||||||
|  |     inline Value *gen_reg_load(unsigned i, unsigned level = 0) { | ||||||
|  |         return this->builder.CreateLoad(get_reg_ptr(i), false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) { | ||||||
|  |         Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val), | ||||||
|  |                                                            this->get_type(traits<ARCH>::XLEN)); | ||||||
|  |         this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // some compile time constants | ||||||
|  |     // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; | ||||||
|  |     enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; | ||||||
|  |  | ||||||
|  |     std::array<compile_func, LUT_SIZE> lut; | ||||||
|  |  | ||||||
|  |     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 *, 4> qlut; | ||||||
|  |  | ||||||
|  | 	std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; | ||||||
|  |  | ||||||
|  |     void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], | ||||||
|  |                          compile_func f) { | ||||||
|  |         if (pos < 0) { | ||||||
|  |             lut[idx] = f; | ||||||
|  |         } else { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); | ||||||
|  |             } else { | ||||||
|  |                 if ((valid & bitmask) == 0) { | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); | ||||||
|  |                 } else { | ||||||
|  |                     auto new_val = idx << 1; | ||||||
|  |                     if ((value & bitmask) != 0) new_val++; | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } | ||||||
|  |  | ||||||
|  |     uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { | ||||||
|  |         if (pos >= 0) { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, lut_val); | ||||||
|  |             } else { | ||||||
|  |                 auto new_val = lut_val << 1; | ||||||
|  |                 if ((val & bitmask) != 0) new_val++; | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, new_val); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return lut_val; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * start opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     struct InstructionDesriptor { | ||||||
|  |         size_t length; | ||||||
|  |         uint32_t value; | ||||||
|  |         uint32_t mask; | ||||||
|  |         compile_func 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.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.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, std::ostringstream& os){<%instr.code.eachLine{%> | ||||||
|  |     	${it}<%}%> | ||||||
|  |     } | ||||||
|  |     <%}%> | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * end opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::stringstream& os) { | ||||||
|  | 		this->gen_sync(iss::PRE_SYNC, instr_descr.size()); | ||||||
|  |         this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true), | ||||||
|  |                                    get_reg_ptr(traits<ARCH>::PC), true); | ||||||
|  |         this->builder.CreateStore( | ||||||
|  |             this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true), | ||||||
|  |                                      this->gen_const(64U, 1)), | ||||||
|  |             get_reg_ptr(traits<ARCH>::ICOUNT), true); | ||||||
|  |         pc = pc + ((instr & 3) == 3 ? 4 : 2); | ||||||
|  |         this->gen_raise_trap(0, 2);     // illegal instruction trap | ||||||
|  | 		this->gen_sync(iss::POST_SYNC, instr_descr.size()); | ||||||
|  |         this->gen_trap_check(this->leave_blk); | ||||||
|  |         return BRANCH; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | ||||||
|  |     volatile CODE_WORD x = insn; | ||||||
|  |     insn = 2 * x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | ||||||
|  | : vm_base<ARCH>(core, core_id, cluster_id) { | ||||||
|  |     qlut[0] = lut_00.data(); | ||||||
|  |     qlut[1] = lut_01.data(); | ||||||
|  |     qlut[2] = lut_10.data(); | ||||||
|  |     qlut[3] = lut_11.data(); | ||||||
|  |     for (auto instr : instr_descr) { | ||||||
|  |         auto quantrant = instr.value & 0x3; | ||||||
|  |         expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | std::tuple<continuation_e> | ||||||
|  | vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstream& os) { | ||||||
|  |     // we fetch at max 4 byte, alignment is 2 | ||||||
|  |     enum {TRAP_ID=1<<16}; | ||||||
|  |     code_word_t insn = 0; | ||||||
|  |     const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK; | ||||||
|  |     phys_addr_t paddr(pc); | ||||||
|  |     auto *const data = (uint8_t *)&insn; | ||||||
|  |     paddr = this->core.v2p(pc); | ||||||
|  |     if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary | ||||||
|  |         auto res = this->core.read(paddr, 2, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |         if ((insn & 0x3) == 0x3) { // this is a 32bit instruction | ||||||
|  |             res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         auto res = this->core.read(paddr, 4, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |     } | ||||||
|  |     if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | ||||||
|  |     // curr pc on stack | ||||||
|  |     ++inst_cnt; | ||||||
|  |     auto lut_val = extract_fields(insn); | ||||||
|  |     auto f = qlut[insn & 0x3][lut_val]; | ||||||
|  |     if (f == nullptr) { | ||||||
|  |         f = &this_class::illegal_intruction; | ||||||
|  |     } | ||||||
|  |     return (this->*f)(pc, insn, this_block); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) { | ||||||
|  |     this->builder.SetInsertPoint(leave_blk); | ||||||
|  |     this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) { | ||||||
|  |     auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id); | ||||||
|  |     this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) { | ||||||
|  |     std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) }; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("leave_trap"), args); | ||||||
|  |     auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8); | ||||||
|  |     this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) { | ||||||
|  |     std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("wait"), args); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) { | ||||||
|  |     this->builder.SetInsertPoint(trap_blk); | ||||||
|  |     auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), | ||||||
|  |                               get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  |     std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val), | ||||||
|  |                               this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))}; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); | ||||||
|  |     auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false); | ||||||
|  |     this->builder.CreateRet(trap_addr_val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) { | ||||||
|  |     auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->gen_cond_branch(this->builder.CreateICmp( | ||||||
|  |                               ICmpInst::ICMP_EQ, v, | ||||||
|  |                               ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), | ||||||
|  |                           bb, this->trap_blk, 1); | ||||||
|  | } | ||||||
|  | } // namespace ${coreDef.name.toLowerCase()} | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { | ||||||
|  |     auto ret = new ${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*core, dump); | ||||||
|  |     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); | ||||||
|  |     return std::unique_ptr<vm_if>(ret); | ||||||
|  | } | ||||||
|  | } | ||||||
|  | } // namespace iss | ||||||
							
								
								
									
										250
									
								
								incl/iss/arch/mnrv32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								incl/iss/arch/mnrv32.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,250 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2017, 2018 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #ifndef _MNRV32_H_ | ||||||
|  | #define _MNRV32_H_ | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <iss/arch/traits.h> | ||||||
|  | #include <iss/arch_if.h> | ||||||
|  | #include <iss/vm_if.h> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace arch { | ||||||
|  |  | ||||||
|  | struct mnrv32; | ||||||
|  |  | ||||||
|  | template <> struct traits<mnrv32> { | ||||||
|  |  | ||||||
|  | 	constexpr static char const* const core_type = "MNRV32"; | ||||||
|  |      | ||||||
|  |   	static constexpr std::array<const char*, 33> reg_names{ | ||||||
|  |  		{"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc"}}; | ||||||
|  |   | ||||||
|  |   	static constexpr std::array<const char*, 33> reg_aliases{ | ||||||
|  |  		{"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}}; | ||||||
|  |  | ||||||
|  |     enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000101000001000100000101, PGSIZE=0x1000, PGMASK=0xfff}; | ||||||
|  |  | ||||||
|  |     constexpr static unsigned FP_REGS_SIZE = 0; | ||||||
|  |  | ||||||
|  |     enum reg_e { | ||||||
|  |         X0, | ||||||
|  |         X1, | ||||||
|  |         X2, | ||||||
|  |         X3, | ||||||
|  |         X4, | ||||||
|  |         X5, | ||||||
|  |         X6, | ||||||
|  |         X7, | ||||||
|  |         X8, | ||||||
|  |         X9, | ||||||
|  |         X10, | ||||||
|  |         X11, | ||||||
|  |         X12, | ||||||
|  |         X13, | ||||||
|  |         X14, | ||||||
|  |         X15, | ||||||
|  |         X16, | ||||||
|  |         X17, | ||||||
|  |         X18, | ||||||
|  |         X19, | ||||||
|  |         X20, | ||||||
|  |         X21, | ||||||
|  |         X22, | ||||||
|  |         X23, | ||||||
|  |         X24, | ||||||
|  |         X25, | ||||||
|  |         X26, | ||||||
|  |         X27, | ||||||
|  |         X28, | ||||||
|  |         X29, | ||||||
|  |         X30, | ||||||
|  |         X31, | ||||||
|  |         PC, | ||||||
|  |         NUM_REGS, | ||||||
|  |         NEXT_PC=NUM_REGS, | ||||||
|  |         TRAP_STATE, | ||||||
|  |         PENDING_TRAP, | ||||||
|  |         MACHINE_STATE, | ||||||
|  |         LAST_BRANCH, | ||||||
|  |         ICOUNT, | ||||||
|  |         ZERO = X0, | ||||||
|  |         RA = X1, | ||||||
|  |         SP = X2, | ||||||
|  |         GP = X3, | ||||||
|  |         TP = X4, | ||||||
|  |         T0 = X5, | ||||||
|  |         T1 = X6, | ||||||
|  |         T2 = X7, | ||||||
|  |         S0 = X8, | ||||||
|  |         S1 = X9, | ||||||
|  |         A0 = X10, | ||||||
|  |         A1 = X11, | ||||||
|  |         A2 = X12, | ||||||
|  |         A3 = X13, | ||||||
|  |         A4 = X14, | ||||||
|  |         A5 = X15, | ||||||
|  |         A6 = X16, | ||||||
|  |         A7 = X17, | ||||||
|  |         S2 = X18, | ||||||
|  |         S3 = X19, | ||||||
|  |         S4 = X20, | ||||||
|  |         S5 = X21, | ||||||
|  |         S6 = X22, | ||||||
|  |         S7 = X23, | ||||||
|  |         S8 = X24, | ||||||
|  |         S9 = X25, | ||||||
|  |         S10 = X26, | ||||||
|  |         S11 = X27, | ||||||
|  |         T3 = X28, | ||||||
|  |         T4 = X29, | ||||||
|  |         T5 = X30, | ||||||
|  |         T6 = X31 | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     using reg_t = uint32_t; | ||||||
|  |  | ||||||
|  |     using addr_t = uint32_t; | ||||||
|  |  | ||||||
|  |     using code_word_t = uint32_t; //TODO: check removal | ||||||
|  |  | ||||||
|  |     using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>; | ||||||
|  |  | ||||||
|  |     using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>; | ||||||
|  |  | ||||||
|  |  	static constexpr std::array<const uint32_t, 39> reg_bit_widths{ | ||||||
|  |  		{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64}}; | ||||||
|  |  | ||||||
|  |     static constexpr std::array<const uint32_t, 40> reg_byte_offsets{ | ||||||
|  |     	{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,160}}; | ||||||
|  |  | ||||||
|  |     static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); | ||||||
|  |  | ||||||
|  |     enum sreg_flag_e { FLAGS }; | ||||||
|  |  | ||||||
|  |     enum mem_type_e { MEM, CSR, FENCE, RES }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct mnrv32: public arch_if { | ||||||
|  |  | ||||||
|  |     using virt_addr_t = typename traits<mnrv32>::virt_addr_t; | ||||||
|  |     using phys_addr_t = typename traits<mnrv32>::phys_addr_t; | ||||||
|  |     using reg_t =  typename traits<mnrv32>::reg_t; | ||||||
|  |     using addr_t = typename traits<mnrv32>::addr_t; | ||||||
|  |  | ||||||
|  |     mnrv32(); | ||||||
|  |     ~mnrv32(); | ||||||
|  |  | ||||||
|  |     void reset(uint64_t address=0) override; | ||||||
|  |  | ||||||
|  |     uint8_t* get_regs_base_ptr() override; | ||||||
|  |     /// deprecated | ||||||
|  |     void get_reg(short idx, std::vector<uint8_t>& value) override {} | ||||||
|  |     void set_reg(short idx, const std::vector<uint8_t>& value) override {} | ||||||
|  |     /// deprecated | ||||||
|  |     bool get_flag(int flag) override {return false;} | ||||||
|  |     void set_flag(int, bool value) override {}; | ||||||
|  |     /// deprecated | ||||||
|  |     void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {}; | ||||||
|  |  | ||||||
|  |     inline uint64_t get_icount() { return reg.icount; } | ||||||
|  |  | ||||||
|  |     inline bool should_stop() { return interrupt_sim; } | ||||||
|  |  | ||||||
|  |     inline phys_addr_t v2p(const iss::addr_t& addr){ | ||||||
|  |         if (addr.space != traits<mnrv32>::MEM || addr.type == iss::address_type::PHYSICAL || | ||||||
|  |                 addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) { | ||||||
|  |             return phys_addr_t(addr.access, addr.space, addr.val&traits<mnrv32>::addr_mask); | ||||||
|  |         } else | ||||||
|  |             return virt2phys(addr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     virtual phys_addr_t virt2phys(const iss::addr_t& addr); | ||||||
|  |  | ||||||
|  |     virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } | ||||||
|  |  | ||||||
|  |     inline uint32_t get_last_branch() { return reg.last_branch; } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     struct MNRV32_regs { | ||||||
|  |         uint32_t X0 = 0; | ||||||
|  |         uint32_t X1 = 0; | ||||||
|  |         uint32_t X2 = 0; | ||||||
|  |         uint32_t X3 = 0; | ||||||
|  |         uint32_t X4 = 0; | ||||||
|  |         uint32_t X5 = 0; | ||||||
|  |         uint32_t X6 = 0; | ||||||
|  |         uint32_t X7 = 0; | ||||||
|  |         uint32_t X8 = 0; | ||||||
|  |         uint32_t X9 = 0; | ||||||
|  |         uint32_t X10 = 0; | ||||||
|  |         uint32_t X11 = 0; | ||||||
|  |         uint32_t X12 = 0; | ||||||
|  |         uint32_t X13 = 0; | ||||||
|  |         uint32_t X14 = 0; | ||||||
|  |         uint32_t X15 = 0; | ||||||
|  |         uint32_t X16 = 0; | ||||||
|  |         uint32_t X17 = 0; | ||||||
|  |         uint32_t X18 = 0; | ||||||
|  |         uint32_t X19 = 0; | ||||||
|  |         uint32_t X20 = 0; | ||||||
|  |         uint32_t X21 = 0; | ||||||
|  |         uint32_t X22 = 0; | ||||||
|  |         uint32_t X23 = 0; | ||||||
|  |         uint32_t X24 = 0; | ||||||
|  |         uint32_t X25 = 0; | ||||||
|  |         uint32_t X26 = 0; | ||||||
|  |         uint32_t X27 = 0; | ||||||
|  |         uint32_t X28 = 0; | ||||||
|  |         uint32_t X29 = 0; | ||||||
|  |         uint32_t X30 = 0; | ||||||
|  |         uint32_t X31 = 0; | ||||||
|  |         uint32_t PC = 0; | ||||||
|  |         uint32_t NEXT_PC = 0; | ||||||
|  |         uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0; | ||||||
|  |         uint64_t icount = 0; | ||||||
|  |     } reg; | ||||||
|  |  | ||||||
|  |     std::array<address_type, 4> addr_mode; | ||||||
|  |      | ||||||
|  |     bool interrupt_sim=false; | ||||||
|  |  | ||||||
|  | 	uint32_t get_fcsr(){return 0;} | ||||||
|  | 	void set_fcsr(uint32_t val){} | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } | ||||||
|  | }             | ||||||
|  | #endif /* _MNRV32_H_ */ | ||||||
							
								
								
									
										79
									
								
								src/iss/mnrv32.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/iss/mnrv32.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2017, 2018 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |   | ||||||
|  | #include "util/ities.h" | ||||||
|  | #include <util/logging.h> | ||||||
|  |  | ||||||
|  | #include <elfio/elfio.hpp> | ||||||
|  | #include <iss/arch/mnrv32.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | #include <ihex.h> | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #include <cstdio> | ||||||
|  | #include <cstring> | ||||||
|  | #include <fstream> | ||||||
|  |  | ||||||
|  | using namespace iss::arch; | ||||||
|  |  | ||||||
|  | constexpr std::array<const char*, 33>    iss::arch::traits<iss::arch::mnrv32>::reg_names; | ||||||
|  | constexpr std::array<const char*, 33>    iss::arch::traits<iss::arch::mnrv32>::reg_aliases; | ||||||
|  | constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::mnrv32>::reg_bit_widths; | ||||||
|  | constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::mnrv32>::reg_byte_offsets; | ||||||
|  |  | ||||||
|  | mnrv32::mnrv32() { | ||||||
|  |     reg.icount = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | mnrv32::~mnrv32() = default; | ||||||
|  |  | ||||||
|  | void mnrv32::reset(uint64_t address) { | ||||||
|  |     for(size_t i=0; i<traits<mnrv32>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<mnrv32>::reg_t),0)); | ||||||
|  |     reg.PC=address; | ||||||
|  |     reg.NEXT_PC=reg.PC; | ||||||
|  |     reg.trap_state=0; | ||||||
|  |     reg.machine_state=0x3; | ||||||
|  |     reg.icount=0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t *mnrv32::get_regs_base_ptr() { | ||||||
|  | 	return reinterpret_cast<uint8_t*>(®); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | mnrv32::phys_addr_t mnrv32::virt2phys(const iss::addr_t &pc) { | ||||||
|  |     return phys_addr_t(pc); // change logical address to physical address | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -107,26 +107,26 @@ int main(int argc, char *argv[]) { | |||||||
|         std::unique_ptr<iss::vm_if> vm{nullptr}; |         std::unique_ptr<iss::vm_if> vm{nullptr}; | ||||||
|         std::unique_ptr<iss::arch_if> cpu{nullptr}; |         std::unique_ptr<iss::arch_if> cpu{nullptr}; | ||||||
|         std::string isa_opt(clim["isa"].as<std::string>()); |         std::string isa_opt(clim["isa"].as<std::string>()); | ||||||
|         if (isa_opt=="rv64ia") { | //        if (isa_opt=="rv64ia") { | ||||||
|             iss::arch::rv64i* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64i>(); | //            iss::arch::rv64i* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64i>(); | ||||||
|             vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>()); | //            vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>()); | ||||||
|             cpu.reset(lcpu); | //            cpu.reset(lcpu); | ||||||
|         } else if (isa_opt=="rv64gc") { | //        } else if (isa_opt=="rv64gc") { | ||||||
|             iss::arch::rv64gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64gc>(); | //            iss::arch::rv64gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv64gc>(); | ||||||
|             vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>()); | //            vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>()); | ||||||
|             cpu.reset(lcpu); | //            cpu.reset(lcpu); | ||||||
|         } else if (isa_opt=="rv32imac") { | //        } else if (isa_opt=="rv32imac") { | ||||||
|             iss::arch::rv32imac* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>(); |             iss::arch::rv32imac* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32imac>(); | ||||||
|             vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>()); |             vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>()); | ||||||
|             cpu.reset(lcpu); |             cpu.reset(lcpu); | ||||||
|         } else if (isa_opt=="rv32gc") { | //        } else if (isa_opt=="rv32gc") { | ||||||
|             iss::arch::rv32gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32gc>(); | //            iss::arch::rv32gc* lcpu = new iss::arch::riscv_hart_msu_vp<iss::arch::rv32gc>(); | ||||||
|             vm = iss::create(lcpu, clim["gdb-port"].as<unsigned>()); | //            vm = iss::llvm::create(lcpu, clim["gdb-port"].as<unsigned>()); | ||||||
|             cpu.reset(lcpu); | //            cpu.reset(lcpu); | ||||||
|         } else { | //        } else { | ||||||
|             LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl; | //            LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl; | ||||||
|             return 127; | //            return 127; | ||||||
|         } | //        } | ||||||
|         if (clim.count("plugin")) { |         if (clim.count("plugin")) { | ||||||
|             for (std::string opt_val : clim["plugin"].as<std::vector<std::string>>()) { |             for (std::string opt_val : clim["plugin"].as<std::vector<std::string>>()) { | ||||||
|                 std::string plugin_name{opt_val}; |                 std::string plugin_name{opt_val}; | ||||||
|   | |||||||
| @@ -282,7 +282,7 @@ void core_complex::trace(sc_trace_file *trf) const {} | |||||||
|  |  | ||||||
| void core_complex::before_end_of_elaboration() { | void core_complex::before_end_of_elaboration() { | ||||||
|     cpu = scc::make_unique<core_wrapper>(this); |     cpu = scc::make_unique<core_wrapper>(this); | ||||||
|     vm = create<arch::rv32imac>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value()); |     vm = llvm::create<arch::rv32imac>(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value()); | ||||||
| #ifdef WITH_SCV | #ifdef WITH_SCV | ||||||
|     vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); |     vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); | ||||||
| #else | #else | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ extern "C" { | |||||||
| #include <limits> | #include <limits> | ||||||
| 
 | 
 | ||||||
| namespace iss { | namespace iss { | ||||||
| namespace llvm { | namespace vm { | ||||||
| namespace fp_impl { | namespace fp_impl { | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
| @@ -47,7 +47,7 @@ | |||||||
| #include <iss/debugger/riscv_target_adapter.h> | #include <iss/debugger/riscv_target_adapter.h> | ||||||
| 
 | 
 | ||||||
| namespace iss { | namespace iss { | ||||||
| namespace llvm { | namespace vm { | ||||||
| namespace fp_impl { | namespace fp_impl { | ||||||
| void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
| } | } | ||||||
| @@ -57,11 +57,11 @@ namespace rv32gc { | |||||||
| using namespace iss::arch; | using namespace iss::arch; | ||||||
| using namespace llvm; | using namespace llvm; | ||||||
| using namespace iss::debugger; | using namespace iss::debugger; | ||||||
| using namespace iss::llvm; | using namespace iss::vm::llvm; | ||||||
| 
 | 
 | ||||||
| template <typename ARCH> class vm_impl : public vm_base<ARCH> { | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
| public: | public: | ||||||
|     using super = typename iss::llvm::vm_base<ARCH>; |     using super = typename iss::vm::llvm::vm_base<ARCH>; | ||||||
|     using virt_addr_t = typename super::virt_addr_t; |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|     using phys_addr_t = typename super::phys_addr_t; |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|     using code_word_t = typename super::code_word_t; |     using code_word_t = typename super::code_word_t; | ||||||
| @@ -91,7 +91,7 @@ protected: | |||||||
| 
 | 
 | ||||||
|     void setup_module(Module* m) override { |     void setup_module(Module* m) override { | ||||||
|         super::setup_module(m); |         super::setup_module(m); | ||||||
|         iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
| @@ -47,12 +47,12 @@ | |||||||
| #include <iss/debugger/riscv_target_adapter.h> | #include <iss/debugger/riscv_target_adapter.h> | ||||||
| 
 | 
 | ||||||
| namespace iss { | namespace iss { | ||||||
| namespace llvm { | namespace vm { | ||||||
| namespace fp_impl { | namespace fp_impl { | ||||||
| void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
| } | } | ||||||
| } | } | ||||||
| 
 | namespace llvm { | ||||||
| namespace rv32imac { | namespace rv32imac { | ||||||
| using namespace iss::arch; | using namespace iss::arch; | ||||||
| using namespace llvm; | using namespace llvm; | ||||||
| @@ -91,7 +91,7 @@ protected: | |||||||
| 
 | 
 | ||||||
|     void setup_module(Module* m) override { |     void setup_module(Module* m) override { | ||||||
|         super::setup_module(m); |         super::setup_module(m); | ||||||
|         iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
| @@ -4815,5 +4815,5 @@ std::unique_ptr<vm_if> create<arch::rv32imac>(arch::rv32imac *core, unsigned sho | |||||||
|     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); |     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); | ||||||
|     return std::unique_ptr<vm_if>(ret); |     return std::unique_ptr<vm_if>(ret); | ||||||
| } | } | ||||||
| 
 | } | ||||||
| } // namespace iss
 | } // namespace iss
 | ||||||
| @@ -47,7 +47,7 @@ | |||||||
| #include <iss/debugger/riscv_target_adapter.h> | #include <iss/debugger/riscv_target_adapter.h> | ||||||
| 
 | 
 | ||||||
| namespace iss { | namespace iss { | ||||||
| namespace llvm { | namespace vm { | ||||||
| namespace fp_impl { | namespace fp_impl { | ||||||
| void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
| } | } | ||||||
| @@ -57,11 +57,11 @@ namespace rv64gc { | |||||||
| using namespace iss::arch; | using namespace iss::arch; | ||||||
| using namespace llvm; | using namespace llvm; | ||||||
| using namespace iss::debugger; | using namespace iss::debugger; | ||||||
| using namespace iss::llvm; | using namespace iss::vm::llvm; | ||||||
| 
 | 
 | ||||||
| template <typename ARCH> class vm_impl : public vm_base<ARCH> { | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
| public: | public: | ||||||
|     using super = typename iss::llvm::vm_base<ARCH>; |     using super = typename iss::vm::llvm::vm_base<ARCH>; | ||||||
|     using virt_addr_t = typename super::virt_addr_t; |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|     using phys_addr_t = typename super::phys_addr_t; |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|     using code_word_t = typename super::code_word_t; |     using code_word_t = typename super::code_word_t; | ||||||
| @@ -91,7 +91,7 @@ protected: | |||||||
| 
 | 
 | ||||||
|     void setup_module(Module* m) override { |     void setup_module(Module* m) override { | ||||||
|         super::setup_module(m); |         super::setup_module(m); | ||||||
|         iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
| @@ -47,7 +47,7 @@ | |||||||
| #include <iss/debugger/riscv_target_adapter.h> | #include <iss/debugger/riscv_target_adapter.h> | ||||||
| 
 | 
 | ||||||
| namespace iss { | namespace iss { | ||||||
| namespace llvm { | namespace vm { | ||||||
| namespace fp_impl { | namespace fp_impl { | ||||||
| void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
| } | } | ||||||
| @@ -57,11 +57,11 @@ namespace rv64i { | |||||||
| using namespace iss::arch; | using namespace iss::arch; | ||||||
| using namespace llvm; | using namespace llvm; | ||||||
| using namespace iss::debugger; | using namespace iss::debugger; | ||||||
| using namespace iss::llvm; | using namespace iss::vm::llvm; | ||||||
| 
 | 
 | ||||||
| template <typename ARCH> class vm_impl : public vm_base<ARCH> { | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
| public: | public: | ||||||
|     using super = typename iss::llvm::vm_base<ARCH>; |     using super = typename iss::vm::llvm::vm_base<ARCH>; | ||||||
|     using virt_addr_t = typename super::virt_addr_t; |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|     using phys_addr_t = typename super::phys_addr_t; |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|     using code_word_t = typename super::code_word_t; |     using code_word_t = typename super::code_word_t; | ||||||
| @@ -91,7 +91,7 @@ protected: | |||||||
| 
 | 
 | ||||||
|     void setup_module(Module* m) override { |     void setup_module(Module* m) override { | ||||||
|         super::setup_module(m); |         super::setup_module(m); | ||||||
|         iss::llvm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
							
								
								
									
										610
									
								
								src/vm/tcc/vm_mnrv32.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										610
									
								
								src/vm/tcc/vm_mnrv32.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,610 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2020 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  | ||||||
|  | #include <iss/arch/mnrv32.h> | ||||||
|  | #include <iss/arch/riscv_hart_msu_vp.h> | ||||||
|  | #include <iss/debugger/gdb_session.h> | ||||||
|  | #include <iss/debugger/server.h> | ||||||
|  | #include <iss/iss.h> | ||||||
|  | #include <iss/tcc/vm_base.h> | ||||||
|  | #include <util/logging.h> | ||||||
|  | #include <sstream> | ||||||
|  |  | ||||||
|  | #ifndef FMT_HEADER_ONLY | ||||||
|  | #define FMT_HEADER_ONLY | ||||||
|  | #endif | ||||||
|  | #include <fmt/format.h> | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <iss/debugger/riscv_target_adapter.h> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace tcc { | ||||||
|  | namespace mnrv32 { | ||||||
|  | using namespace iss::arch; | ||||||
|  | using namespace iss::debugger; | ||||||
|  | using namespace iss::vm::tcc; | ||||||
|  |  | ||||||
|  | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
|  | public: | ||||||
|  |     using super = typename iss::vm::tcc::vm_base<ARCH>; | ||||||
|  |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|  |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|  |     using code_word_t = typename super::code_word_t; | ||||||
|  |     using addr_t = typename super::addr_t; | ||||||
|  |  | ||||||
|  |     using Value = void; | ||||||
|  |     using ConstantInt = void; | ||||||
|  |     using Type = void; | ||||||
|  |  | ||||||
|  |     vm_impl(); | ||||||
|  |  | ||||||
|  |     vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0); | ||||||
|  |  | ||||||
|  |     void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; } | ||||||
|  |  | ||||||
|  |     target_adapter_if *accquire_target_adapter(server_if *srv) override { | ||||||
|  |         debugger_if::dbg_enabled = true; | ||||||
|  |         if (vm_base<ARCH>::tgt_adapter == nullptr) | ||||||
|  |             vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch()); | ||||||
|  |         return vm_base<ARCH>::tgt_adapter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     using vm_base<ARCH>::get_reg_ptr; | ||||||
|  |  | ||||||
|  |     using this_class = vm_impl<ARCH>; | ||||||
|  |     using compile_ret_t = std::tuple<continuation_e>; | ||||||
|  |     using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&); | ||||||
|  |  | ||||||
|  |     inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);} | ||||||
|  |  | ||||||
|  |     template <typename T> inline ConstantInt *size(T type) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setup_module(Module* m) override { | ||||||
|  |         super::setup_module(m); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
|  |         return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override; | ||||||
|  |  | ||||||
|  |     void gen_leave_behavior(std::ostringstream& os) override; | ||||||
|  |  | ||||||
|  |     void gen_raise_trap(uint16_t trap_id, uint16_t cause); | ||||||
|  |  | ||||||
|  |     void gen_leave_trap(unsigned lvl); | ||||||
|  |  | ||||||
|  |     void gen_wait(unsigned type); | ||||||
|  |  | ||||||
|  |     void gen_trap_behavior(std::ostringstream& os) override; | ||||||
|  |  | ||||||
|  |     void gen_trap_check(std::ostringstream& os){} | ||||||
|  |  | ||||||
|  |     inline Value *gen_reg_load(unsigned i, unsigned level = 0) { | ||||||
|  |         return this->builder.CreateLoad(get_reg_ptr(i), false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) { | ||||||
|  |         Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val), | ||||||
|  |                                                            this->get_type(traits<ARCH>::XLEN)); | ||||||
|  |         this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // some compile time constants | ||||||
|  |     // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; | ||||||
|  |     enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; | ||||||
|  |  | ||||||
|  |     std::array<compile_func, LUT_SIZE> lut; | ||||||
|  |  | ||||||
|  |     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 *, 4> qlut; | ||||||
|  |  | ||||||
|  | 	std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; | ||||||
|  |  | ||||||
|  |     void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], | ||||||
|  |                          compile_func f) { | ||||||
|  |         if (pos < 0) { | ||||||
|  |             lut[idx] = f; | ||||||
|  |         } else { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); | ||||||
|  |             } else { | ||||||
|  |                 if ((valid & bitmask) == 0) { | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); | ||||||
|  |                 } else { | ||||||
|  |                     auto new_val = idx << 1; | ||||||
|  |                     if ((value & bitmask) != 0) new_val++; | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } | ||||||
|  |  | ||||||
|  |     uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { | ||||||
|  |         if (pos >= 0) { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, lut_val); | ||||||
|  |             } else { | ||||||
|  |                 auto new_val = lut_val << 1; | ||||||
|  |                 if ((val & bitmask) != 0) new_val++; | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, new_val); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return lut_val; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * start opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     struct InstructionDesriptor { | ||||||
|  |         size_t length; | ||||||
|  |         uint32_t value; | ||||||
|  |         uint32_t mask; | ||||||
|  |         compile_func op; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const std::array<InstructionDesriptor, 52> instr_descr = {{ | ||||||
|  |          /* entries are: size, valid value, valid mask, function ptr */ | ||||||
|  |         /* instruction LUI */ | ||||||
|  |         {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, | ||||||
|  |         /* instruction AUIPC */ | ||||||
|  |         {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc}, | ||||||
|  |         /* instruction JAL */ | ||||||
|  |         {32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal}, | ||||||
|  |         /* instruction JALR */ | ||||||
|  |         {32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr}, | ||||||
|  |         /* instruction BEQ */ | ||||||
|  |         {32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq}, | ||||||
|  |         /* instruction BNE */ | ||||||
|  |         {32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne}, | ||||||
|  |         /* instruction BLT */ | ||||||
|  |         {32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt}, | ||||||
|  |         /* instruction BGE */ | ||||||
|  |         {32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge}, | ||||||
|  |         /* instruction BLTU */ | ||||||
|  |         {32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu}, | ||||||
|  |         /* instruction BGEU */ | ||||||
|  |         {32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu}, | ||||||
|  |         /* instruction LB */ | ||||||
|  |         {32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb}, | ||||||
|  |         /* instruction LH */ | ||||||
|  |         {32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh}, | ||||||
|  |         /* instruction LW */ | ||||||
|  |         {32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw}, | ||||||
|  |         /* instruction LBU */ | ||||||
|  |         {32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu}, | ||||||
|  |         /* instruction LHU */ | ||||||
|  |         {32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu}, | ||||||
|  |         /* instruction SB */ | ||||||
|  |         {32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb}, | ||||||
|  |         /* instruction SH */ | ||||||
|  |         {32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh}, | ||||||
|  |         /* instruction SW */ | ||||||
|  |         {32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw}, | ||||||
|  |         /* instruction ADDI */ | ||||||
|  |         {32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi}, | ||||||
|  |         /* instruction SLTI */ | ||||||
|  |         {32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti}, | ||||||
|  |         /* instruction SLTIU */ | ||||||
|  |         {32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu}, | ||||||
|  |         /* instruction XORI */ | ||||||
|  |         {32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori}, | ||||||
|  |         /* instruction ORI */ | ||||||
|  |         {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, | ||||||
|  |         /* instruction ANDI */ | ||||||
|  |         {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, | ||||||
|  |         /* instruction SLLI */ | ||||||
|  |         {32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli}, | ||||||
|  |         /* instruction SRLI */ | ||||||
|  |         {32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli}, | ||||||
|  |         /* instruction SRAI */ | ||||||
|  |         {32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai}, | ||||||
|  |         /* instruction ADD */ | ||||||
|  |         {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, | ||||||
|  |         /* instruction SUB */ | ||||||
|  |         {32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub}, | ||||||
|  |         /* instruction SLL */ | ||||||
|  |         {32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll}, | ||||||
|  |         /* instruction SLT */ | ||||||
|  |         {32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt}, | ||||||
|  |         /* instruction SLTU */ | ||||||
|  |         {32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu}, | ||||||
|  |         /* instruction XOR */ | ||||||
|  |         {32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor}, | ||||||
|  |         /* instruction SRL */ | ||||||
|  |         {32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl}, | ||||||
|  |         /* instruction SRA */ | ||||||
|  |         {32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra}, | ||||||
|  |         /* instruction OR */ | ||||||
|  |         {32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or}, | ||||||
|  |         /* instruction AND */ | ||||||
|  |         {32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and}, | ||||||
|  |         /* instruction FENCE */ | ||||||
|  |         {32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence}, | ||||||
|  |         /* instruction FENCE_I */ | ||||||
|  |         {32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i}, | ||||||
|  |         /* instruction ECALL */ | ||||||
|  |         {32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall}, | ||||||
|  |         /* instruction EBREAK */ | ||||||
|  |         {32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak}, | ||||||
|  |         /* instruction URET */ | ||||||
|  |         {32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret}, | ||||||
|  |         /* instruction SRET */ | ||||||
|  |         {32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret}, | ||||||
|  |         /* instruction MRET */ | ||||||
|  |         {32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret}, | ||||||
|  |         /* instruction WFI */ | ||||||
|  |         {32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi}, | ||||||
|  |         /* instruction SFENCE.VMA */ | ||||||
|  |         {32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma}, | ||||||
|  |         /* instruction CSRRW */ | ||||||
|  |         {32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw}, | ||||||
|  |         /* instruction CSRRS */ | ||||||
|  |         {32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs}, | ||||||
|  |         /* instruction CSRRC */ | ||||||
|  |         {32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc}, | ||||||
|  |         /* instruction CSRRWI */ | ||||||
|  |         {32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi}, | ||||||
|  |         /* instruction CSRRSI */ | ||||||
|  |         {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, | ||||||
|  |         /* instruction CSRRCI */ | ||||||
|  |         {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, | ||||||
|  |     }}; | ||||||
|  |   | ||||||
|  |     /* instruction definitions */ | ||||||
|  |     /* instruction 0: LUI */ | ||||||
|  |     compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 1: AUIPC */ | ||||||
|  |     compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 2: JAL */ | ||||||
|  |     compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |         this->gen_sync(PRE_SYNC, 0); | ||||||
|  |  | ||||||
|  |         uint8_t rd = ((bit_sub<7,5>(instr))); | ||||||
|  |         uint8_t rs1 = ((bit_sub<15,5>(instr))); | ||||||
|  |         int16_t imm = signextend<int16_t,12>((bit_sub<20,12>(instr))); | ||||||
|  |         if(this->disass_enabled){ | ||||||
|  |             /* generate console output when executing the command */ | ||||||
|  |             auto mnemonic = fmt::format( | ||||||
|  |                 "{mnemonic:10} {rd}, {rs1}, {imm:#0x}", fmt::arg("mnemonic", "jalr"), | ||||||
|  |                 fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|  |             os<<"print_disass(0x"<<std::hex<<this->core_ptr<<", 0x"<<pc.val<<", \""<<mnemonic<<"\");\n"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         auto cur_pc_val = pc.val; | ||||||
|  |         pc=pc+4; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 3: JALR */ | ||||||
|  |     compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 4: BEQ */ | ||||||
|  |     compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 5: BNE */ | ||||||
|  |     compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 6: BLT */ | ||||||
|  |     compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 7: BGE */ | ||||||
|  |     compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 8: BLTU */ | ||||||
|  |     compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 9: BGEU */ | ||||||
|  |     compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 10: LB */ | ||||||
|  |     compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 11: LH */ | ||||||
|  |     compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 12: LW */ | ||||||
|  |     compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 13: LBU */ | ||||||
|  |     compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 14: LHU */ | ||||||
|  |     compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 15: SB */ | ||||||
|  |     compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 16: SH */ | ||||||
|  |     compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 17: SW */ | ||||||
|  |     compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 18: ADDI */ | ||||||
|  |     compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 19: SLTI */ | ||||||
|  |     compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 20: SLTIU */ | ||||||
|  |     compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 21: XORI */ | ||||||
|  |     compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 22: ORI */ | ||||||
|  |     compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 23: ANDI */ | ||||||
|  |     compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 24: SLLI */ | ||||||
|  |     compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 25: SRLI */ | ||||||
|  |     compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 26: SRAI */ | ||||||
|  |     compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 27: ADD */ | ||||||
|  |     compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 28: SUB */ | ||||||
|  |     compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 29: SLL */ | ||||||
|  |     compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 30: SLT */ | ||||||
|  |     compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 31: SLTU */ | ||||||
|  |     compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 32: XOR */ | ||||||
|  |     compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 33: SRL */ | ||||||
|  |     compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 34: SRA */ | ||||||
|  |     compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 35: OR */ | ||||||
|  |     compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 36: AND */ | ||||||
|  |     compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 37: FENCE */ | ||||||
|  |     compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 38: FENCE_I */ | ||||||
|  |     compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 39: ECALL */ | ||||||
|  |     compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 40: EBREAK */ | ||||||
|  |     compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 41: URET */ | ||||||
|  |     compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 42: SRET */ | ||||||
|  |     compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 43: MRET */ | ||||||
|  |     compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 44: WFI */ | ||||||
|  |     compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 45: SFENCE.VMA */ | ||||||
|  |     compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 46: CSRRW */ | ||||||
|  |     compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 47: CSRRS */ | ||||||
|  |     compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 48: CSRRC */ | ||||||
|  |     compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 49: CSRRWI */ | ||||||
|  |     compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 50: CSRRSI */ | ||||||
|  |     compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 51: CSRRCI */ | ||||||
|  |     compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * end opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::ostringstream& oss) { | ||||||
|  |         vm_impl::gen_sync(iss::PRE_SYNC, instr_descr.size()); | ||||||
|  |         pc = pc + ((instr & 3) == 3 ? 4 : 2); | ||||||
|  |         gen_raise_trap(0, 2);     // illegal instruction trap | ||||||
|  |         vm_impl::gen_sync(iss::POST_SYNC, instr_descr.size()); | ||||||
|  |         vm_impl::gen_trap_check(oss); | ||||||
|  |         return BRANCH; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | ||||||
|  |     volatile CODE_WORD x = insn; | ||||||
|  |     insn = 2 * x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | ||||||
|  | : vm_base<ARCH>(core, core_id, cluster_id) { | ||||||
|  |     qlut[0] = lut_00.data(); | ||||||
|  |     qlut[1] = lut_01.data(); | ||||||
|  |     qlut[2] = lut_10.data(); | ||||||
|  |     qlut[3] = lut_11.data(); | ||||||
|  |     for (auto instr : instr_descr) { | ||||||
|  |         auto quantrant = instr.value & 0x3; | ||||||
|  |         expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | std::tuple<continuation_e> | ||||||
|  | vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstream& os) { | ||||||
|  |     // we fetch at max 4 byte, alignment is 2 | ||||||
|  |     enum {TRAP_ID=1<<16}; | ||||||
|  |     code_word_t insn = 0; | ||||||
|  |     const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK; | ||||||
|  |     phys_addr_t paddr(pc); | ||||||
|  |     auto *const data = (uint8_t *)&insn; | ||||||
|  |     paddr = this->core.v2p(pc); | ||||||
|  |     if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary | ||||||
|  |         auto res = this->core.read(paddr, 2, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |         if ((insn & 0x3) == 0x3) { // this is a 32bit instruction | ||||||
|  |             res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         auto res = this->core.read(paddr, 4, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |     } | ||||||
|  |     if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | ||||||
|  |     // curr pc on stack | ||||||
|  |     ++inst_cnt; | ||||||
|  |     auto lut_val = extract_fields(insn); | ||||||
|  |     auto f = qlut[insn & 0x3][lut_val]; | ||||||
|  |     if (f == nullptr) { | ||||||
|  |         f = &this_class::illegal_intruction; | ||||||
|  |     } | ||||||
|  |     return (this->*f)(pc, insn, os); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(std::ostringstream& os) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(std::ostringstream& os) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace mnrv32 | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | std::unique_ptr<vm_if> create<arch::mnrv32>(arch::mnrv32 *core, unsigned short port, bool dump) { | ||||||
|  |     auto ret = new mnrv32::vm_impl<arch::mnrv32>(*core, dump); | ||||||
|  |     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); | ||||||
|  |     return std::unique_ptr<vm_if>(ret); | ||||||
|  | } | ||||||
|  | } | ||||||
|  | } // namespace iss | ||||||
							
								
								
									
										1273
									
								
								src/vm/tcc/vm_rv32gc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1273
									
								
								src/vm/tcc/vm_rv32gc.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										913
									
								
								src/vm/tcc/vm_rv32imac.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										913
									
								
								src/vm/tcc/vm_rv32imac.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,913 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2020 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  | ||||||
|  | #include <iss/arch/rv32imac.h> | ||||||
|  | #include <iss/arch/riscv_hart_msu_vp.h> | ||||||
|  | #include <iss/debugger/gdb_session.h> | ||||||
|  | #include <iss/debugger/server.h> | ||||||
|  | #include <iss/iss.h> | ||||||
|  | #include <iss/llvm/vm_base.h> | ||||||
|  | #include <util/logging.h> | ||||||
|  |  | ||||||
|  | #ifndef FMT_HEADER_ONLY | ||||||
|  | #define FMT_HEADER_ONLY | ||||||
|  | #endif | ||||||
|  | #include <fmt/format.h> | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <iss/debugger/riscv_target_adapter.h> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace vm { | ||||||
|  | namespace fp_impl { | ||||||
|  | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace tcc { | ||||||
|  | namespace rv32imac { | ||||||
|  | using namespace iss::arch; | ||||||
|  | using namespace iss::debugger; | ||||||
|  | using namespace iss::vm::llvm; | ||||||
|  |  | ||||||
|  | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
|  | public: | ||||||
|  |     using super = typename iss::vm::llvm::vm_base<ARCH>; | ||||||
|  |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|  |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|  |     using code_word_t = typename super::code_word_t; | ||||||
|  |     using addr_t = typename super::addr_t; | ||||||
|  |  | ||||||
|  |     vm_impl(); | ||||||
|  |  | ||||||
|  |     vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0); | ||||||
|  |  | ||||||
|  |     void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; } | ||||||
|  |  | ||||||
|  |     target_adapter_if *accquire_target_adapter(server_if *srv) override { | ||||||
|  |         debugger_if::dbg_enabled = true; | ||||||
|  |         if (vm_base<ARCH>::tgt_adapter == nullptr) | ||||||
|  |             vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch()); | ||||||
|  |         return vm_base<ARCH>::tgt_adapter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     using vm_base<ARCH>::get_reg_ptr; | ||||||
|  |  | ||||||
|  |     using this_class = vm_impl<ARCH>; | ||||||
|  |     using compile_ret_t = std::tuple<continuation_e>; | ||||||
|  |     using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&); | ||||||
|  |  | ||||||
|  |     inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);} | ||||||
|  |  | ||||||
|  |     template <typename T> inline ConstantInt *size(T type) { | ||||||
|  |         return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setup_module(Module* m) override { | ||||||
|  |         super::setup_module(m); | ||||||
|  |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
|  |         return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override; | ||||||
|  |  | ||||||
|  |     void gen_leave_behavior(BasicBlock *leave_blk) override; | ||||||
|  |  | ||||||
|  |     void gen_raise_trap(uint16_t trap_id, uint16_t cause); | ||||||
|  |  | ||||||
|  |     void gen_leave_trap(unsigned lvl); | ||||||
|  |  | ||||||
|  |     void gen_wait(unsigned type); | ||||||
|  |  | ||||||
|  |     void gen_trap_behavior(BasicBlock *) override; | ||||||
|  |  | ||||||
|  |     void gen_trap_check(BasicBlock *bb); | ||||||
|  |  | ||||||
|  |     inline Value *gen_reg_load(unsigned i, unsigned level = 0) { | ||||||
|  |         return this->builder.CreateLoad(get_reg_ptr(i), false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) { | ||||||
|  |         Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val), | ||||||
|  |                                                            this->get_type(traits<ARCH>::XLEN)); | ||||||
|  |         this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // some compile time constants | ||||||
|  |     // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; | ||||||
|  |     enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; | ||||||
|  |  | ||||||
|  |     std::array<compile_func, LUT_SIZE> lut; | ||||||
|  |  | ||||||
|  |     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 *, 4> qlut; | ||||||
|  |  | ||||||
|  | 	std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; | ||||||
|  |  | ||||||
|  |     void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], | ||||||
|  |                          compile_func f) { | ||||||
|  |         if (pos < 0) { | ||||||
|  |             lut[idx] = f; | ||||||
|  |         } else { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); | ||||||
|  |             } else { | ||||||
|  |                 if ((valid & bitmask) == 0) { | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); | ||||||
|  |                 } else { | ||||||
|  |                     auto new_val = idx << 1; | ||||||
|  |                     if ((value & bitmask) != 0) new_val++; | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } | ||||||
|  |  | ||||||
|  |     uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { | ||||||
|  |         if (pos >= 0) { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, lut_val); | ||||||
|  |             } else { | ||||||
|  |                 auto new_val = lut_val << 1; | ||||||
|  |                 if ((val & bitmask) != 0) new_val++; | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, new_val); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return lut_val; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * start opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     struct InstructionDesriptor { | ||||||
|  |         size_t length; | ||||||
|  |         uint32_t value; | ||||||
|  |         uint32_t mask; | ||||||
|  |         compile_func op; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const std::array<InstructionDesriptor, 99> instr_descr = {{ | ||||||
|  |          /* entries are: size, valid value, valid mask, function ptr */ | ||||||
|  |         /* instruction JALR */ | ||||||
|  |         {32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr}, | ||||||
|  |         /* instruction C.ADDI4SPN */ | ||||||
|  |         {16, 0b0000000000000000, 0b1110000000000011, &this_class::__c_addi4spn}, | ||||||
|  |         /* instruction C.LW */ | ||||||
|  |         {16, 0b0100000000000000, 0b1110000000000011, &this_class::__c_lw}, | ||||||
|  |         /* instruction C.SW */ | ||||||
|  |         {16, 0b1100000000000000, 0b1110000000000011, &this_class::__c_sw}, | ||||||
|  |         /* instruction C.ADDI */ | ||||||
|  |         {16, 0b0000000000000001, 0b1110000000000011, &this_class::__c_addi}, | ||||||
|  |         /* instruction C.NOP */ | ||||||
|  |         {16, 0b0000000000000001, 0b1111111111111111, &this_class::__c_nop}, | ||||||
|  |         /* instruction C.JAL */ | ||||||
|  |         {16, 0b0010000000000001, 0b1110000000000011, &this_class::__c_jal}, | ||||||
|  |         /* instruction C.LI */ | ||||||
|  |         {16, 0b0100000000000001, 0b1110000000000011, &this_class::__c_li}, | ||||||
|  |         /* instruction C.LUI */ | ||||||
|  |         {16, 0b0110000000000001, 0b1110000000000011, &this_class::__c_lui}, | ||||||
|  |         /* instruction C.ADDI16SP */ | ||||||
|  |         {16, 0b0110000100000001, 0b1110111110000011, &this_class::__c_addi16sp}, | ||||||
|  |         /* instruction C.SRLI */ | ||||||
|  |         {16, 0b1000000000000001, 0b1111110000000011, &this_class::__c_srli}, | ||||||
|  |         /* instruction C.SRAI */ | ||||||
|  |         {16, 0b1000010000000001, 0b1111110000000011, &this_class::__c_srai}, | ||||||
|  |         /* instruction C.ANDI */ | ||||||
|  |         {16, 0b1000100000000001, 0b1110110000000011, &this_class::__c_andi}, | ||||||
|  |         /* instruction C.SUB */ | ||||||
|  |         {16, 0b1000110000000001, 0b1111110001100011, &this_class::__c_sub}, | ||||||
|  |         /* instruction C.XOR */ | ||||||
|  |         {16, 0b1000110000100001, 0b1111110001100011, &this_class::__c_xor}, | ||||||
|  |         /* instruction C.OR */ | ||||||
|  |         {16, 0b1000110001000001, 0b1111110001100011, &this_class::__c_or}, | ||||||
|  |         /* instruction C.AND */ | ||||||
|  |         {16, 0b1000110001100001, 0b1111110001100011, &this_class::__c_and}, | ||||||
|  |         /* instruction C.J */ | ||||||
|  |         {16, 0b1010000000000001, 0b1110000000000011, &this_class::__c_j}, | ||||||
|  |         /* instruction C.BEQZ */ | ||||||
|  |         {16, 0b1100000000000001, 0b1110000000000011, &this_class::__c_beqz}, | ||||||
|  |         /* instruction C.BNEZ */ | ||||||
|  |         {16, 0b1110000000000001, 0b1110000000000011, &this_class::__c_bnez}, | ||||||
|  |         /* instruction C.SLLI */ | ||||||
|  |         {16, 0b0000000000000010, 0b1111000000000011, &this_class::__c_slli}, | ||||||
|  |         /* instruction C.LWSP */ | ||||||
|  |         {16, 0b0100000000000010, 0b1110000000000011, &this_class::__c_lwsp}, | ||||||
|  |         /* instruction C.MV */ | ||||||
|  |         {16, 0b1000000000000010, 0b1111000000000011, &this_class::__c_mv}, | ||||||
|  |         /* instruction C.JR */ | ||||||
|  |         {16, 0b1000000000000010, 0b1111000001111111, &this_class::__c_jr}, | ||||||
|  |         /* instruction C.ADD */ | ||||||
|  |         {16, 0b1001000000000010, 0b1111000000000011, &this_class::__c_add}, | ||||||
|  |         /* instruction C.JALR */ | ||||||
|  |         {16, 0b1001000000000010, 0b1111000001111111, &this_class::__c_jalr}, | ||||||
|  |         /* instruction C.EBREAK */ | ||||||
|  |         {16, 0b1001000000000010, 0b1111111111111111, &this_class::__c_ebreak}, | ||||||
|  |         /* instruction C.SWSP */ | ||||||
|  |         {16, 0b1100000000000010, 0b1110000000000011, &this_class::__c_swsp}, | ||||||
|  |         /* instruction DII */ | ||||||
|  |         {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, | ||||||
|  |         /* instruction LR.W */ | ||||||
|  |         {32, 0b00010000000000000010000000101111, 0b11111001111100000111000001111111, &this_class::__lr_w}, | ||||||
|  |         /* instruction SC.W */ | ||||||
|  |         {32, 0b00011000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__sc_w}, | ||||||
|  |         /* instruction AMOSWAP.W */ | ||||||
|  |         {32, 0b00001000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoswap_w}, | ||||||
|  |         /* instruction AMOADD.W */ | ||||||
|  |         {32, 0b00000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoadd_w}, | ||||||
|  |         /* instruction AMOXOR.W */ | ||||||
|  |         {32, 0b00100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoxor_w}, | ||||||
|  |         /* instruction AMOAND.W */ | ||||||
|  |         {32, 0b01100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoand_w}, | ||||||
|  |         /* instruction AMOOR.W */ | ||||||
|  |         {32, 0b01000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amoor_w}, | ||||||
|  |         /* instruction AMOMIN.W */ | ||||||
|  |         {32, 0b10000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomin_w}, | ||||||
|  |         /* instruction AMOMAX.W */ | ||||||
|  |         {32, 0b10100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomax_w}, | ||||||
|  |         /* instruction AMOMINU.W */ | ||||||
|  |         {32, 0b11000000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amominu_w}, | ||||||
|  |         /* instruction AMOMAXU.W */ | ||||||
|  |         {32, 0b11100000000000000010000000101111, 0b11111000000000000111000001111111, &this_class::__amomaxu_w}, | ||||||
|  |         /* instruction MUL */ | ||||||
|  |         {32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__mul}, | ||||||
|  |         /* instruction MULH */ | ||||||
|  |         {32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__mulh}, | ||||||
|  |         /* instruction MULHSU */ | ||||||
|  |         {32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__mulhsu}, | ||||||
|  |         /* instruction MULHU */ | ||||||
|  |         {32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__mulhu}, | ||||||
|  |         /* instruction DIV */ | ||||||
|  |         {32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__div}, | ||||||
|  |         /* instruction DIVU */ | ||||||
|  |         {32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__divu}, | ||||||
|  |         /* instruction REM */ | ||||||
|  |         {32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__rem}, | ||||||
|  |         /* instruction REMU */ | ||||||
|  |         {32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__remu}, | ||||||
|  |         /* instruction LUI */ | ||||||
|  |         {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, | ||||||
|  |         /* instruction AUIPC */ | ||||||
|  |         {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc}, | ||||||
|  |         /* instruction JAL */ | ||||||
|  |         {32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal}, | ||||||
|  |         /* instruction BEQ */ | ||||||
|  |         {32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq}, | ||||||
|  |         /* instruction BNE */ | ||||||
|  |         {32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne}, | ||||||
|  |         /* instruction BLT */ | ||||||
|  |         {32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt}, | ||||||
|  |         /* instruction BGE */ | ||||||
|  |         {32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge}, | ||||||
|  |         /* instruction BLTU */ | ||||||
|  |         {32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu}, | ||||||
|  |         /* instruction BGEU */ | ||||||
|  |         {32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu}, | ||||||
|  |         /* instruction LB */ | ||||||
|  |         {32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb}, | ||||||
|  |         /* instruction LH */ | ||||||
|  |         {32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh}, | ||||||
|  |         /* instruction LW */ | ||||||
|  |         {32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw}, | ||||||
|  |         /* instruction LBU */ | ||||||
|  |         {32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu}, | ||||||
|  |         /* instruction LHU */ | ||||||
|  |         {32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu}, | ||||||
|  |         /* instruction SB */ | ||||||
|  |         {32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb}, | ||||||
|  |         /* instruction SH */ | ||||||
|  |         {32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh}, | ||||||
|  |         /* instruction SW */ | ||||||
|  |         {32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw}, | ||||||
|  |         /* instruction ADDI */ | ||||||
|  |         {32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi}, | ||||||
|  |         /* instruction SLTI */ | ||||||
|  |         {32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti}, | ||||||
|  |         /* instruction SLTIU */ | ||||||
|  |         {32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu}, | ||||||
|  |         /* instruction XORI */ | ||||||
|  |         {32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori}, | ||||||
|  |         /* instruction ORI */ | ||||||
|  |         {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, | ||||||
|  |         /* instruction ANDI */ | ||||||
|  |         {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, | ||||||
|  |         /* instruction SLLI */ | ||||||
|  |         {32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli}, | ||||||
|  |         /* instruction SRLI */ | ||||||
|  |         {32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli}, | ||||||
|  |         /* instruction SRAI */ | ||||||
|  |         {32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai}, | ||||||
|  |         /* instruction ADD */ | ||||||
|  |         {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, | ||||||
|  |         /* instruction SUB */ | ||||||
|  |         {32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub}, | ||||||
|  |         /* instruction SLL */ | ||||||
|  |         {32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll}, | ||||||
|  |         /* instruction SLT */ | ||||||
|  |         {32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt}, | ||||||
|  |         /* instruction SLTU */ | ||||||
|  |         {32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu}, | ||||||
|  |         /* instruction XOR */ | ||||||
|  |         {32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor}, | ||||||
|  |         /* instruction SRL */ | ||||||
|  |         {32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl}, | ||||||
|  |         /* instruction SRA */ | ||||||
|  |         {32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra}, | ||||||
|  |         /* instruction OR */ | ||||||
|  |         {32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or}, | ||||||
|  |         /* instruction AND */ | ||||||
|  |         {32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and}, | ||||||
|  |         /* instruction FENCE */ | ||||||
|  |         {32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence}, | ||||||
|  |         /* instruction FENCE_I */ | ||||||
|  |         {32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i}, | ||||||
|  |         /* instruction ECALL */ | ||||||
|  |         {32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall}, | ||||||
|  |         /* instruction EBREAK */ | ||||||
|  |         {32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak}, | ||||||
|  |         /* instruction URET */ | ||||||
|  |         {32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret}, | ||||||
|  |         /* instruction SRET */ | ||||||
|  |         {32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret}, | ||||||
|  |         /* instruction MRET */ | ||||||
|  |         {32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret}, | ||||||
|  |         /* instruction WFI */ | ||||||
|  |         {32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi}, | ||||||
|  |         /* instruction SFENCE.VMA */ | ||||||
|  |         {32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma}, | ||||||
|  |         /* instruction CSRRW */ | ||||||
|  |         {32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw}, | ||||||
|  |         /* instruction CSRRS */ | ||||||
|  |         {32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs}, | ||||||
|  |         /* instruction CSRRC */ | ||||||
|  |         {32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc}, | ||||||
|  |         /* instruction CSRRWI */ | ||||||
|  |         {32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi}, | ||||||
|  |         /* instruction CSRRSI */ | ||||||
|  |         {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, | ||||||
|  |         /* instruction CSRRCI */ | ||||||
|  |         {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, | ||||||
|  |     }}; | ||||||
|  |   | ||||||
|  |     /* instruction definitions */ | ||||||
|  |     /* instruction 0: JALR */ | ||||||
|  |     compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 1: C.ADDI4SPN */ | ||||||
|  |     compile_ret_t __c_addi4spn(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 2: C.LW */ | ||||||
|  |     compile_ret_t __c_lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 3: C.SW */ | ||||||
|  |     compile_ret_t __c_sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 4: C.ADDI */ | ||||||
|  |     compile_ret_t __c_addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 5: C.NOP */ | ||||||
|  |     compile_ret_t __c_nop(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 6: C.JAL */ | ||||||
|  |     compile_ret_t __c_jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 7: C.LI */ | ||||||
|  |     compile_ret_t __c_li(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 8: C.LUI */ | ||||||
|  |     compile_ret_t __c_lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 9: C.ADDI16SP */ | ||||||
|  |     compile_ret_t __c_addi16sp(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 10: C.SRLI */ | ||||||
|  |     compile_ret_t __c_srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 11: C.SRAI */ | ||||||
|  |     compile_ret_t __c_srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 12: C.ANDI */ | ||||||
|  |     compile_ret_t __c_andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 13: C.SUB */ | ||||||
|  |     compile_ret_t __c_sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 14: C.XOR */ | ||||||
|  |     compile_ret_t __c_xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 15: C.OR */ | ||||||
|  |     compile_ret_t __c_or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 16: C.AND */ | ||||||
|  |     compile_ret_t __c_and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 17: C.J */ | ||||||
|  |     compile_ret_t __c_j(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 18: C.BEQZ */ | ||||||
|  |     compile_ret_t __c_beqz(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 19: C.BNEZ */ | ||||||
|  |     compile_ret_t __c_bnez(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 20: C.SLLI */ | ||||||
|  |     compile_ret_t __c_slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 21: C.LWSP */ | ||||||
|  |     compile_ret_t __c_lwsp(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 22: C.MV */ | ||||||
|  |     compile_ret_t __c_mv(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 23: C.JR */ | ||||||
|  |     compile_ret_t __c_jr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 24: C.ADD */ | ||||||
|  |     compile_ret_t __c_add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 25: C.JALR */ | ||||||
|  |     compile_ret_t __c_jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 26: C.EBREAK */ | ||||||
|  |     compile_ret_t __c_ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 27: C.SWSP */ | ||||||
|  |     compile_ret_t __c_swsp(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 28: DII */ | ||||||
|  |     compile_ret_t __dii(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 29: LR.W */ | ||||||
|  |     compile_ret_t __lr_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 30: SC.W */ | ||||||
|  |     compile_ret_t __sc_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 31: AMOSWAP.W */ | ||||||
|  |     compile_ret_t __amoswap_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 32: AMOADD.W */ | ||||||
|  |     compile_ret_t __amoadd_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 33: AMOXOR.W */ | ||||||
|  |     compile_ret_t __amoxor_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 34: AMOAND.W */ | ||||||
|  |     compile_ret_t __amoand_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 35: AMOOR.W */ | ||||||
|  |     compile_ret_t __amoor_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 36: AMOMIN.W */ | ||||||
|  |     compile_ret_t __amomin_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 37: AMOMAX.W */ | ||||||
|  |     compile_ret_t __amomax_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 38: AMOMINU.W */ | ||||||
|  |     compile_ret_t __amominu_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 39: AMOMAXU.W */ | ||||||
|  |     compile_ret_t __amomaxu_w(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 40: MUL */ | ||||||
|  |     compile_ret_t __mul(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 41: MULH */ | ||||||
|  |     compile_ret_t __mulh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 42: MULHSU */ | ||||||
|  |     compile_ret_t __mulhsu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 43: MULHU */ | ||||||
|  |     compile_ret_t __mulhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 44: DIV */ | ||||||
|  |     compile_ret_t __div(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 45: DIVU */ | ||||||
|  |     compile_ret_t __divu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 46: REM */ | ||||||
|  |     compile_ret_t __rem(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 47: REMU */ | ||||||
|  |     compile_ret_t __remu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 48: LUI */ | ||||||
|  |     compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 49: AUIPC */ | ||||||
|  |     compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 50: JAL */ | ||||||
|  |     compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 51: BEQ */ | ||||||
|  |     compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 52: BNE */ | ||||||
|  |     compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 53: BLT */ | ||||||
|  |     compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 54: BGE */ | ||||||
|  |     compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 55: BLTU */ | ||||||
|  |     compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 56: BGEU */ | ||||||
|  |     compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 57: LB */ | ||||||
|  |     compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 58: LH */ | ||||||
|  |     compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 59: LW */ | ||||||
|  |     compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 60: LBU */ | ||||||
|  |     compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 61: LHU */ | ||||||
|  |     compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 62: SB */ | ||||||
|  |     compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 63: SH */ | ||||||
|  |     compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 64: SW */ | ||||||
|  |     compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 65: ADDI */ | ||||||
|  |     compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 66: SLTI */ | ||||||
|  |     compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 67: SLTIU */ | ||||||
|  |     compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 68: XORI */ | ||||||
|  |     compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 69: ORI */ | ||||||
|  |     compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 70: ANDI */ | ||||||
|  |     compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 71: SLLI */ | ||||||
|  |     compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 72: SRLI */ | ||||||
|  |     compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 73: SRAI */ | ||||||
|  |     compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 74: ADD */ | ||||||
|  |     compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 75: SUB */ | ||||||
|  |     compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 76: SLL */ | ||||||
|  |     compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 77: SLT */ | ||||||
|  |     compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 78: SLTU */ | ||||||
|  |     compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 79: XOR */ | ||||||
|  |     compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 80: SRL */ | ||||||
|  |     compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 81: SRA */ | ||||||
|  |     compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 82: OR */ | ||||||
|  |     compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 83: AND */ | ||||||
|  |     compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 84: FENCE */ | ||||||
|  |     compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 85: FENCE_I */ | ||||||
|  |     compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 86: ECALL */ | ||||||
|  |     compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 87: EBREAK */ | ||||||
|  |     compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 88: URET */ | ||||||
|  |     compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 89: SRET */ | ||||||
|  |     compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 90: MRET */ | ||||||
|  |     compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 91: WFI */ | ||||||
|  |     compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 92: SFENCE.VMA */ | ||||||
|  |     compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 93: CSRRW */ | ||||||
|  |     compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 94: CSRRS */ | ||||||
|  |     compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 95: CSRRC */ | ||||||
|  |     compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 96: CSRRWI */ | ||||||
|  |     compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 97: CSRRSI */ | ||||||
|  |     compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 98: CSRRCI */ | ||||||
|  |     compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * end opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::stringstream& os) { | ||||||
|  | 		this->gen_sync(iss::PRE_SYNC, instr_descr.size()); | ||||||
|  |         this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true), | ||||||
|  |                                    get_reg_ptr(traits<ARCH>::PC), true); | ||||||
|  |         this->builder.CreateStore( | ||||||
|  |             this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true), | ||||||
|  |                                      this->gen_const(64U, 1)), | ||||||
|  |             get_reg_ptr(traits<ARCH>::ICOUNT), true); | ||||||
|  |         pc = pc + ((instr & 3) == 3 ? 4 : 2); | ||||||
|  |         this->gen_raise_trap(0, 2);     // illegal instruction trap | ||||||
|  | 		this->gen_sync(iss::POST_SYNC, instr_descr.size()); | ||||||
|  |         this->gen_trap_check(this->leave_blk); | ||||||
|  |         return BRANCH; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | ||||||
|  |     volatile CODE_WORD x = insn; | ||||||
|  |     insn = 2 * x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | ||||||
|  | : vm_base<ARCH>(core, core_id, cluster_id) { | ||||||
|  |     qlut[0] = lut_00.data(); | ||||||
|  |     qlut[1] = lut_01.data(); | ||||||
|  |     qlut[2] = lut_10.data(); | ||||||
|  |     qlut[3] = lut_11.data(); | ||||||
|  |     for (auto instr : instr_descr) { | ||||||
|  |         auto quantrant = instr.value & 0x3; | ||||||
|  |         expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | std::tuple<continuation_e> | ||||||
|  | vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstrem& os) { | ||||||
|  |     // we fetch at max 4 byte, alignment is 2 | ||||||
|  |     enum {TRAP_ID=1<<16}; | ||||||
|  |     code_word_t insn = 0; | ||||||
|  |     const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK; | ||||||
|  |     phys_addr_t paddr(pc); | ||||||
|  |     auto *const data = (uint8_t *)&insn; | ||||||
|  |     paddr = this->core.v2p(pc); | ||||||
|  |     if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary | ||||||
|  |         auto res = this->core.read(paddr, 2, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |         if ((insn & 0x3) == 0x3) { // this is a 32bit instruction | ||||||
|  |             res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         auto res = this->core.read(paddr, 4, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |     } | ||||||
|  |     if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | ||||||
|  |     // curr pc on stack | ||||||
|  |     ++inst_cnt; | ||||||
|  |     auto lut_val = extract_fields(insn); | ||||||
|  |     auto f = qlut[insn & 0x3][lut_val]; | ||||||
|  |     if (f == nullptr) { | ||||||
|  |         f = &this_class::illegal_intruction; | ||||||
|  |     } | ||||||
|  |     return (this->*f)(pc, insn, this_block); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) { | ||||||
|  |     this->builder.SetInsertPoint(leave_blk); | ||||||
|  |     this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) { | ||||||
|  |     auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id); | ||||||
|  |     this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) { | ||||||
|  |     std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) }; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("leave_trap"), args); | ||||||
|  |     auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8); | ||||||
|  |     this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) { | ||||||
|  |     std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("wait"), args); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) { | ||||||
|  |     this->builder.SetInsertPoint(trap_blk); | ||||||
|  |     auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), | ||||||
|  |                               get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  |     std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val), | ||||||
|  |                               this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))}; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); | ||||||
|  |     auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false); | ||||||
|  |     this->builder.CreateRet(trap_addr_val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) { | ||||||
|  |     auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->gen_cond_branch(this->builder.CreateICmp( | ||||||
|  |                               ICmpInst::ICMP_EQ, v, | ||||||
|  |                               ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), | ||||||
|  |                           bb, this->trap_blk, 1); | ||||||
|  | } | ||||||
|  | } // namespace rv32imac | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | std::unique_ptr<vm_if> create<arch::rv32imac>(arch::rv32imac *core, unsigned short port, bool dump) { | ||||||
|  |     auto ret = new rv32imac::vm_impl<arch::rv32imac>(*core, dump); | ||||||
|  |     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); | ||||||
|  |     return std::unique_ptr<vm_if>(ret); | ||||||
|  | } | ||||||
|  | } | ||||||
|  | } // namespace iss | ||||||
							
								
								
									
										1543
									
								
								src/vm/tcc/vm_rv64gc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1543
									
								
								src/vm/tcc/vm_rv64gc.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										703
									
								
								src/vm/tcc/vm_rv64i.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										703
									
								
								src/vm/tcc/vm_rv64i.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,703 @@ | |||||||
|  | /******************************************************************************* | ||||||
|  |  * Copyright (C) 2020 MINRES Technologies GmbH | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  *    this list of conditions and the following disclaimer in the documentation | ||||||
|  |  *    and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||||
|  |  *    may be used to endorse or promote products derived from this software | ||||||
|  |  *    without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  *******************************************************************************/ | ||||||
|  |  | ||||||
|  | #include <iss/arch/rv64i.h> | ||||||
|  | #include <iss/arch/riscv_hart_msu_vp.h> | ||||||
|  | #include <iss/debugger/gdb_session.h> | ||||||
|  | #include <iss/debugger/server.h> | ||||||
|  | #include <iss/iss.h> | ||||||
|  | #include <iss/llvm/vm_base.h> | ||||||
|  | #include <util/logging.h> | ||||||
|  |  | ||||||
|  | #ifndef FMT_HEADER_ONLY | ||||||
|  | #define FMT_HEADER_ONLY | ||||||
|  | #endif | ||||||
|  | #include <fmt/format.h> | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <iss/debugger/riscv_target_adapter.h> | ||||||
|  |  | ||||||
|  | namespace iss { | ||||||
|  | namespace vm { | ||||||
|  | namespace fp_impl { | ||||||
|  | void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace tcc { | ||||||
|  | namespace rv64i { | ||||||
|  | using namespace iss::arch; | ||||||
|  | using namespace iss::debugger; | ||||||
|  | using namespace iss::vm::llvm; | ||||||
|  |  | ||||||
|  | template <typename ARCH> class vm_impl : public vm_base<ARCH> { | ||||||
|  | public: | ||||||
|  |     using super = typename iss::vm::llvm::vm_base<ARCH>; | ||||||
|  |     using virt_addr_t = typename super::virt_addr_t; | ||||||
|  |     using phys_addr_t = typename super::phys_addr_t; | ||||||
|  |     using code_word_t = typename super::code_word_t; | ||||||
|  |     using addr_t = typename super::addr_t; | ||||||
|  |  | ||||||
|  |     vm_impl(); | ||||||
|  |  | ||||||
|  |     vm_impl(ARCH &core, unsigned core_id = 0, unsigned cluster_id = 0); | ||||||
|  |  | ||||||
|  |     void enableDebug(bool enable) { super::sync_exec = super::ALL_SYNC; } | ||||||
|  |  | ||||||
|  |     target_adapter_if *accquire_target_adapter(server_if *srv) override { | ||||||
|  |         debugger_if::dbg_enabled = true; | ||||||
|  |         if (vm_base<ARCH>::tgt_adapter == nullptr) | ||||||
|  |             vm_base<ARCH>::tgt_adapter = new riscv_target_adapter<ARCH>(srv, this->get_arch()); | ||||||
|  |         return vm_base<ARCH>::tgt_adapter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     using vm_base<ARCH>::get_reg_ptr; | ||||||
|  |  | ||||||
|  |     using this_class = vm_impl<ARCH>; | ||||||
|  |     using compile_ret_t = std::tuple<continuation_e>; | ||||||
|  |     using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&); | ||||||
|  |  | ||||||
|  |     inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);} | ||||||
|  |  | ||||||
|  |     template <typename T> inline ConstantInt *size(T type) { | ||||||
|  |         return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setup_module(Module* m) override { | ||||||
|  |         super::setup_module(m); | ||||||
|  |         iss::vm::fp_impl::add_fp_functions_2_module(m, traits<ARCH>::FP_REGS_SIZE, traits<ARCH>::XLEN); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { | ||||||
|  |         return super::gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, std::ostringstream&) override; | ||||||
|  |  | ||||||
|  |     void gen_leave_behavior(BasicBlock *leave_blk) override; | ||||||
|  |  | ||||||
|  |     void gen_raise_trap(uint16_t trap_id, uint16_t cause); | ||||||
|  |  | ||||||
|  |     void gen_leave_trap(unsigned lvl); | ||||||
|  |  | ||||||
|  |     void gen_wait(unsigned type); | ||||||
|  |  | ||||||
|  |     void gen_trap_behavior(BasicBlock *) override; | ||||||
|  |  | ||||||
|  |     void gen_trap_check(BasicBlock *bb); | ||||||
|  |  | ||||||
|  |     inline Value *gen_reg_load(unsigned i, unsigned level = 0) { | ||||||
|  |         return this->builder.CreateLoad(get_reg_ptr(i), false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline void gen_set_pc(virt_addr_t pc, unsigned reg_num) { | ||||||
|  |         Value *next_pc_v = this->builder.CreateSExtOrTrunc(this->gen_const(traits<ARCH>::XLEN, pc.val), | ||||||
|  |                                                            this->get_type(traits<ARCH>::XLEN)); | ||||||
|  |         this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // some compile time constants | ||||||
|  |     // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; | ||||||
|  |     enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; | ||||||
|  |     enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; | ||||||
|  |  | ||||||
|  |     std::array<compile_func, LUT_SIZE> lut; | ||||||
|  |  | ||||||
|  |     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 *, 4> qlut; | ||||||
|  |  | ||||||
|  | 	std::array<const uint32_t, 4> lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; | ||||||
|  |  | ||||||
|  |     void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], | ||||||
|  |                          compile_func f) { | ||||||
|  |         if (pos < 0) { | ||||||
|  |             lut[idx] = f; | ||||||
|  |         } else { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); | ||||||
|  |             } else { | ||||||
|  |                 if ((valid & bitmask) == 0) { | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); | ||||||
|  |                 } else { | ||||||
|  |                     auto new_val = idx << 1; | ||||||
|  |                     if ((value & bitmask) != 0) new_val++; | ||||||
|  |                     expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } | ||||||
|  |  | ||||||
|  |     uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { | ||||||
|  |         if (pos >= 0) { | ||||||
|  |             auto bitmask = 1UL << pos; | ||||||
|  |             if ((mask & bitmask) == 0) { | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, lut_val); | ||||||
|  |             } else { | ||||||
|  |                 auto new_val = lut_val << 1; | ||||||
|  |                 if ((val & bitmask) != 0) new_val++; | ||||||
|  |                 lut_val = extract_fields(pos - 1, val, mask, new_val); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return lut_val; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * start opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     struct InstructionDesriptor { | ||||||
|  |         size_t length; | ||||||
|  |         uint32_t value; | ||||||
|  |         uint32_t mask; | ||||||
|  |         compile_func op; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const std::array<InstructionDesriptor, 64> instr_descr = {{ | ||||||
|  |          /* entries are: size, valid value, valid mask, function ptr */ | ||||||
|  |         /* instruction LUI */ | ||||||
|  |         {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, | ||||||
|  |         /* instruction AUIPC */ | ||||||
|  |         {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc}, | ||||||
|  |         /* instruction JAL */ | ||||||
|  |         {32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal}, | ||||||
|  |         /* instruction JALR */ | ||||||
|  |         {32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr}, | ||||||
|  |         /* instruction BEQ */ | ||||||
|  |         {32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq}, | ||||||
|  |         /* instruction BNE */ | ||||||
|  |         {32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne}, | ||||||
|  |         /* instruction BLT */ | ||||||
|  |         {32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt}, | ||||||
|  |         /* instruction BGE */ | ||||||
|  |         {32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge}, | ||||||
|  |         /* instruction BLTU */ | ||||||
|  |         {32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu}, | ||||||
|  |         /* instruction BGEU */ | ||||||
|  |         {32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu}, | ||||||
|  |         /* instruction LB */ | ||||||
|  |         {32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb}, | ||||||
|  |         /* instruction LH */ | ||||||
|  |         {32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh}, | ||||||
|  |         /* instruction LW */ | ||||||
|  |         {32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw}, | ||||||
|  |         /* instruction LBU */ | ||||||
|  |         {32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu}, | ||||||
|  |         /* instruction LHU */ | ||||||
|  |         {32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu}, | ||||||
|  |         /* instruction SB */ | ||||||
|  |         {32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb}, | ||||||
|  |         /* instruction SH */ | ||||||
|  |         {32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh}, | ||||||
|  |         /* instruction SW */ | ||||||
|  |         {32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw}, | ||||||
|  |         /* instruction ADDI */ | ||||||
|  |         {32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi}, | ||||||
|  |         /* instruction SLTI */ | ||||||
|  |         {32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti}, | ||||||
|  |         /* instruction SLTIU */ | ||||||
|  |         {32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu}, | ||||||
|  |         /* instruction XORI */ | ||||||
|  |         {32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori}, | ||||||
|  |         /* instruction ORI */ | ||||||
|  |         {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, | ||||||
|  |         /* instruction ANDI */ | ||||||
|  |         {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, | ||||||
|  |         /* instruction SLLI */ | ||||||
|  |         {32, 0b00000000000000000001000000010011, 0b11111100000000000111000001111111, &this_class::__slli}, | ||||||
|  |         /* instruction SRLI */ | ||||||
|  |         {32, 0b00000000000000000101000000010011, 0b11111100000000000111000001111111, &this_class::__srli}, | ||||||
|  |         /* instruction SRAI */ | ||||||
|  |         {32, 0b01000000000000000101000000010011, 0b11111100000000000111000001111111, &this_class::__srai}, | ||||||
|  |         /* instruction ADD */ | ||||||
|  |         {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, | ||||||
|  |         /* instruction SUB */ | ||||||
|  |         {32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub}, | ||||||
|  |         /* instruction SLL */ | ||||||
|  |         {32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll}, | ||||||
|  |         /* instruction SLT */ | ||||||
|  |         {32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt}, | ||||||
|  |         /* instruction SLTU */ | ||||||
|  |         {32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu}, | ||||||
|  |         /* instruction XOR */ | ||||||
|  |         {32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor}, | ||||||
|  |         /* instruction SRL */ | ||||||
|  |         {32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl}, | ||||||
|  |         /* instruction SRA */ | ||||||
|  |         {32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra}, | ||||||
|  |         /* instruction OR */ | ||||||
|  |         {32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or}, | ||||||
|  |         /* instruction AND */ | ||||||
|  |         {32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and}, | ||||||
|  |         /* instruction FENCE */ | ||||||
|  |         {32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence}, | ||||||
|  |         /* instruction FENCE_I */ | ||||||
|  |         {32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i}, | ||||||
|  |         /* instruction ECALL */ | ||||||
|  |         {32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall}, | ||||||
|  |         /* instruction EBREAK */ | ||||||
|  |         {32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak}, | ||||||
|  |         /* instruction URET */ | ||||||
|  |         {32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret}, | ||||||
|  |         /* instruction SRET */ | ||||||
|  |         {32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret}, | ||||||
|  |         /* instruction MRET */ | ||||||
|  |         {32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret}, | ||||||
|  |         /* instruction WFI */ | ||||||
|  |         {32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi}, | ||||||
|  |         /* instruction SFENCE.VMA */ | ||||||
|  |         {32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma}, | ||||||
|  |         /* instruction CSRRW */ | ||||||
|  |         {32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw}, | ||||||
|  |         /* instruction CSRRS */ | ||||||
|  |         {32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs}, | ||||||
|  |         /* instruction CSRRC */ | ||||||
|  |         {32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc}, | ||||||
|  |         /* instruction CSRRWI */ | ||||||
|  |         {32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi}, | ||||||
|  |         /* instruction CSRRSI */ | ||||||
|  |         {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, | ||||||
|  |         /* instruction CSRRCI */ | ||||||
|  |         {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, | ||||||
|  |         /* instruction LWU */ | ||||||
|  |         {32, 0b00000000000000000110000000000011, 0b00000000000000000111000001111111, &this_class::__lwu}, | ||||||
|  |         /* instruction LD */ | ||||||
|  |         {32, 0b00000000000000000011000000000011, 0b00000000000000000111000001111111, &this_class::__ld}, | ||||||
|  |         /* instruction SD */ | ||||||
|  |         {32, 0b00000000000000000011000000100011, 0b00000000000000000111000001111111, &this_class::__sd}, | ||||||
|  |         /* instruction ADDIW */ | ||||||
|  |         {32, 0b00000000000000000000000000011011, 0b00000000000000000111000001111111, &this_class::__addiw}, | ||||||
|  |         /* instruction SLLIW */ | ||||||
|  |         {32, 0b00000000000000000001000000011011, 0b11111110000000000111000001111111, &this_class::__slliw}, | ||||||
|  |         /* instruction SRLIW */ | ||||||
|  |         {32, 0b00000000000000000101000000011011, 0b11111110000000000111000001111111, &this_class::__srliw}, | ||||||
|  |         /* instruction SRAIW */ | ||||||
|  |         {32, 0b01000000000000000101000000011011, 0b11111110000000000111000001111111, &this_class::__sraiw}, | ||||||
|  |         /* instruction ADDW */ | ||||||
|  |         {32, 0b00000000000000000000000000111011, 0b11111110000000000111000001111111, &this_class::__addw}, | ||||||
|  |         /* instruction SUBW */ | ||||||
|  |         {32, 0b01000000000000000000000000111011, 0b11111110000000000111000001111111, &this_class::__subw}, | ||||||
|  |         /* instruction SLLW */ | ||||||
|  |         {32, 0b00000000000000000001000000111011, 0b11111110000000000111000001111111, &this_class::__sllw}, | ||||||
|  |         /* instruction SRLW */ | ||||||
|  |         {32, 0b00000000000000000101000000111011, 0b11111110000000000111000001111111, &this_class::__srlw}, | ||||||
|  |         /* instruction SRAW */ | ||||||
|  |         {32, 0b01000000000000000101000000111011, 0b11111110000000000111000001111111, &this_class::__sraw}, | ||||||
|  |     }}; | ||||||
|  |   | ||||||
|  |     /* instruction definitions */ | ||||||
|  |     /* instruction 0: LUI */ | ||||||
|  |     compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 1: AUIPC */ | ||||||
|  |     compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 2: JAL */ | ||||||
|  |     compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 3: JALR */ | ||||||
|  |     compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 4: BEQ */ | ||||||
|  |     compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 5: BNE */ | ||||||
|  |     compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 6: BLT */ | ||||||
|  |     compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 7: BGE */ | ||||||
|  |     compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 8: BLTU */ | ||||||
|  |     compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 9: BGEU */ | ||||||
|  |     compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 10: LB */ | ||||||
|  |     compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 11: LH */ | ||||||
|  |     compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 12: LW */ | ||||||
|  |     compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 13: LBU */ | ||||||
|  |     compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 14: LHU */ | ||||||
|  |     compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 15: SB */ | ||||||
|  |     compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 16: SH */ | ||||||
|  |     compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 17: SW */ | ||||||
|  |     compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 18: ADDI */ | ||||||
|  |     compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 19: SLTI */ | ||||||
|  |     compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 20: SLTIU */ | ||||||
|  |     compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 21: XORI */ | ||||||
|  |     compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 22: ORI */ | ||||||
|  |     compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 23: ANDI */ | ||||||
|  |     compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 24: SLLI */ | ||||||
|  |     compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 25: SRLI */ | ||||||
|  |     compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 26: SRAI */ | ||||||
|  |     compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 27: ADD */ | ||||||
|  |     compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 28: SUB */ | ||||||
|  |     compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 29: SLL */ | ||||||
|  |     compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 30: SLT */ | ||||||
|  |     compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 31: SLTU */ | ||||||
|  |     compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 32: XOR */ | ||||||
|  |     compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 33: SRL */ | ||||||
|  |     compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 34: SRA */ | ||||||
|  |     compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 35: OR */ | ||||||
|  |     compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 36: AND */ | ||||||
|  |     compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 37: FENCE */ | ||||||
|  |     compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 38: FENCE_I */ | ||||||
|  |     compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 39: ECALL */ | ||||||
|  |     compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 40: EBREAK */ | ||||||
|  |     compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 41: URET */ | ||||||
|  |     compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 42: SRET */ | ||||||
|  |     compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 43: MRET */ | ||||||
|  |     compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 44: WFI */ | ||||||
|  |     compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 45: SFENCE.VMA */ | ||||||
|  |     compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 46: CSRRW */ | ||||||
|  |     compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 47: CSRRS */ | ||||||
|  |     compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 48: CSRRC */ | ||||||
|  |     compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 49: CSRRWI */ | ||||||
|  |     compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 50: CSRRSI */ | ||||||
|  |     compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 51: CSRRCI */ | ||||||
|  |     compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 52: LWU */ | ||||||
|  |     compile_ret_t __lwu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 53: LD */ | ||||||
|  |     compile_ret_t __ld(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 54: SD */ | ||||||
|  |     compile_ret_t __sd(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 55: ADDIW */ | ||||||
|  |     compile_ret_t __addiw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 56: SLLIW */ | ||||||
|  |     compile_ret_t __slliw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 57: SRLIW */ | ||||||
|  |     compile_ret_t __srliw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 58: SRAIW */ | ||||||
|  |     compile_ret_t __sraiw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 59: ADDW */ | ||||||
|  |     compile_ret_t __addw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 60: SUBW */ | ||||||
|  |     compile_ret_t __subw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 61: SLLW */ | ||||||
|  |     compile_ret_t __sllw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 62: SRLW */ | ||||||
|  |     compile_ret_t __srlw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* instruction 63: SRAW */ | ||||||
|  |     compile_ret_t __sraw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /**************************************************************************** | ||||||
|  |      * end opcode definitions | ||||||
|  |      ****************************************************************************/ | ||||||
|  |     compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, std::stringstream& os) { | ||||||
|  | 		this->gen_sync(iss::PRE_SYNC, instr_descr.size()); | ||||||
|  |         this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), true), | ||||||
|  |                                    get_reg_ptr(traits<ARCH>::PC), true); | ||||||
|  |         this->builder.CreateStore( | ||||||
|  |             this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::ICOUNT), true), | ||||||
|  |                                      this->gen_const(64U, 1)), | ||||||
|  |             get_reg_ptr(traits<ARCH>::ICOUNT), true); | ||||||
|  |         pc = pc + ((instr & 3) == 3 ? 4 : 2); | ||||||
|  |         this->gen_raise_trap(0, 2);     // illegal instruction trap | ||||||
|  | 		this->gen_sync(iss::POST_SYNC, instr_descr.size()); | ||||||
|  |         this->gen_trap_check(this->leave_blk); | ||||||
|  |         return BRANCH; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | ||||||
|  |     volatile CODE_WORD x = insn; | ||||||
|  |     insn = 2 * x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | ||||||
|  | : vm_base<ARCH>(core, core_id, cluster_id) { | ||||||
|  |     qlut[0] = lut_00.data(); | ||||||
|  |     qlut[1] = lut_01.data(); | ||||||
|  |     qlut[2] = lut_10.data(); | ||||||
|  |     qlut[3] = lut_11.data(); | ||||||
|  |     for (auto instr : instr_descr) { | ||||||
|  |         auto quantrant = instr.value & 0x3; | ||||||
|  |         expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> | ||||||
|  | std::tuple<continuation_e> | ||||||
|  | vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstrem& os) { | ||||||
|  |     // we fetch at max 4 byte, alignment is 2 | ||||||
|  |     enum {TRAP_ID=1<<16}; | ||||||
|  |     code_word_t insn = 0; | ||||||
|  |     const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK; | ||||||
|  |     phys_addr_t paddr(pc); | ||||||
|  |     auto *const data = (uint8_t *)&insn; | ||||||
|  |     paddr = this->core.v2p(pc); | ||||||
|  |     if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary | ||||||
|  |         auto res = this->core.read(paddr, 2, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |         if ((insn & 0x3) == 0x3) { // this is a 32bit instruction | ||||||
|  |             res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         auto res = this->core.read(paddr, 4, data); | ||||||
|  |         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | ||||||
|  |     } | ||||||
|  |     if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | ||||||
|  |     // curr pc on stack | ||||||
|  |     ++inst_cnt; | ||||||
|  |     auto lut_val = extract_fields(insn); | ||||||
|  |     auto f = qlut[insn & 0x3][lut_val]; | ||||||
|  |     if (f == nullptr) { | ||||||
|  |         f = &this_class::illegal_intruction; | ||||||
|  |     } | ||||||
|  |     return (this->*f)(pc, insn, this_block); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) { | ||||||
|  |     this->builder.SetInsertPoint(leave_blk); | ||||||
|  |     this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::NEXT_PC), false)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) { | ||||||
|  |     auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id); | ||||||
|  |     this->builder.CreateStore(TRAP_val, get_reg_ptr(traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) { | ||||||
|  |     std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) }; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("leave_trap"), args); | ||||||
|  |     auto *PC_val = this->gen_read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN / 8); | ||||||
|  |     this->builder.CreateStore(PC_val, get_reg_ptr(traits<ARCH>::NEXT_PC), false); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) { | ||||||
|  |     std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("wait"), args); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) { | ||||||
|  |     this->builder.SetInsertPoint(trap_blk); | ||||||
|  |     auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), | ||||||
|  |                               get_reg_ptr(traits<ARCH>::LAST_BRANCH), false); | ||||||
|  |     std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val), | ||||||
|  |                               this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::PC), false))}; | ||||||
|  |     this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); | ||||||
|  |     auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits<ARCH>::NEXT_PC), false); | ||||||
|  |     this->builder.CreateRet(trap_addr_val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) { | ||||||
|  |     auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), true); | ||||||
|  |     this->gen_cond_branch(this->builder.CreateICmp( | ||||||
|  |                               ICmpInst::ICMP_EQ, v, | ||||||
|  |                               ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), | ||||||
|  |                           bb, this->trap_blk, 1); | ||||||
|  | } | ||||||
|  | } // namespace rv64i | ||||||
|  |  | ||||||
|  | template <> | ||||||
|  | std::unique_ptr<vm_if> create<arch::rv64i>(arch::rv64i *core, unsigned short port, bool dump) { | ||||||
|  |     auto ret = new rv64i::vm_impl<arch::rv64i>(*core, dump); | ||||||
|  |     if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); | ||||||
|  |     return std::unique_ptr<vm_if>(ret); | ||||||
|  | } | ||||||
|  | } | ||||||
|  | } // namespace iss | ||||||
		Reference in New Issue
	
	Block a user