diff --git a/CMakeLists.txt b/CMakeLists.txt index b779746..13c15d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.12) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) # main (top) cmake dir set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project specific cmake dir @@ -50,11 +50,13 @@ set(LIB_SOURCES #src/iss/rv64gc.cpp src/iss/mnrv32.cpp src/vm/llvm/fp_functions.cpp + src/vm/llvm/vm_mnrv32.cpp #src/vm/llvm/vm_rv32gc.cpp - src/vm/llvm/vm_rv32imac.cpp + #src/vm/llvm/vm_rv32imac.cpp #src/vm/llvm/vm_rv64i.cpp #src/vm/llvm/vm_rv64gc.cpp src/vm/tcc/vm_mnrv32.cpp + src/vm/interp/vm_mnrv32.cpp src/plugin/instruction_count.cpp src/plugin/cycle_estimate.cpp) @@ -64,7 +66,7 @@ set(LIBRARY_NAME riscv) # Define the library add_library(${LIBRARY_NAME} ${LIB_SOURCES}) SET(${LIBRARY_NAME} -Wl,-whole-archive -l${LIBRARY_NAME} -Wl,-no-whole-archive) -target_link_libraries(${LIBRARY_NAME} softfloat dbt-core tinycc scc-util) +target_link_libraries(${LIBRARY_NAME} softfloat dbt-core scc-util) set_target_properties(${LIBRARY_NAME} PROPERTIES VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists. FRAMEWORK FALSE diff --git a/gen_input/RVC.core_desc b/gen_input/RVC.core_desc index 5c00c5d..273618a 100644 --- a/gen_input/RVC.core_desc +++ b/gen_input/RVC.core_desc @@ -164,7 +164,7 @@ InsructionSet RV32IC extends RISCVBase{ val offs[XLEN] <= X[2] + uimm; MEM[offs]{32} <= X[rs2]; } - DII { + DII(no_cont) { // Defined Illegal Instruction encoding:b000 | b0 | b00000 | b00000 | b00; raise(0, 2); } diff --git a/gen_input/minres_rv.core_desc b/gen_input/minres_rv.core_desc index 462d7a1..14ddd6f 100644 --- a/gen_input/minres_rv.core_desc +++ b/gen_input/minres_rv.core_desc @@ -6,7 +6,7 @@ import "RVC.core_desc" import "RVF.core_desc" import "RVD.core_desc" -Core MNRV32 provides RV32I/*, RV32IC */ { +Core MNRV32 provides RV32I, RV32IC { constants { XLEN:=32; PCLEN:=32; @@ -17,7 +17,7 @@ Core MNRV32 provides RV32I/*, RV32IC */ { PGMASK := 0xfff; //PGSIZE-1 } } - +/* Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC { constants { XLEN:=32; @@ -67,4 +67,4 @@ Core RV64GC provides RV64I, RV64M, RV64A, RV64F, RV64D, RV64IC, RV32FC, RV32DC { PGMASK := 0xfff; //PGSIZE-1 } } - +*/ diff --git a/gen_input/templates/CORENAME_cyles.txt.gtl b/gen_input/templates/interp/CORENAME_cyles.txt.gtl similarity index 100% rename from gen_input/templates/CORENAME_cyles.txt.gtl rename to gen_input/templates/interp/CORENAME_cyles.txt.gtl diff --git a/gen_input/templates/incl-CORENAME.h.gtl b/gen_input/templates/interp/incl-CORENAME.h.gtl similarity index 100% rename from gen_input/templates/incl-CORENAME.h.gtl rename to gen_input/templates/interp/incl-CORENAME.h.gtl diff --git a/gen_input/templates/src-CORENAME.cpp.gtl b/gen_input/templates/interp/src-CORENAME.cpp.gtl similarity index 100% rename from gen_input/templates/src-CORENAME.cpp.gtl rename to gen_input/templates/interp/src-CORENAME.cpp.gtl diff --git a/gen_input/templates/interp/vm-vm_CORENAME.cpp.gtl b/gen_input/templates/interp/vm-vm_CORENAME.cpp.gtl new file mode 100644 index 0000000..35a3ca7 --- /dev/null +++ b/gen_input/templates/interp/vm-vm_CORENAME.cpp.gtl @@ -0,0 +1,246 @@ +/******************************************************************************* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include + +#include +#include + +namespace iss { +namespace interp { +namespace ${coreDef.name.toLowerCase()} { +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::interp::vm_base { +public: + using super = typename iss::interp::vm_base; + 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 reg_t = typename traits::reg_t; + using iss::interp::vm_base::get_reg; + + 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 (super::tgt_adapter == nullptr) + super::tgt_adapter = new riscv_target_adapter(srv, this->get_arch()); + return super::tgt_adapter; + } + +protected: + using this_class = vm_impl; + using compile_ret_t = virt_addr_t; + using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr); + + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + virt_addr_t execute_inst(virt_addr_t start, std::function pred) override; + + // 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 lut; + + std::array lut_00, lut_01, lut_10; + std::array lut_11; + + std::array qlut; + + std::array 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; + } + + void raise_trap(uint16_t trap_id, uint16_t cause){ + auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id; + this->template get_reg(arch::traits::TRAP_STATE) = trap_val; + this->template get_reg(arch::traits::NEXT_PC) = std::numeric_limits::max(); + } + + void leave_trap(unsigned lvl){ + this->core.leave_trap(lvl); + auto pc_val = super::template read_mem(traits::CSR, (lvl << 8) + 0x41); + this->template get_reg(arch::traits::NEXT_PC) = pc_val; + this->template get_reg(arch::traits::LAST_BRANCH) = std::numeric_limits::max(); + } + + void wait(unsigned type){ + this->core.wait_until(type); + } + + +private: + /**************************************************************************** + * start opcode definitions + ****************************************************************************/ + struct InstructionDesriptor { + size_t length; + uint32_t value; + uint32_t mask; + compile_func op; + }; + + const std::array 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){<%instr.code.eachLine{%> + ${it}<%}%> + } + <%}%> + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) { + pc = pc + ((instr & 3) == 3 ? 4 : 2); + return pc; + } +}; + +template void debug_fn(CODE_WORD insn) { + volatile CODE_WORD x = insn; + insn = 2 * x; +} + +template vm_impl::vm_impl() { this(new ARCH()); } + +template +vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) +: vm_base(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 vm_base::virt_addr_t vm_impl::execute_inst(virt_addr_t start, std::function pred) { + // we fetch at max 4 byte, alignment is 2 + enum {TRAP_ID=1<<16}; + const typename traits::addr_t upper_bits = ~traits::PGMASK; + code_word_t insn = 0; + auto *const data = (uint8_t *)&insn; + auto pc=start; + while(pred){ + auto paddr = this->core.v2p(pc); + if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary + if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if ((insn & 0x3) == 0x3) // this is a 32bit instruction + if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val); + } else { + if (this->core.read(paddr, 4, data) != 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' + auto lut_val = extract_fields(insn); + auto f = qlut[insn & 0x3][lut_val]; + if (!f) + f = &this_class::illegal_intruction; + pc = (this->*f)(pc, insn); + } + return pc; +} + +} // namespace mnrv32 + +template <> +std::unique_ptr create(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { + auto ret = new ${coreDef.name.toLowerCase()}::vm_impl(*core, dump); + if (port != 0) debugger::server::run_server(ret, port); + return std::unique_ptr(ret); +} +} // namespace interp +} // namespace iss diff --git a/gen_input/templates/llvm/CORENAME_cyles.txt.gtl b/gen_input/templates/llvm/CORENAME_cyles.txt.gtl new file mode 100644 index 0000000..3a1ad8e --- /dev/null +++ b/gen_input/templates/llvm/CORENAME_cyles.txt.gtl @@ -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} + }<%}%> + ] +} \ No newline at end of file diff --git a/gen_input/templates/llvm/incl-CORENAME.h.gtl b/gen_input/templates/llvm/incl-CORENAME.h.gtl new file mode 100644 index 0000000..139d39d --- /dev/null +++ b/gen_input/templates/llvm/incl-CORENAME.h.gtl @@ -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 +#include +#include +#include + +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 reg_names{ + {"${getRegisterNames().join("\", \"")}"}}; + + static constexpr std::array 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; + + using phys_addr_t = iss::typed_addr_t; + + static constexpr std::array reg_bit_widths{ + {${regSizes.join(",")}}}; + + static constexpr std::array 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& value) override {} + void set_reg(short idx, const std::vector& 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(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 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_ */ diff --git a/gen_input/templates/llvm/src-CORENAME.cpp.gtl b/gen_input/templates/llvm/src-CORENAME.cpp.gtl new file mode 100644 index 0000000..6dee5fc --- /dev/null +++ b/gen_input/templates/llvm/src-CORENAME.cpp.gtl @@ -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 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif +#include +#include +#include + +using namespace iss::arch; + +constexpr std::array iss::arch::traits::reg_names; +constexpr std::array iss::arch::traits::reg_aliases; +constexpr std::array iss::arch::traits::reg_bit_widths; +constexpr std::array iss::arch::traits::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::NUM_REGS; ++i) set_reg(i, std::vector(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(®); +} + +${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 +} + diff --git a/gen_input/templates/vm-vm_CORENAME.cpp.gtl b/gen_input/templates/llvm/vm-vm_CORENAME.cpp.gtl similarity index 98% rename from gen_input/templates/vm-vm_CORENAME.cpp.gtl rename to gen_input/templates/llvm/vm-vm_CORENAME.cpp.gtl index bd0fc8d..e041cb4 100644 --- a/gen_input/templates/vm-vm_CORENAME.cpp.gtl +++ b/gen_input/templates/llvm/vm-vm_CORENAME.cpp.gtl @@ -49,19 +49,17 @@ namespace iss { namespace llvm { namespace fp_impl { -void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); -} +void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned); } namespace ${coreDef.name.toLowerCase()} { +using namespace ::llvm; using namespace iss::arch; -using namespace llvm; using namespace iss::debugger; -using namespace iss::vm::llvm; -template class vm_impl : public vm_base { +template class vm_impl : public vm::llvm::vm_base { public: - using super = typename iss::vm::llvm::vm_base; + using super = typename iss::llvm::vm_base; 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; @@ -323,5 +321,5 @@ std::unique_ptr create(arch::${coreD if (port != 0) debugger::server::run_server(ret, port); return std::unique_ptr(ret); } - +} // namespace llvm } // namespace iss diff --git a/gen_input/templates/tcc/incl-CORENAME.h.gtl b/gen_input/templates/tcc/incl-CORENAME.h.gtl index 139d39d..0a5b99f 100644 --- a/gen_input/templates/tcc/incl-CORENAME.h.gtl +++ b/gen_input/templates/tcc/incl-CORENAME.h.gtl @@ -172,6 +172,8 @@ struct ${coreDef.name.toLowerCase()}: public arch_if { inline bool should_stop() { return interrupt_sim; } + inline uint64_t stop_code() { 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(addr.access)&0x3]==address_type::PHYSICAL) { @@ -204,7 +206,7 @@ protected: std::array addr_mode; - bool interrupt_sim=false; + uint64_t interrupt_sim=0; <% def fcsr = allRegs.find {it.name=='FCSR'} if(fcsr != null) {%> diff --git a/gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl b/gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl index 3de4462..8d93371 100644 --- a/gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl +++ b/gen_input/templates/tcc/vm-vm_CORENAME.cpp.gtl @@ -35,9 +35,9 @@ #include #include #include -#include +#include #include -#include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -48,25 +48,19 @@ #include 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 class vm_impl : public vm_base { +template class vm_impl : public iss::tcc::vm_base { public: - using super = typename iss::vm::llvm::vm_base; + using super = typename iss::tcc::vm_base; 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 addr_t = typename super::addr_t; + using tu_builder = typename super::tu_builder; vm_impl(); @@ -86,45 +80,43 @@ protected: using this_class = vm_impl; using compile_ret_t = std::tuple; - using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&); + using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); inline const char *name(size_t index){return traits::reg_aliases.at(index);} - template inline ConstantInt *size(T type) { - return ConstantInt::get(getContext(), APInt(32, type->getType()->getScalarSizeInBits())); - } - - void setup_module(Module* m) override { + void setup_module(std::string m) override { super::setup_module(m); - iss::vm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::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 &, tu_builder&) override; + + void gen_trap_behavior(tu_builder& tu) override; + + void gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause); + + void gen_leave_trap(tu_builder& tu, unsigned lvl); + + void gen_wait(tu_builder& tu, unsigned type); + + inline void gen_trap_check(tu_builder& tu) { + tu("if(*trap_state!=0) goto trap_entry;"); } - 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::XLEN, pc.val), - this->get_type(traits::XLEN)); - this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); + inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) { + switch(reg_num){ + case traits::NEXT_PC: + tu("*next_pc = {:#x};", pc.val); + break; + case traits::PC: + tu("*pc = {:#x};", pc.val); + break; + default: + if(!tu.defined_regs[reg_num]){ + tu("reg_t* reg{:02d} = (reg_t*){:#x};", reg_num, reinterpret_cast(get_reg_ptr(reg_num))); + tu.defined_regs[reg_num]=true; + } + tu("*reg{:02d} = {:#x};", reg_num, pc.val); + } } // some compile time constants @@ -138,9 +130,9 @@ protected: std::array lut_00, lut_01, lut_10; std::array lut_11; - std::array qlut; + std::array qlut; - std::array lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; + std::array 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) { @@ -198,25 +190,19 @@ private: /* 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}<%}%> + compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){<%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::NEXT_PC), true), - get_reg_ptr(traits::PC), true); - this->builder.CreateStore( - this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits::ICOUNT), true), - this->gen_const(64U, 1)), - get_reg_ptr(traits::ICOUNT), true); + compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) { + vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size()); 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); + gen_raise_trap(tu, 0, 2); // illegal instruction trap + vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size()); + vm_impl::gen_trap_check(tu); return BRANCH; } }; @@ -243,7 +229,7 @@ vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) template std::tuple -vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstream& os) { +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; code_word_t insn = 0; @@ -269,53 +255,31 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, if (f == nullptr) { f = &this_class::illegal_intruction; } - return (this->*f)(pc, insn, this_block); + return (this->*f)(pc, insn, tu); } -template void vm_impl::gen_leave_behavior(BasicBlock *leave_blk) { - this->builder.SetInsertPoint(leave_blk); - this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits::NEXT_PC), false)); +template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { + tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); } -template void vm_impl::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::TRAP_STATE), true); - this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); +template void vm_impl::gen_leave_trap(tu_builder& tu, unsigned lvl) { + tu("leave_trap(core_ptr, {});", lvl); + tu.store(tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN),traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); } -template void vm_impl::gen_leave_trap(unsigned lvl) { - std::vector 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::CSR, (lvl << 8) + 0x41, traits::XLEN / 8); - this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); - this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); +template void vm_impl::gen_wait(tu_builder& tu, unsigned type) { } -template void vm_impl::gen_wait(unsigned type) { - std::vector args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; - this->builder.CreateCall(this->mod->getFunction("wait"), args); +template void vm_impl::gen_trap_behavior(tu_builder& tu) { + tu("trap_entry:"); + tu("enter_trap(core_ptr, *trap_state, *pc);"); + tu.store(tu.constant(std::numeric_limits::max(),32),traits::LAST_BRANCH); + tu("return *next_pc;"); } -template void vm_impl::gen_trap_behavior(BasicBlock *trap_blk) { - this->builder.SetInsertPoint(trap_blk); - auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits::TRAP_STATE), true); - this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), - get_reg_ptr(traits::LAST_BRANCH), false); - std::vector args{this->core_ptr, this->adj_to64(trap_state_val), - this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits::PC), false))}; - this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); - auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), false); - this->builder.CreateRet(trap_addr_val); -} - -template inline void vm_impl::gen_trap_check(BasicBlock *bb) { - auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits::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()} +} // namespace mnrv32 template <> std::unique_ptr create(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { diff --git a/incl/iss/arch/mnrv32.h b/incl/iss/arch/mnrv32.h index 82eac60..33f97ce 100644 --- a/incl/iss/arch/mnrv32.h +++ b/incl/iss/arch/mnrv32.h @@ -182,6 +182,8 @@ struct mnrv32: public arch_if { inline bool should_stop() { return interrupt_sim; } + inline uint64_t stop_code() { return interrupt_sim; } + inline phys_addr_t v2p(const iss::addr_t& addr){ if (addr.space != traits::MEM || addr.type == iss::address_type::PHYSICAL || addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { @@ -238,7 +240,7 @@ protected: std::array addr_mode; - bool interrupt_sim=false; + uint64_t interrupt_sim=0; uint32_t get_fcsr(){return 0;} void set_fcsr(uint32_t val){} diff --git a/incl/iss/arch/riscv_hart_msu_vp.h b/incl/iss/arch/riscv_hart_msu_vp.h index 53ec877..81cc622 100644 --- a/incl/iss/arch/riscv_hart_msu_vp.h +++ b/incl/iss/arch/riscv_hart_msu_vp.h @@ -657,10 +657,12 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ const uint64_t addr, const unsigned length, uint8_t *const data) { #ifndef NDEBUG if (access && iss::access_type::DEBUG) { - LOG(TRACE) << "debug read of " << length << " bytes @addr " << addr; + LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; + } else if(access && iss::access_type::FETCH){ + LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; } else { - LOG(TRACE) << "read of " << length << " bytes @addr " << addr; - } + LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; + } #endif try { switch (space) { @@ -738,19 +740,19 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access switch (length) { case 8: LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec - << ") @addr " << addr; + << ") @addr 0x" << std::hex << addr; break; case 4: LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t *)&data[0] << std::dec - << ") @addr " << addr; + << ") @addr 0x" << std::hex << addr; break; case 2: LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t *)&data[0] << std::dec - << ") @addr " << addr; + << ") @addr 0x" << std::hex << addr; break; case 1: LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec - << ") @addr " << addr; + << ") @addr 0x" << std::hex << addr; break; default: LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; @@ -1082,7 +1084,10 @@ iss::status riscv_hart_msu_vp::write_mem(phys_addr_t paddr, unsigned lengt LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar << "), stopping simulation"; } - throw(iss::simulation_stopped(hostvar)); + this->reg.trap_state=std::numeric_limits::max(); + this->interrupt_sim=hostvar; + break; + //throw(iss::simulation_stopped(hostvar)); case 0x0101: { char c = static_cast(hostvar & 0xff); if (c == '\n' || c == 0) { @@ -1313,8 +1318,9 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f this->reg.trap_state = 0; std::array buffer; sprintf(buffer.data(), "0x%016lx", addr); + if((flags&0xffffffff) != 0xffffffff) CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" - << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << trap_id << ")" + << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")" << " at address " << buffer.data() << " occurred, changing privilege level from " << lvl[cur_priv] << " to " << lvl[new_priv]; update_vm_info(); diff --git a/incl/sysc/core_complex.h b/incl/sysc/core_complex.h index bb27492..bef6804 100644 --- a/incl/sysc/core_complex.h +++ b/incl/sysc/core_complex.h @@ -75,8 +75,6 @@ class core_wrapper; class core_complex : public sc_core::sc_module, public scc::traceable { public: - SC_HAS_PROCESS(core_complex);// NOLINT - scc::initiator_mixin> initiator; sc_core::sc_in clk_i; diff --git a/softfloat/CMakeLists.txt b/softfloat/CMakeLists.txt index 8c13151..db9892e 100644 --- a/softfloat/CMakeLists.txt +++ b/softfloat/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.12) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) # main (top) cmake dir set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project specific cmake dir diff --git a/src/main.cpp b/src/main.cpp index cf6c92e..fc63ae3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,10 +36,7 @@ #include #include #include -#include -#include -#include -#include +#include #include #include #include @@ -66,6 +63,7 @@ int main(int argc, char *argv[]) { ("elf", po::value>(), "ELF file(s) to load") ("mem,m", po::value(), "the memory input file") ("plugin,p", po::value>(), "plugin to activate") + ("backend", po::value()->default_value("tcc"), "the memory input file") ("isa", po::value()->default_value("rv32gc"), "isa to use for simulation"); // clang-format on auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); @@ -85,6 +83,8 @@ int main(int argc, char *argv[]) { } std::vector args = collect_unrecognized(parsed.options, po::include_positional); + LOGGER(DEFAULT)::print_time() = false; + LOGGER(connection)::print_time() = false; if (clim.count("verbose")) { auto l = logging::as_log_level(clim["verbose"].as()); LOGGER(DEFAULT)::reporting_level() = l; @@ -107,26 +107,14 @@ int main(int argc, char *argv[]) { std::unique_ptr vm{nullptr}; std::unique_ptr cpu{nullptr}; std::string isa_opt(clim["isa"].as()); -// if (isa_opt=="rv64ia") { -// iss::arch::rv64i* lcpu = new iss::arch::riscv_hart_msu_vp(); -// vm = iss::llvm::create(lcpu, clim["gdb-port"].as()); -// cpu.reset(lcpu); -// } else if (isa_opt=="rv64gc") { -// iss::arch::rv64gc* lcpu = new iss::arch::riscv_hart_msu_vp(); -// vm = iss::llvm::create(lcpu, clim["gdb-port"].as()); -// cpu.reset(lcpu); -// } else if (isa_opt=="rv32imac") { - iss::arch::rv32imac* lcpu = new iss::arch::riscv_hart_msu_vp(); + iss::arch::mnrv32* lcpu = new iss::arch::riscv_hart_msu_vp(); + if(clim["backend"].as() == "interp") + vm = iss::interp::create(lcpu, clim["gdb-port"].as()); + if(clim["backend"].as() == "llvm") vm = iss::llvm::create(lcpu, clim["gdb-port"].as()); - cpu.reset(lcpu); -// } else if (isa_opt=="rv32gc") { -// iss::arch::rv32gc* lcpu = new iss::arch::riscv_hart_msu_vp(); -// vm = iss::llvm::create(lcpu, clim["gdb-port"].as()); -// cpu.reset(lcpu); -// } else { -// LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as() << std::endl; -// return 127; -// } + if(clim["backend"].as() == "tcc") + vm = iss::tcc::create(lcpu, clim["gdb-port"].as()); + cpu.reset(lcpu); if (clim.count("plugin")) { for (std::string opt_val : clim["plugin"].as>()) { std::string plugin_name{opt_val}; @@ -153,16 +141,16 @@ int main(int argc, char *argv[]) { if (clim.count("disass")) { vm->setDisassEnabled(true); LOGGER(disass)::reporting_level() = logging::INFO; + LOGGER(disass)::print_time() = false; auto file_name = clim["disass"].as(); if (file_name.length() > 0) { LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w"); - LOGGER(disass)::print_time() = false; LOGGER(disass)::print_severity() = false; } } uint64_t start_address = 0; if (clim.count("mem")) - vm->get_arch()->load_file(clim["mem"].as(), iss::arch::traits::MEM); + vm->get_arch()->load_file(clim["mem"].as(), iss::arch::traits::MEM); if (clim.count("elf")) for (std::string input : clim["elf"].as>()) { auto start_addr = vm->get_arch()->load_file(input); diff --git a/src/sysc/core_complex.cpp b/src/sysc/core_complex.cpp index 24bbb88..7061dc9 100644 --- a/src/sysc/core_complex.cpp +++ b/src/sysc/core_complex.cpp @@ -32,7 +32,8 @@ #include "sysc/core_complex.h" #include "iss/arch/riscv_hart_msu_vp.h" -#include "iss/arch/rv32imac.h" +//#include "iss/arch/rv32imac.h" +#include "iss/arch/mnrv32.h" #include "iss/debugger/encoderdecoder.h" #include "iss/debugger/gdb_session.h" #include "iss/debugger/server.h" @@ -59,6 +60,9 @@ namespace { iss::debugger::encoder_decoder encdec; } +//using core_type = iss::arch::rv32imac; +using core_type = iss::arch::mnrv32; + namespace { std::array lvl = {{'U', 'S', 'H', 'M'}}; @@ -87,11 +91,10 @@ std::array irq_str = { { "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt" } }; } -class core_wrapper : public iss::arch::riscv_hart_msu_vp { +class core_wrapper : public iss::arch::riscv_hart_msu_vp { public: - using core_type = arch::rv32imac; - using base_type = arch::riscv_hart_msu_vp; - using phys_addr_t = typename arch::traits::phys_addr_t; + using base_type = arch::riscv_hart_msu_vp; + using phys_addr_t = typename arch::traits::phys_addr_t; core_wrapper(core_complex *owner) : owner(owner) { @@ -99,7 +102,7 @@ public: uint32_t get_mode() { return this->reg.machine_state; } - inline void set_interrupt_execution(bool v) { this->interrupt_sim = v; } + inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; } inline bool get_interrupt_execution() { return this->interrupt_sim; } @@ -252,6 +255,7 @@ core_complex::core_complex(sc_module_name name) , fetch_tr_handle(nullptr) #endif { + SC_HAS_PROCESS(core_complex);// NOLINT initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void { auto lut_entry = read_lut.getEntry(start); if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { @@ -282,7 +286,7 @@ void core_complex::trace(sc_trace_file *trf) const {} void core_complex::before_end_of_elaboration() { cpu = scc::make_unique(this); - vm = llvm::create(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value()); + vm = llvm::create(cpu.get(), gdb_server_port.get_value(), dump_ir.get_value()); #ifdef WITH_SCV vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr); #else diff --git a/src/vm/interp/vm_mnrv32.cpp b/src/vm/interp/vm_mnrv32.cpp new file mode 100644 index 0000000..f0cf95c --- /dev/null +++ b/src/vm/interp/vm_mnrv32.cpp @@ -0,0 +1,2982 @@ +/******************************************************************************* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include + +#include +#include + +namespace iss { +namespace interp { +namespace mnrv32 { +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::interp::vm_base { +public: + using super = typename iss::interp::vm_base; + 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 reg_t = typename traits::reg_t; + using iss::interp::vm_base::get_reg; + + 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 (super::tgt_adapter == nullptr) + super::tgt_adapter = new riscv_target_adapter(srv, this->get_arch()); + return super::tgt_adapter; + } + +protected: + using this_class = vm_impl; + using compile_ret_t = virt_addr_t; + using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr); + + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + virt_addr_t execute_inst(virt_addr_t start, std::function pred) override; + + // 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 lut; + + std::array lut_00, lut_01, lut_10; + std::array lut_11; + + std::array qlut; + + std::array 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; + } + + void raise_trap(uint16_t trap_id, uint16_t cause){ + auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id; + this->template get_reg(arch::traits::TRAP_STATE) = trap_val; + this->template get_reg(arch::traits::NEXT_PC) = std::numeric_limits::max(); + } + + void leave_trap(unsigned lvl){ + this->core.leave_trap(lvl); + auto pc_val = super::template read_mem(traits::CSR, (lvl << 8) + 0x41); + this->template get_reg(arch::traits::NEXT_PC) = pc_val; + this->template get_reg(arch::traits::LAST_BRANCH) = std::numeric_limits::max(); + } + + void wait(unsigned type){ + this->core.wait_until(type); + } + + +private: + /**************************************************************************** + * start opcode definitions + ****************************************************************************/ + struct InstructionDesriptor { + size_t length; + uint32_t value; + uint32_t mask; + compile_func op; + }; + + const std::array 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 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 definitions */ + /* instruction 0: LUI */ + compile_ret_t __lui(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 0); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (imm); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 0); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 1: AUIPC */ + compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 1); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(cur_pc_val) + (imm)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 1); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 2: JAL */ + compile_ret_t __jal(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 2); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,8>(instr) << 12) | (bit_sub<20,1>(instr) << 11) | (bit_sub<21,10>(instr) << 1) | (bit_sub<31,1>(instr) << 20)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (cur_pc_val + 4); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + auto PC_val = (static_cast(cur_pc_val) + (imm)); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 2); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 3: JALR */ + compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 3); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto new_pc_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + if(rd != 0){ + auto Xtmp0_val = (cur_pc_val + 4); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + auto PC_val = (new_pc_val & ~(0x1)); + super::template get_reg(traits::NEXT_PC) = PC_val; + super::template get_reg(traits::LAST_BRANCH) = std::numeric_limits::max(); + this->do_sync(POST_SYNC, 3); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 4: BEQ */ + compile_ret_t __beq(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 4); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto PC_val = (super::template get_reg(rs1 + traits::X0) == super::template get_reg(rs2 + traits::X0))? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 4); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 4); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 5: BNE */ + compile_ret_t __bne(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 5); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto PC_val = (super::template get_reg(rs1 + traits::X0) != super::template get_reg(rs2 + traits::X0))? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 4); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 5); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 6: BLT */ + compile_ret_t __blt(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 6); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto PC_val = (static_cast(super::template get_reg(rs1 + traits::X0)) < static_cast(super::template get_reg(rs2 + traits::X0)))? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 4); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 6); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 7: BGE */ + compile_ret_t __bge(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 7); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto PC_val = (static_cast(super::template get_reg(rs1 + traits::X0)) >= static_cast(super::template get_reg(rs2 + traits::X0)))? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 4); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 7); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 8: BLTU */ + compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 8); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto PC_val = (super::template get_reg(rs1 + traits::X0) < super::template get_reg(rs2 + traits::X0))? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 4); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 8); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 9: BGEU */ + compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 9); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto PC_val = (super::template get_reg(rs1 + traits::X0) >= super::template get_reg(rs2 + traits::X0))? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 4); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 9); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 10: LB */ + compile_ret_t __lb(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 10); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + if(rd != 0){ + auto Xtmp0_val = super::template sext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 10); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 11: LH */ + compile_ret_t __lh(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 11); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + if(rd != 0){ + auto Xtmp0_val = super::template sext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 11); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 12: LW */ + compile_ret_t __lw(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 12); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + if(rd != 0){ + auto Xtmp0_val = super::template sext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 12); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 13: LBU */ + compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 13); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + if(rd != 0){ + auto Xtmp0_val = super::template zext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 13); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 14: LHU */ + compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 14); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + if(rd != 0){ + auto Xtmp0_val = super::template zext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 14); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 15: SB */ + compile_ret_t __sb(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 15); + + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + auto MEMtmp0_val = super::template get_reg(rs2 + traits::X0); + super::write_mem(traits::MEM, offs_val, static_cast(MEMtmp0_val)); + this->do_sync(POST_SYNC, 15); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 16: SH */ + compile_ret_t __sh(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 16); + + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + auto MEMtmp0_val = super::template get_reg(rs2 + traits::X0); + super::write_mem(traits::MEM, offs_val, static_cast(MEMtmp0_val)); + this->do_sync(POST_SYNC, 16); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 17: SW */ + compile_ret_t __sw(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 17); + + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto offs_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + auto MEMtmp0_val = super::template get_reg(rs2 + traits::X0); + super::write_mem(traits::MEM, offs_val, static_cast(MEMtmp0_val)); + this->do_sync(POST_SYNC, 17); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 18: ADDI */ + compile_ret_t __addi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 18); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "addi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 18); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 19: SLTI */ + compile_ret_t __slti(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 19); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "slti"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) < (imm))? + 1: + 0; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 19); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 20: SLTIU */ + compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 20); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "sltiu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + int32_t full_imm_val = imm; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0) < full_imm_val)? + 1: + 0; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 20); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 21: XORI */ + compile_ret_t __xori(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 21); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "xori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) ^ (imm)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 21); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 22: ORI */ + compile_ret_t __ori(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 22); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "ori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) | (imm)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 22); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 23: ANDI */ + compile_ret_t __andi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 23); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "andi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) & (imm)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 23); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 24: SLLI */ + compile_ret_t __slli(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 24); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(shamt > 31){ + raise_trap(0, 0); + } else { + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0)<<(shamt)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + } + this->do_sync(POST_SYNC, 24); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 25: SRLI */ + compile_ret_t __srli(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 25); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(shamt > 31){ + raise_trap(0, 0); + } else { + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0))>>(shamt)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + } + this->do_sync(POST_SYNC, 25); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 26: SRAI */ + compile_ret_t __srai(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 26); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(shamt > 31){ + raise_trap(0, 0); + } else { + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0))>>(shamt)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + } + this->do_sync(POST_SYNC, 26); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 27: ADD */ + compile_ret_t __add(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 27); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0) + super::template get_reg(rs2 + traits::X0)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 27); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 28: SUB */ + compile_ret_t __sub(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 28); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0) - super::template get_reg(rs2 + traits::X0)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 28); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 29: SLL */ + compile_ret_t __sll(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 29); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0)<<(super::template get_reg(rs2 + traits::X0) & ((32) - 1))); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 29); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 30: SLT */ + compile_ret_t __slt(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 30); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) < static_cast(super::template get_reg(rs2 + traits::X0)))? + 1: + 0; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 30); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 31: SLTU */ + compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 31); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template zext(super::template get_reg(rs1 + traits::X0)) < super::template zext(super::template get_reg(rs2 + traits::X0)))? + 1: + 0; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 31); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 32: XOR */ + compile_ret_t __xor(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 32); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0) ^ super::template get_reg(rs2 + traits::X0)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 32); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 33: SRL */ + compile_ret_t __srl(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 33); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0))>>(super::template get_reg(rs2 + traits::X0) & ((32) - 1))); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 33); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 34: SRA */ + compile_ret_t __sra(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 34); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0))>>(super::template get_reg(rs2 + traits::X0) & ((32) - 1))); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 34); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 35: OR */ + compile_ret_t __or(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 35); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0) | super::template get_reg(rs2 + traits::X0)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 35); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 36: AND */ + compile_ret_t __and(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 36); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0) & super::template get_reg(rs2 + traits::X0)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + this->do_sync(POST_SYNC, 36); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 37: FENCE */ + compile_ret_t __fence(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 37); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t succ = ((bit_sub<20,4>(instr))); + uint8_t pred = ((bit_sub<24,4>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "fence"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto FENCEtmp0_val = (((pred) << 4) | (succ)); + super::write_mem(traits::FENCE, (0), static_cast(FENCEtmp0_val)); + this->do_sync(POST_SYNC, 37); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 38: FENCE_I */ + compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 38); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t imm = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "fence_i"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto FENCEtmp0_val = (imm); + super::write_mem(traits::FENCE, (1), static_cast(FENCEtmp0_val)); + this->do_sync(POST_SYNC, 38); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 39: ECALL */ + compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 39); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "ecall"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + raise_trap(0, 11); + this->do_sync(POST_SYNC, 39); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 40: EBREAK */ + compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 40); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "ebreak"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + raise_trap(0, 3); + this->do_sync(POST_SYNC, 40); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 41: URET */ + compile_ret_t __uret(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 41); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "uret"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + leave_trap(0); + this->do_sync(POST_SYNC, 41); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 42: SRET */ + compile_ret_t __sret(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 42); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "sret"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + leave_trap(1); + this->do_sync(POST_SYNC, 42); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 43: MRET */ + compile_ret_t __mret(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 43); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "mret"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + leave_trap(3); + this->do_sync(POST_SYNC, 43); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 44: WFI */ + compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 44); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "wfi"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + wait(1); + this->do_sync(POST_SYNC, 44); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 45: SFENCE.VMA */ + compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 45); + + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "sfence.vma"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto FENCEtmp0_val = (rs1); + super::write_mem(traits::FENCE, (2), static_cast(FENCEtmp0_val)); + auto FENCEtmp1_val = (rs2); + super::write_mem(traits::FENCE, (3), static_cast(FENCEtmp1_val)); + this->do_sync(POST_SYNC, 45); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 46: CSRRW */ + compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 46); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto rs_val_val = super::template get_reg(rs1 + traits::X0); + if(rd != 0){ + auto csr_val_val = super::template read_mem(traits::CSR, (csr)); + auto CSRtmp0_val = rs_val_val; + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp0_val)); + auto Xtmp1_val = csr_val_val; + super::template get_reg(rd + traits::X0)=Xtmp1_val; + } else { + auto CSRtmp2_val = rs_val_val; + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp2_val)); + } + this->do_sync(POST_SYNC, 46); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 47: CSRRS */ + compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 47); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto xrd_val = super::template read_mem(traits::CSR, (csr)); + auto xrs1_val = super::template get_reg(rs1 + traits::X0); + if(rd != 0){ + auto Xtmp0_val = xrd_val; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + if(rs1 != 0){ + auto CSRtmp1_val = (xrd_val | xrs1_val); + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp1_val)); + } + this->do_sync(POST_SYNC, 47); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 48: CSRRC */ + compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 48); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto xrd_val = super::template read_mem(traits::CSR, (csr)); + auto xrs1_val = super::template get_reg(rs1 + traits::X0); + if(rd != 0){ + auto Xtmp0_val = xrd_val; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + if(rs1 != 0){ + auto CSRtmp1_val = (xrd_val & ~(xrs1_val)); + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp1_val)); + } + this->do_sync(POST_SYNC, 48); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 49: CSRRWI */ + compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 49); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + if(rd != 0){ + auto Xtmp0_val = super::template read_mem(traits::CSR, (csr)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + auto CSRtmp1_val = super::template zext((zimm)); + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp1_val)); + this->do_sync(POST_SYNC, 49); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 50: CSRRSI */ + compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 50); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto res_val = super::template read_mem(traits::CSR, (csr)); + if(zimm != 0){ + auto CSRtmp0_val = (res_val | super::template zext((zimm))); + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp0_val)); + } + if(rd != 0){ + auto Xtmp1_val = res_val; + super::template get_reg(rd + traits::X0)=Xtmp1_val; + } + this->do_sync(POST_SYNC, 50); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 51: CSRRCI */ + compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 51); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 4; + auto res_val = super::template read_mem(traits::CSR, (csr)); + if(rd != 0){ + auto Xtmp0_val = res_val; + super::template get_reg(rd + traits::X0)=Xtmp0_val; + } + if(zimm != 0){ + auto CSRtmp1_val = (res_val & ~(super::template zext((zimm)))); + super::write_mem(traits::CSR, (csr), static_cast(CSRtmp1_val)); + } + this->do_sync(POST_SYNC, 51); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 52: C.ADDI4SPN */ + compile_ret_t __c_addi4spn(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 52); + + uint8_t rd = ((bit_sub<2,3>(instr))); + uint16_t imm = ((bit_sub<5,1>(instr) << 3) | (bit_sub<6,1>(instr) << 2) | (bit_sub<7,4>(instr) << 6) | (bit_sub<11,2>(instr) << 4)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.addi4spn"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + if(imm == 0){ + raise_trap(0, 2); + } + auto Xtmp0_val = (super::template get_reg(2 + traits::X0) + (imm)); + super::template get_reg(rd + 8 + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 52); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 53: C.LW */ + compile_ret_t __c_lw(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 53); + + uint8_t rd = ((bit_sub<2,3>(instr))); + uint8_t uimm = ((bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.lw"), + fmt::arg("rd", name(8+rd)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto offs_val = (super::template get_reg(rs1 + 8 + traits::X0) + (uimm)); + auto Xtmp0_val = super::template sext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + 8 + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 53); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 54: C.SW */ + compile_ret_t __c_sw(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 54); + + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t uimm = ((bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.sw"), + fmt::arg("rs2", name(8+rs2)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto offs_val = (super::template get_reg(rs1 + 8 + traits::X0) + (uimm)); + auto MEMtmp0_val = super::template get_reg(rs2 + 8 + traits::X0); + super::write_mem(traits::MEM, offs_val, static_cast(MEMtmp0_val)); + this->do_sync(POST_SYNC, 54); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 55: C.ADDI */ + compile_ret_t __c_addi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 55); + + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.addi"), + fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto Xtmp0_val = (static_cast(super::template get_reg(rs1 + traits::X0)) + (imm)); + super::template get_reg(rs1 + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 55); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 56: C.NOP */ + compile_ret_t __c_nop(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 56); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "c.nop"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + /* TODO: describe operations for C.NOP ! */ + this->do_sync(POST_SYNC, 56); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 57: C.JAL */ + compile_ret_t __c_jal(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 57); + + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (bit_sub<12,1>(instr) << 11)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.jal"), + fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto Xtmp0_val = (cur_pc_val + 2); + super::template get_reg(1 + traits::X0)=Xtmp0_val; + auto PC_val = (static_cast(cur_pc_val) + (imm)); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 57); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 58: C.LI */ + compile_ret_t __c_li(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 58); + + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.li"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + if(rd == 0){ + raise_trap(0, 2); + } + auto Xtmp0_val = (imm); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 58); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 59: C.LUI */ + compile_ret_t __c_lui(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 59); + + int32_t imm = signextend((bit_sub<2,5>(instr) << 12) | (bit_sub<12,1>(instr) << 17)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + if(rd == 0){ + raise_trap(0, 2); + } + if(imm == 0){ + raise_trap(0, 2); + } + auto Xtmp0_val = (imm); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 59); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 60: C.ADDI16SP */ + compile_ret_t __c_addi16sp(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 60); + + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 7) | (bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 4) | (bit_sub<12,1>(instr) << 9)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.addi16sp"), + fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto Xtmp0_val = (static_cast(super::template get_reg(2 + traits::X0)) + (imm)); + super::template get_reg(2 + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 60); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 61: C.SRLI */ + compile_ret_t __c_srli(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 61); + + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srli"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rs1_idx_val = rs1 + 8; + auto Xtmp0_val = (static_cast(super::template get_reg(rs1_idx_val + traits::X0))>>(shamt)); + super::template get_reg(rs1_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 61); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 62: C.SRAI */ + compile_ret_t __c_srai(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 62); + + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srai"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rs1_idx_val = rs1 + 8; + auto Xtmp0_val = (static_cast(super::template get_reg(rs1_idx_val + traits::X0))>>(shamt)); + super::template get_reg(rs1_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 62); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 63: C.ANDI */ + compile_ret_t __c_andi(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 63); + + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.andi"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rs1_idx_val = rs1 + 8; + auto Xtmp0_val = (static_cast(super::template get_reg(rs1_idx_val + traits::X0)) & (imm)); + super::template get_reg(rs1_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 63); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 64: C.SUB */ + compile_ret_t __c_sub(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 64); + + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.sub"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val = (super::template get_reg(rd_idx_val + traits::X0) - super::template get_reg(rs2 + 8 + traits::X0)); + super::template get_reg(rd_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 64); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 65: C.XOR */ + compile_ret_t __c_xor(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 65); + + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.xor"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val = (super::template get_reg(rd_idx_val + traits::X0) ^ super::template get_reg(rs2 + 8 + traits::X0)); + super::template get_reg(rd_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 65); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 66: C.OR */ + compile_ret_t __c_or(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 66); + + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.or"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val = (super::template get_reg(rd_idx_val + traits::X0) | super::template get_reg(rs2 + 8 + traits::X0)); + super::template get_reg(rd_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 66); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 67: C.AND */ + compile_ret_t __c_and(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 67); + + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.and"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val = (super::template get_reg(rd_idx_val + traits::X0) & super::template get_reg(rs2 + 8 + traits::X0)); + super::template get_reg(rd_idx_val + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 67); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 68: C.J */ + compile_ret_t __c_j(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 68); + + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (bit_sub<12,1>(instr) << 11)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.j"), + fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto PC_val = (static_cast(cur_pc_val) + (imm)); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 68); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 69: C.BEQZ */ + compile_ret_t __c_beqz(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 69); + + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.beqz"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto PC_val = (super::template get_reg(rs1 + 8 + traits::X0) == 0)? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 2); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 69); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 70: C.BNEZ */ + compile_ret_t __c_bnez(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 70); + + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.bnez"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto PC_val = (super::template get_reg(rs1 + 8 + traits::X0) != 0)? + (static_cast(cur_pc_val) + (imm)): + (cur_pc_val + 2); + super::template get_reg(traits::NEXT_PC) = PC_val; + auto is_cont_v = PC_val !=pc.val; + super::template get_reg(traits::LAST_BRANCH) = is_cont_v?1:0; + this->do_sync(POST_SYNC, 70); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 71: C.SLLI */ + compile_ret_t __c_slli(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 71); + + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.slli"), + fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + if(rs1 == 0){ + raise_trap(0, 2); + } + auto Xtmp0_val = (super::template get_reg(rs1 + traits::X0)<<(shamt)); + super::template get_reg(rs1 + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 71); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 72: C.LWSP */ + compile_ret_t __c_lwsp(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 72); + + uint8_t uimm = ((bit_sub<2,2>(instr) << 6) | (bit_sub<4,3>(instr) << 2) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, sp, {uimm:#05x}", fmt::arg("mnemonic", "c.lwsp"), + fmt::arg("rd", name(rd)), fmt::arg("uimm", uimm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto offs_val = (super::template get_reg(2 + traits::X0) + (uimm)); + auto Xtmp0_val = super::template sext(super::template read_mem(traits::MEM, offs_val)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 72); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 73: C.MV */ + compile_ret_t __c_mv(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 73); + + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.mv"), + fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto Xtmp0_val = super::template get_reg(rs2 + traits::X0); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 73); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 74: C.JR */ + compile_ret_t __c_jr(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 74); + + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jr"), + fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto PC_val = super::template get_reg(rs1 + traits::X0); + super::template get_reg(traits::NEXT_PC) = PC_val; + super::template get_reg(traits::LAST_BRANCH) = std::numeric_limits::max(); + this->do_sync(POST_SYNC, 74); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 75: C.ADD */ + compile_ret_t __c_add(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 75); + + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.add"), + fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto Xtmp0_val = (super::template get_reg(rd + traits::X0) + super::template get_reg(rs2 + traits::X0)); + super::template get_reg(rd + traits::X0)=Xtmp0_val; + this->do_sync(POST_SYNC, 75); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 76: C.JALR */ + compile_ret_t __c_jalr(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 76); + + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jalr"), + fmt::arg("rs1", name(rs1))); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto Xtmp0_val = (cur_pc_val + 2); + super::template get_reg(1 + traits::X0)=Xtmp0_val; + auto PC_val = super::template get_reg(rs1 + traits::X0); + super::template get_reg(traits::NEXT_PC) = PC_val; + super::template get_reg(traits::LAST_BRANCH) = std::numeric_limits::max(); + this->do_sync(POST_SYNC, 76); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 77: C.EBREAK */ + compile_ret_t __c_ebreak(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 77); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "c.ebreak"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + raise_trap(0, 3); + this->do_sync(POST_SYNC, 77); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 78: C.SWSP */ + compile_ret_t __c_swsp(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 78); + + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t uimm = ((bit_sub<7,2>(instr) << 6) | (bit_sub<9,4>(instr) << 2)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {uimm:#05x}(sp)", fmt::arg("mnemonic", "c.swsp"), + fmt::arg("rs2", name(rs2)), fmt::arg("uimm", uimm)); + this->core.disass_output(pc.val, mnemonic); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + auto offs_val = (super::template get_reg(2 + traits::X0) + (uimm)); + auto MEMtmp0_val = super::template get_reg(rs2 + traits::X0); + super::write_mem(traits::MEM, offs_val, static_cast(MEMtmp0_val)); + this->do_sync(POST_SYNC, 78); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /* instruction 79: DII */ + compile_ret_t __dii(virt_addr_t& pc, code_word_t instr){ + this->do_sync(PRE_SYNC, 79); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + this->core.disass_output(pc.val, "dii"); + } + + auto cur_pc_val = pc.val; + super::template get_reg(arch::traits::NEXT_PC) = cur_pc_val + 2; + raise_trap(0, 2); + this->do_sync(POST_SYNC, 79); + auto& trap_state = super::template get_reg(arch::traits::TRAP_STATE); + // trap check + if(trap_state!=0){ + auto& last_br = super::template get_reg(arch::traits::LAST_BRANCH); + last_br = std::numeric_limits::max(); + super::core.enter_trap(trap_state, cur_pc_val); + } + pc.val=super::template get_reg(arch::traits::NEXT_PC); + return pc; + } + + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) { + pc = pc + ((instr & 3) == 3 ? 4 : 2); + return pc; + } +}; + +template void debug_fn(CODE_WORD insn) { + volatile CODE_WORD x = insn; + insn = 2 * x; +} + +template vm_impl::vm_impl() { this(new ARCH()); } + +template +vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) +: vm_base(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 vm_base::virt_addr_t vm_impl::execute_inst(virt_addr_t start, std::function pred) { + // we fetch at max 4 byte, alignment is 2 + enum {TRAP_ID=1<<16}; + const typename traits::addr_t upper_bits = ~traits::PGMASK; + code_word_t insn = 0; + auto *const data = (uint8_t *)&insn; + auto pc=start; + while(pred){ + auto paddr = this->core.v2p(pc); + if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary + if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if ((insn & 0x3) == 0x3) // this is a 32bit instruction + if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val); + } else { + if (this->core.read(paddr, 4, data) != 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' + auto lut_val = extract_fields(insn); + auto f = qlut[insn & 0x3][lut_val]; + if (!f) + f = &this_class::illegal_intruction; + pc = (this->*f)(pc, insn); + } + return pc; +} + +} // namespace mnrv32 + +template <> +std::unique_ptr create(arch::mnrv32 *core, unsigned short port, bool dump) { + auto ret = new mnrv32::vm_impl(*core, dump); + if (port != 0) debugger::server::run_server(ret, port); + return std::unique_ptr(ret); +} +} // namespace interp +} // namespace iss diff --git a/src/vm/llvm/fp_functions.cpp b/src/vm/llvm/fp_functions.cpp index 1f0169a..ce5bc66 100644 --- a/src/vm/llvm/fp_functions.cpp +++ b/src/vm/llvm/fp_functions.cpp @@ -44,10 +44,11 @@ extern "C" { #include namespace iss { -namespace vm { +namespace llvm { namespace fp_impl { using namespace std; +using namespace ::llvm; #define INT_TYPE(L) Type::getIntNTy(mod->getContext(), L) #define FLOAT_TYPE Type::getFloatTy(mod->getContext()) @@ -65,10 +66,9 @@ using namespace std; #define FDECL(NAME, RET, ...) \ std::vector NAME##_args{__VA_ARGS__}; \ - FunctionType *NAME##_type = llvm::FunctionType::get(RET, NAME##_args, false); \ + FunctionType *NAME##_type = FunctionType::get(RET, NAME##_args, false); \ mod->getOrInsertFunction(#NAME, NAME##_type); -using namespace llvm; void add_fp_functions_2_module(Module *mod, uint32_t flen, uint32_t xlen) { if(flen){ diff --git a/src/vm/llvm/vm_mnrv32.cpp b/src/vm/llvm/vm_mnrv32.cpp new file mode 100644 index 0000000..428b618 --- /dev/null +++ b/src/vm/llvm/vm_mnrv32.cpp @@ -0,0 +1,2582 @@ +/******************************************************************************* + * 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 +#include +#include +#include +#include +#include +#include + +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include + +#include +#include + +namespace iss { +namespace llvm { +namespace fp_impl { +void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned); +} + +namespace mnrv32 { +using namespace ::llvm; +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::llvm::vm_base { +public: + using super = typename iss::llvm::vm_base; + 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::tgt_adapter == nullptr) + vm_base::tgt_adapter = new riscv_target_adapter(srv, this->get_arch()); + return vm_base::tgt_adapter; + } + +protected: + using vm_base::get_reg_ptr; + + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + template 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::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::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)); + } + + std::tuple gen_single_inst_behavior(virt_addr_t &, unsigned int &, BasicBlock *) 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::XLEN, pc.val), + this->get_type(traits::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) }; + + using this_class = vm_impl; + using compile_func = std::tuple (this_class::*)(virt_addr_t &pc, + code_word_t instr, + BasicBlock *bb); + std::array lut; + + std::array lut_00, lut_01, lut_10; + std::array lut_11; + + std::array qlut; + + std::array 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 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 */ + std::tuple __lui(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("LUI"); + + this->gen_sync(PRE_SYNC, 0); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->gen_const(32U, imm); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 0); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 1: AUIPC */ + std::tuple __auipc(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("AUIPC"); + + this->gen_sync(PRE_SYNC, 1); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 1); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 2: JAL */ + std::tuple __jal(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("JAL"); + + this->gen_sync(PRE_SYNC, 2); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,8>(instr) << 12) | (bit_sub<20,1>(instr) << 11) | (bit_sub<21,10>(instr) << 1) | (bit_sub<31,1>(instr) << 20)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + Value* PC_val = this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 2); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 3: JALR */ + std::tuple __jalr(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("JALR"); + + this->gen_sync(PRE_SYNC, 3); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* new_pc_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + Value* align_val = this->builder.CreateAnd( + new_pc_val, + this->gen_const(32U, 0x2)); + { + BasicBlock* bbnext = BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk); + BasicBlock* bb_then = BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext); + BasicBlock* bb_else = BasicBlock::Create(this->mod->getContext(), "elsebr", this->func, bbnext); + // this->builder.SetInsertPoint(bb); + this->gen_cond_branch(this->builder.CreateICmp( + ICmpInst::ICMP_NE, + align_val, + this->gen_const(32U, 0)), + bb_then, + bb_else); + this->builder.SetInsertPoint(bb_then); + { + this->gen_raise_trap(0, 0); + } + this->builder.CreateBr(bbnext); + this->builder.SetInsertPoint(bb_else); + { + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + Value* PC_val = this->builder.CreateAnd( + new_pc_val, + this->builder.CreateNot(this->gen_const(32U, 0x1))); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); + } + this->builder.CreateBr(bbnext); + bb=bbnext; + } + this->builder.SetInsertPoint(bb); + this->gen_sync(POST_SYNC, 3); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 4: BEQ */ + std::tuple __beq(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("BEQ"); + + this->gen_sync(PRE_SYNC, 4); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_EQ, + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)), + this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)), + this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)), + 32); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 4); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 5: BNE */ + std::tuple __bne(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("BNE"); + + this->gen_sync(PRE_SYNC, 5); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_NE, + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)), + this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)), + this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)), + 32); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 5); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 6: BLT */ + std::tuple __blt(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("BLT"); + + this->gen_sync(PRE_SYNC, 6); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_ext( + this->gen_reg_load(rs2 + traits::X0, 0), + 32, true)), + this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)), + this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)), + 32); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 6); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 7: BGE */ + std::tuple __bge(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("BGE"); + + this->gen_sync(PRE_SYNC, 7); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_SGE, + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_ext( + this->gen_reg_load(rs2 + traits::X0, 0), + 32, true)), + this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)), + this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)), + 32); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 7); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 8: BLTU */ + std::tuple __bltu(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("BLTU"); + + this->gen_sync(PRE_SYNC, 8); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_ULT, + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)), + this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)), + this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)), + 32); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 8); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 9: BGEU */ + std::tuple __bgeu(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("BGEU"); + + this->gen_sync(PRE_SYNC, 9); + + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_UGE, + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)), + this->builder.CreateAdd( + this->gen_ext( + cur_pc_val, + 32, true), + this->gen_const(32U, imm)), + this->builder.CreateAdd( + cur_pc_val, + this->gen_const(32U, 4)), + 32); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + Value* is_cont_v = this->builder.CreateICmp(ICmpInst::ICMP_NE, PC_val, this->gen_const(32U, pc.val), "is_cont_v"); + this->builder.CreateStore(this->gen_ext(is_cont_v, 32U, false), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_sync(POST_SYNC, 9); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 10: LB */ + std::tuple __lb(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("LB"); + + this->gen_sync(PRE_SYNC, 10); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + if(rd != 0){ + Value* Xtmp0_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 8/8), + 32, + true); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 10); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 11: LH */ + std::tuple __lh(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("LH"); + + this->gen_sync(PRE_SYNC, 11); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + if(rd != 0){ + Value* Xtmp0_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 16/8), + 32, + true); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 11); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 12: LW */ + std::tuple __lw(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("LW"); + + this->gen_sync(PRE_SYNC, 12); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + if(rd != 0){ + Value* Xtmp0_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 12); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 13: LBU */ + std::tuple __lbu(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("LBU"); + + this->gen_sync(PRE_SYNC, 13); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + if(rd != 0){ + Value* Xtmp0_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 8/8), + 32, + false); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 13); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 14: LHU */ + std::tuple __lhu(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("LHU"); + + this->gen_sync(PRE_SYNC, 14); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + if(rd != 0){ + Value* Xtmp0_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 16/8), + 32, + false); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 14); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 15: SB */ + std::tuple __sb(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SB"); + + this->gen_sync(PRE_SYNC, 15); + + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + Value* MEMtmp0_val = this->gen_reg_load(rs2 + traits::X0, 0); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder.CreateZExtOrTrunc(MEMtmp0_val,this->get_type(8))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 15); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 16: SH */ + std::tuple __sh(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SH"); + + this->gen_sync(PRE_SYNC, 16); + + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + Value* MEMtmp0_val = this->gen_reg_load(rs2 + traits::X0, 0); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder.CreateZExtOrTrunc(MEMtmp0_val,this->get_type(16))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 16); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 17: SW */ + std::tuple __sw(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SW"); + + this->gen_sync(PRE_SYNC, 17); + + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* offs_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + Value* MEMtmp0_val = this->gen_reg_load(rs2 + traits::X0, 0); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder.CreateZExtOrTrunc(MEMtmp0_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 17); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 18: ADDI */ + std::tuple __addi(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("ADDI"); + + this->gen_sync(PRE_SYNC, 18); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "addi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAdd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 18); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 19: SLTI */ + std::tuple __slti(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SLTI"); + + this->gen_sync(PRE_SYNC, 19); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "slti"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 19); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 20: SLTIU */ + std::tuple __sltiu(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SLTIU"); + + this->gen_sync(PRE_SYNC, 20); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "sltiu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + int32_t full_imm_val = imm; + if(rd != 0){ + Value* Xtmp0_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_ULT, + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_const(32U, full_imm_val)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 20); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 21: XORI */ + std::tuple __xori(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("XORI"); + + this->gen_sync(PRE_SYNC, 21); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "xori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateXor( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 21); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 22: ORI */ + std::tuple __ori(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("ORI"); + + this->gen_sync(PRE_SYNC, 22); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "ori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateOr( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 22); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 23: ANDI */ + std::tuple __andi(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("ANDI"); + + this->gen_sync(PRE_SYNC, 23); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "andi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAnd( + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_const(32U, imm)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 23); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 24: SLLI */ + std::tuple __slli(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SLLI"); + + this->gen_sync(PRE_SYNC, 24); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(shamt > 31){ + this->gen_raise_trap(0, 0); + } else { + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateShl( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_const(32U, shamt)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 24); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 25: SRLI */ + std::tuple __srli(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SRLI"); + + this->gen_sync(PRE_SYNC, 25); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(shamt > 31){ + this->gen_raise_trap(0, 0); + } else { + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateLShr( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_const(32U, shamt)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 25); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 26: SRAI */ + std::tuple __srai(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SRAI"); + + this->gen_sync(PRE_SYNC, 26); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(shamt > 31){ + this->gen_raise_trap(0, 0); + } else { + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAShr( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_const(32U, shamt)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 26); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 27: ADD */ + std::tuple __add(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("ADD"); + + this->gen_sync(PRE_SYNC, 27); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAdd( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 27); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 28: SUB */ + std::tuple __sub(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SUB"); + + this->gen_sync(PRE_SYNC, 28); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateSub( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 28); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 29: SLL */ + std::tuple __sll(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SLL"); + + this->gen_sync(PRE_SYNC, 29); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateShl( + this->gen_reg_load(rs1 + traits::X0, 0), + this->builder.CreateAnd( + this->gen_reg_load(rs2 + traits::X0, 0), + this->builder.CreateSub( + this->gen_const(32U, 32), + this->gen_const(32U, 1)))); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 29); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 30: SLT */ + std::tuple __slt(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SLT"); + + this->gen_sync(PRE_SYNC, 30); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, true), + this->gen_ext( + this->gen_reg_load(rs2 + traits::X0, 0), + 32, true)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 30); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 31: SLTU */ + std::tuple __sltu(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SLTU"); + + this->gen_sync(PRE_SYNC, 31); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->gen_choose( + this->builder.CreateICmp( + ICmpInst::ICMP_ULT, + this->gen_ext( + this->gen_reg_load(rs1 + traits::X0, 0), + 32, + false), + this->gen_ext( + this->gen_reg_load(rs2 + traits::X0, 0), + 32, + false)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 31); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 32: XOR */ + std::tuple __xor(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("XOR"); + + this->gen_sync(PRE_SYNC, 32); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateXor( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 32); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 33: SRL */ + std::tuple __srl(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SRL"); + + this->gen_sync(PRE_SYNC, 33); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateLShr( + this->gen_reg_load(rs1 + traits::X0, 0), + this->builder.CreateAnd( + this->gen_reg_load(rs2 + traits::X0, 0), + this->builder.CreateSub( + this->gen_const(32U, 32), + this->gen_const(32U, 1)))); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 33); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 34: SRA */ + std::tuple __sra(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SRA"); + + this->gen_sync(PRE_SYNC, 34); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAShr( + this->gen_reg_load(rs1 + traits::X0, 0), + this->builder.CreateAnd( + this->gen_reg_load(rs2 + traits::X0, 0), + this->builder.CreateSub( + this->gen_const(32U, 32), + this->gen_const(32U, 1)))); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 34); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 35: OR */ + std::tuple __or(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("OR"); + + this->gen_sync(PRE_SYNC, 35); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateOr( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 35); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 36: AND */ + std::tuple __and(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("AND"); + + this->gen_sync(PRE_SYNC, 36); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->builder.CreateAnd( + this->gen_reg_load(rs1 + traits::X0, 0), + this->gen_reg_load(rs2 + traits::X0, 0)); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 36); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 37: FENCE */ + std::tuple __fence(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("FENCE"); + + this->gen_sync(PRE_SYNC, 37); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t succ = ((bit_sub<20,4>(instr))); + uint8_t pred = ((bit_sub<24,4>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("fence"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* FENCEtmp0_val = this->builder.CreateOr( + this->builder.CreateShl( + this->gen_const(32U, pred), + this->gen_const(32U, 4)), + this->gen_const(32U, succ)); + this->gen_write_mem( + traits::FENCE, + this->gen_const(64U, 0), + this->builder.CreateZExtOrTrunc(FENCEtmp0_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 37); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 38: FENCE_I */ + std::tuple __fence_i(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("FENCE_I"); + + this->gen_sync(PRE_SYNC, 38); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t imm = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("fence_i"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* FENCEtmp0_val = this->gen_const(32U, imm); + this->gen_write_mem( + traits::FENCE, + this->gen_const(64U, 1), + this->builder.CreateZExtOrTrunc(FENCEtmp0_val,this->get_type(32))); + this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 38); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(FLUSH, nullptr); + } + + /* instruction 39: ECALL */ + std::tuple __ecall(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("ECALL"); + + this->gen_sync(PRE_SYNC, 39); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("ecall"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + this->gen_raise_trap(0, 11); + this->gen_sync(POST_SYNC, 39); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 40: EBREAK */ + std::tuple __ebreak(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("EBREAK"); + + this->gen_sync(PRE_SYNC, 40); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("ebreak"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + this->gen_raise_trap(0, 3); + this->gen_sync(POST_SYNC, 40); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 41: URET */ + std::tuple __uret(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("URET"); + + this->gen_sync(PRE_SYNC, 41); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("uret"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + this->gen_leave_trap(0); + this->gen_sync(POST_SYNC, 41); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 42: SRET */ + std::tuple __sret(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SRET"); + + this->gen_sync(PRE_SYNC, 42); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("sret"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + this->gen_leave_trap(1); + this->gen_sync(POST_SYNC, 42); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 43: MRET */ + std::tuple __mret(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("MRET"); + + this->gen_sync(PRE_SYNC, 43); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("mret"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + this->gen_leave_trap(3); + this->gen_sync(POST_SYNC, 43); + this->gen_trap_check(this->leave_blk); + return std::make_tuple(BRANCH, nullptr); + } + + /* instruction 44: WFI */ + std::tuple __wfi(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("WFI"); + + this->gen_sync(PRE_SYNC, 44); + + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("wfi"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + this->gen_wait(1); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 44); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 45: SFENCE.VMA */ + std::tuple __sfence_vma(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("SFENCE.VMA"); + + this->gen_sync(PRE_SYNC, 45); + + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr("sfence.vma"), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* FENCEtmp0_val = this->gen_const(32U, rs1); + this->gen_write_mem( + traits::FENCE, + this->gen_const(64U, 2), + this->builder.CreateZExtOrTrunc(FENCEtmp0_val,this->get_type(32))); + Value* FENCEtmp1_val = this->gen_const(32U, rs2); + this->gen_write_mem( + traits::FENCE, + this->gen_const(64U, 3), + this->builder.CreateZExtOrTrunc(FENCEtmp1_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 45); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 46: CSRRW */ + std::tuple __csrrw(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("CSRRW"); + + this->gen_sync(PRE_SYNC, 46); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* rs_val_val = this->gen_reg_load(rs1 + traits::X0, 0); + if(rd != 0){ + Value* csr_val_val = this->gen_read_mem(traits::CSR, this->gen_const(16U, csr), 32/8); + Value* CSRtmp0_val = rs_val_val; + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp0_val,this->get_type(32))); + Value* Xtmp1_val = csr_val_val; + this->builder.CreateStore(Xtmp1_val, get_reg_ptr(rd + traits::X0), false); + } else { + Value* CSRtmp2_val = rs_val_val; + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp2_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 46); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 47: CSRRS */ + std::tuple __csrrs(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("CSRRS"); + + this->gen_sync(PRE_SYNC, 47); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* xrd_val = this->gen_read_mem(traits::CSR, this->gen_const(16U, csr), 32/8); + Value* xrs1_val = this->gen_reg_load(rs1 + traits::X0, 0); + if(rd != 0){ + Value* Xtmp0_val = xrd_val; + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + if(rs1 != 0){ + Value* CSRtmp1_val = this->builder.CreateOr( + xrd_val, + xrs1_val); + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp1_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 47); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 48: CSRRC */ + std::tuple __csrrc(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("CSRRC"); + + this->gen_sync(PRE_SYNC, 48); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* xrd_val = this->gen_read_mem(traits::CSR, this->gen_const(16U, csr), 32/8); + Value* xrs1_val = this->gen_reg_load(rs1 + traits::X0, 0); + if(rd != 0){ + Value* Xtmp0_val = xrd_val; + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + if(rs1 != 0){ + Value* CSRtmp1_val = this->builder.CreateAnd( + xrd_val, + this->builder.CreateNot(xrs1_val)); + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp1_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 48); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 49: CSRRWI */ + std::tuple __csrrwi(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("CSRRWI"); + + this->gen_sync(PRE_SYNC, 49); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + if(rd != 0){ + Value* Xtmp0_val = this->gen_read_mem(traits::CSR, this->gen_const(16U, csr), 32/8); + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + Value* CSRtmp1_val = this->gen_ext( + this->gen_const(32U, zimm), + 32, + false); + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp1_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 49); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 50: CSRRSI */ + std::tuple __csrrsi(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("CSRRSI"); + + this->gen_sync(PRE_SYNC, 50); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* res_val = this->gen_read_mem(traits::CSR, this->gen_const(16U, csr), 32/8); + if(zimm != 0){ + Value* CSRtmp0_val = this->builder.CreateOr( + res_val, + this->gen_ext( + this->gen_const(32U, zimm), + 32, + false)); + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp0_val,this->get_type(32))); + } + if(rd != 0){ + Value* Xtmp1_val = res_val; + this->builder.CreateStore(Xtmp1_val, get_reg_ptr(rd + traits::X0), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 50); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /* instruction 51: CSRRCI */ + std::tuple __csrrci(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ + bb->setName("CSRRCI"); + + this->gen_sync(PRE_SYNC, 51); + + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + std::vector args { + this->core_ptr, + this->gen_const(64, pc.val), + this->builder.CreateGlobalStringPtr(mnemonic), + }; + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + } + + Value* cur_pc_val = this->gen_const(32, pc.val); + pc=pc+4; + + Value* res_val = this->gen_read_mem(traits::CSR, this->gen_const(16U, csr), 32/8); + if(rd != 0){ + Value* Xtmp0_val = res_val; + this->builder.CreateStore(Xtmp0_val, get_reg_ptr(rd + traits::X0), false); + } + if(zimm != 0){ + Value* CSRtmp1_val = this->builder.CreateAnd( + res_val, + this->builder.CreateNot(this->gen_ext( + this->gen_const(32U, zimm), + 32, + false))); + this->gen_write_mem( + traits::CSR, + this->gen_const(16U, csr), + this->builder.CreateZExtOrTrunc(CSRtmp1_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(POST_SYNC, 51); + bb = BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(CONT, bb); + } + + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + std::tuple illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) { + this->gen_sync(iss::PRE_SYNC, instr_descr.size()); + this->builder.CreateStore(this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), true), + get_reg_ptr(traits::PC), true); + this->builder.CreateStore( + this->builder.CreateAdd(this->builder.CreateLoad(get_reg_ptr(traits::ICOUNT), true), + this->gen_const(64U, 1)), + get_reg_ptr(traits::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 std::make_tuple(BRANCH, nullptr); + } +}; + +template void debug_fn(CODE_WORD insn) { + volatile CODE_WORD x = insn; + insn = 2 * x; +} + +template vm_impl::vm_impl() { this(new ARCH()); } + +template +vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) +: vm_base(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 +std::tuple +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, BasicBlock *this_block) { + // we fetch at max 4 byte, alignment is 2 + enum {TRAP_ID=1<<16}; + code_word_t insn = 0; + const typename traits::addr_t upper_bits = ~traits::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 void vm_impl::gen_leave_behavior(BasicBlock *leave_blk) { + this->builder.SetInsertPoint(leave_blk); + this->builder.CreateRet(this->builder.CreateLoad(get_reg_ptr(arch::traits::NEXT_PC), false)); +} + +template void vm_impl::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::TRAP_STATE), true); + this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); +} + +template void vm_impl::gen_leave_trap(unsigned lvl) { + std::vector 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::CSR, (lvl << 8) + 0x41, traits::XLEN / 8); + this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), get_reg_ptr(traits::LAST_BRANCH), false); +} + +template void vm_impl::gen_wait(unsigned type) { + std::vector args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; + this->builder.CreateCall(this->mod->getFunction("wait"), args); +} + +template void vm_impl::gen_trap_behavior(BasicBlock *trap_blk) { + this->builder.SetInsertPoint(trap_blk); + auto *trap_state_val = this->builder.CreateLoad(get_reg_ptr(traits::TRAP_STATE), true); + this->builder.CreateStore(this->gen_const(32U, std::numeric_limits::max()), + get_reg_ptr(traits::LAST_BRANCH), false); + std::vector args{this->core_ptr, this->adj_to64(trap_state_val), + this->adj_to64(this->builder.CreateLoad(get_reg_ptr(traits::PC), false))}; + this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); + auto *trap_addr_val = this->builder.CreateLoad(get_reg_ptr(traits::NEXT_PC), false); + this->builder.CreateRet(trap_addr_val); +} + +template inline void vm_impl::gen_trap_check(BasicBlock *bb) { + auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits::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 mnrv32 + +template <> +std::unique_ptr create(arch::mnrv32 *core, unsigned short port, bool dump) { + auto ret = new mnrv32::vm_impl(*core, dump); + if (port != 0) debugger::server::run_server(ret, port); + return std::unique_ptr(ret); +} +} // namespace llvm +} // namespace iss diff --git a/src/vm/llvm/vm_rv32gc.cpp b/src/vm/llvm/vm_rv32gc.cpp index 043a8bb..8d51c7d 100644 --- a/src/vm/llvm/vm_rv32gc.cpp +++ b/src/vm/llvm/vm_rv32gc.cpp @@ -47,7 +47,7 @@ #include namespace iss { -namespace vm { +namespace llvm { namespace fp_impl { void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); } @@ -91,7 +91,7 @@ protected: void setup_module(Module* m) override { super::setup_module(m); - iss::vm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); + iss::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); } inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { diff --git a/src/vm/llvm/vm_rv32imac.cpp b/src/vm/llvm/vm_rv32imac.cpp index c00aed8..4a2eed7 100644 --- a/src/vm/llvm/vm_rv32imac.cpp +++ b/src/vm/llvm/vm_rv32imac.cpp @@ -47,21 +47,21 @@ #include namespace iss { -namespace vm { +namespace llvm { namespace fp_impl { void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); } } -namespace llvm { + namespace rv32imac { using namespace iss::arch; using namespace llvm; using namespace iss::debugger; -using namespace iss::llvm; +using namespace iss::vm::llvm; template class vm_impl : public vm_base { public: - using super = typename iss::llvm::vm_base; + using super = typename iss::vm::llvm::vm_base; 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; @@ -91,7 +91,7 @@ protected: void setup_module(Module* m) override { super::setup_module(m); - iss::vm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); + iss::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); } inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { @@ -4815,5 +4815,5 @@ std::unique_ptr create(arch::rv32imac *core, unsigned sho if (port != 0) debugger::server::run_server(ret, port); return std::unique_ptr(ret); } -} + } // namespace iss diff --git a/src/vm/llvm/vm_rv64gc.cpp b/src/vm/llvm/vm_rv64gc.cpp index 26dbd67..d47c791 100644 --- a/src/vm/llvm/vm_rv64gc.cpp +++ b/src/vm/llvm/vm_rv64gc.cpp @@ -47,7 +47,7 @@ #include namespace iss { -namespace vm { +namespace llvm { namespace fp_impl { void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); } @@ -91,7 +91,7 @@ protected: void setup_module(Module* m) override { super::setup_module(m); - iss::vm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); + iss::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); } inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { diff --git a/src/vm/llvm/vm_rv64i.cpp b/src/vm/llvm/vm_rv64i.cpp index 5048e36..961f019 100644 --- a/src/vm/llvm/vm_rv64i.cpp +++ b/src/vm/llvm/vm_rv64i.cpp @@ -47,7 +47,7 @@ #include namespace iss { -namespace vm { +namespace llvm { namespace fp_impl { void add_fp_functions_2_module(llvm::Module *, unsigned, unsigned); } @@ -57,11 +57,11 @@ namespace rv64i { using namespace iss::arch; using namespace llvm; using namespace iss::debugger; -using namespace iss::vm::llvm; +using namespace iss::llvm; template class vm_impl : public vm_base { public: - using super = typename iss::vm::llvm::vm_base; + using super = typename iss::llvm::vm_base; 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; @@ -91,7 +91,7 @@ protected: void setup_module(Module* m) override { super::setup_module(m); - iss::vm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); + iss::llvm::fp_impl::add_fp_functions_2_module(m, traits::FP_REGS_SIZE, traits::XLEN); } inline Value *gen_choose(Value *cond, Value *trueVal, Value *falseVal, unsigned size) { diff --git a/src/vm/tcc/vm_mnrv32.cpp b/src/vm/tcc/vm_mnrv32.cpp index 25c4347..345f64c 100644 --- a/src/vm/tcc/vm_mnrv32.cpp +++ b/src/vm/tcc/vm_mnrv32.cpp @@ -52,19 +52,15 @@ namespace tcc { namespace mnrv32 { using namespace iss::arch; using namespace iss::debugger; -using namespace iss::vm::tcc; -template class vm_impl : public vm_base { +template class vm_impl : public iss::tcc::vm_base { public: - using super = typename iss::vm::tcc::vm_base; + using super = typename iss::tcc::vm_base; 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; + using addr_t = typename super::addr_t; + using tu_builder = typename super::tu_builder; vm_impl(); @@ -84,44 +80,43 @@ protected: using this_class = vm_impl; using compile_ret_t = std::tuple; - using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, std::ostringstream&); + using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); inline const char *name(size_t index){return traits::reg_aliases.at(index);} - template inline ConstantInt *size(T type) { - return nullptr; - } - - void setup_module(Module* m) override { + void setup_module(std::string 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 &, tu_builder&) override; + + void gen_trap_behavior(tu_builder& tu) override; + + void gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause); + + void gen_leave_trap(tu_builder& tu, unsigned lvl); + + void gen_wait(tu_builder& tu, unsigned type); + + inline void gen_trap_check(tu_builder& tu) { + tu("if(*trap_state!=0) goto trap_entry;"); } - 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::XLEN, pc.val), - this->get_type(traits::XLEN)); - this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); + inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) { + switch(reg_num){ + case traits::NEXT_PC: + tu("*next_pc = {:#x};", pc.val); + break; + case traits::PC: + tu("*pc = {:#x};", pc.val); + break; + default: + if(!tu.defined_regs[reg_num]){ + tu("reg_t* reg{:02d} = (reg_t*){:#x};", reg_num, reinterpret_cast(get_reg_ptr(reg_num))); + tu.defined_regs[reg_num]=true; + } + tu("*reg{:02d} = {:#x};", reg_num, pc.val); + } } // some compile time constants @@ -135,9 +130,9 @@ protected: std::array lut_00, lut_01, lut_10; std::array lut_11; - std::array qlut; + std::array qlut; - std::array lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; + std::array 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) { @@ -187,7 +182,7 @@ private: compile_func op; }; - const std::array instr_descr = {{ + const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */ /* instruction LUI */ {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, @@ -293,21 +288,165 @@ private: {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, /* instruction CSRRCI */ {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, + /* 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 definitions */ /* instruction 0: LUI */ - compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LUI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 0); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.constant(imm, 32U), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 0); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 1: AUIPC */ - compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("AUIPC_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 1); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 1); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 2: JAL */ - compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ - this->gen_sync(PRE_SYNC, 0); - + compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("JAL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 2); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,8>(instr) << 12) | (bit_sub<20,1>(instr) << 11) | (bit_sub<21,10>(instr) << 1) | (bit_sub<31,1>(instr) << 20)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + cur_pc_val, + tu.constant(4, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 2); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 3: JALR */ + compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("JALR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 3); uint8_t rd = ((bit_sub<7,5>(instr))); uint8_t rs1 = ((bit_sub<15,5>(instr))); int16_t imm = signextend((bit_sub<20,12>(instr))); @@ -315,219 +454,2449 @@ private: /* 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"<core_ptr<<", 0x"<::reg_bit_widths[traits::PC]); pc=pc+4; - } - - /* instruction 3: JALR */ - compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + tu.open_scope(); + auto new_pc_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + cur_pc_val, + tu.constant(4, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + auto PC_val_v = tu.assignment("PC_val", tu.l_and( + new_pc_val, + tu.l_not(tu.constant(0x1, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 3); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 4: BEQ */ - compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BEQ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 4); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 4); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 5: BNE */ - compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BNE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 5); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 5); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 6: BLT */ - compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BLT_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 6); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 6); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 7: BGE */ - compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BGE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 7); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SGE, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 7); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 8: BLTU */ - compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BLTU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 8); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 8); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 9: BGEU */ - compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BGEU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 9); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_UGE, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 9); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 10: LB */ - compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 10); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 8), + 32, + false), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 10); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 11: LH */ - compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 11); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 16), + 32, + false), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 11); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 12: LW */ - compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 12); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 12); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 13: LBU */ - compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LBU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 13); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 8), + 32, + true), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 13); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 14: LHU */ - compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LHU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 14); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 16), + 32, + true), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 14); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 15: SB */ - compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 15); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + auto MEMtmp0_val_v = tu.assignment("MEMtmp0_val", tu.load(rs2 + traits::X0, 0), 8); + tu.write_mem( + traits::MEM, + offs_val, + MEMtmp0_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 15); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 16: SH */ - compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 16); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + auto MEMtmp0_val_v = tu.assignment("MEMtmp0_val", tu.load(rs2 + traits::X0, 0), 16); + tu.write_mem( + traits::MEM, + offs_val, + MEMtmp0_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 16); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 17: SW */ - compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 17); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)); + auto MEMtmp0_val_v = tu.assignment("MEMtmp0_val", tu.load(rs2 + traits::X0, 0), 32); + tu.write_mem( + traits::MEM, + offs_val, + MEMtmp0_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 17); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 18: ADDI */ - compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ADDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 18); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "addi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 18); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 19: SLTI */ - compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 19); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "slti"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), + tu.constant(1, 32U), + tu.constant(0, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 19); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 20: SLTIU */ - compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTIU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 20); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "sltiu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + int32_t full_imm_val = imm; + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.load(rs1 + traits::X0, 0), + tu.constant(full_imm_val, 32U)), + tu.constant(1, 32U), + tu.constant(0, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 20); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 21: XORI */ - compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("XORI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 21); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "xori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_xor( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 21); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 22: ORI */ - compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ORI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 22); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "ori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_or( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 22); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 23: ANDI */ - compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ANDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 23); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((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}", fmt::arg("mnemonic", "andi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_and( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 23); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 24: SLLI */ - compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 24); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 24); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 25: SRLI */ - compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 25); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.lshr( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 25); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 26: SRAI */ - compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRAI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 26); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ashr( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 26); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 27: ADD */ - compile_ret_t __add(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __add(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ADD_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 27); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 27); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 28: SUB */ - compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SUB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 28); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.sub( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 28); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 29: SLL */ - compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 29); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 29); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 30: SLT */ - compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLT_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 30); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.constant(1, 32U), + tu.constant(0, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 30); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 31: SLTU */ - compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 31); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, + true), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, + true)), + tu.constant(1, 32U), + tu.constant(0, 32U)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 31); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 32: XOR */ - compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("XOR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 32); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_xor( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 32); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 33: SRL */ - compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 33); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.lshr( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 33); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 34: SRA */ - compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRA_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 34); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ashr( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 34); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 35: OR */ - compile_ret_t __or(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __or(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("OR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 35); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_or( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 35); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 36: AND */ - compile_ret_t __and(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __and(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("AND_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 36); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_and( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 36); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 37: FENCE */ - compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("FENCE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 37); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t succ = ((bit_sub<20,4>(instr))); + uint8_t pred = ((bit_sub<24,4>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "fence"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto FENCEtmp0_val_v = tu.assignment("FENCEtmp0_val", tu.l_or( + tu.shl( + tu.constant(pred, 32U), + tu.constant(4, 32U)), + tu.constant(succ, 32U)), 32); + tu.write_mem( + traits::FENCE, + tu.constant(0, 64U), + FENCEtmp0_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 37); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 38: FENCE_I */ - compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("FENCE_I_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 38); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t imm = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "fence_i"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto FENCEtmp0_val_v = tu.assignment("FENCEtmp0_val", tu.constant(imm, 32U), 32); + tu.write_mem( + traits::FENCE, + tu.constant(1, 64U), + FENCEtmp0_val_v); + tu.close_scope(); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 38); + gen_trap_check(tu); + return std::make_tuple(FLUSH); } /* instruction 39: ECALL */ - compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ECALL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 39); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "ecall"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 11); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 39); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 40: EBREAK */ - compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("EBREAK_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 40); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "ebreak"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 40); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 41: URET */ - compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("URET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 41); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "uret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 0); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 41); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 42: SRET */ - compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 42); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "sret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 1); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 42); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 43: MRET */ - compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MRET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 43); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "mret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 43); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /* instruction 44: WFI */ - compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("WFI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 44); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "wfi"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_wait(tu, 1); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 44); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 45: SFENCE.VMA */ - compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SFENCE_VMA_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 45); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "sfence.vma"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto FENCEtmp0_val_v = tu.assignment("FENCEtmp0_val", tu.constant(rs1, 32U), 32); + tu.write_mem( + traits::FENCE, + tu.constant(2, 64U), + FENCEtmp0_val_v); + auto FENCEtmp1_val_v = tu.assignment("FENCEtmp1_val", tu.constant(rs2, 32U), 32); + tu.write_mem( + traits::FENCE, + tu.constant(3, 64U), + FENCEtmp1_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 45); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 46: CSRRW */ - compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 46); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto rs_val_val = tu.load(rs1 + traits::X0, 0); + if(rd != 0){ + auto csr_val_val = tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32); + auto CSRtmp0_val_v = tu.assignment("CSRtmp0_val", rs_val_val, 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp0_val_v); + auto Xtmp1_val_v = tu.assignment("Xtmp1_val", csr_val_val, 32); + tu.store(Xtmp1_val_v, rd + traits::X0); + } else { + auto CSRtmp2_val_v = tu.assignment("CSRtmp2_val", rs_val_val, 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp2_val_v); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 46); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 47: CSRRS */ - compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRS_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 47); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto xrd_val = tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32); + auto xrs1_val = tu.load(rs1 + traits::X0, 0); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", xrd_val, 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + if(rs1 != 0){ + auto CSRtmp1_val_v = tu.assignment("CSRtmp1_val", tu.l_or( + xrd_val, + xrs1_val), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp1_val_v); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 47); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 48: CSRRC */ - compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRC_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 48); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto xrd_val = tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32); + auto xrs1_val = tu.load(rs1 + traits::X0, 0); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", xrd_val, 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + if(rs1 != 0){ + auto CSRtmp1_val_v = tu.assignment("CSRtmp1_val", tu.l_and( + xrd_val, + tu.l_not(xrs1_val)), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp1_val_v); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 48); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 49: CSRRWI */ - compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRWI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 49); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + auto CSRtmp1_val_v = tu.assignment("CSRtmp1_val", tu.ext( + tu.constant(zimm, 32U), + 32, + true), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp1_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 49); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 50: CSRRSI */ - compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRSI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 50); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto res_val = tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32); + if(zimm != 0){ + auto CSRtmp0_val_v = tu.assignment("CSRtmp0_val", tu.l_or( + res_val, + tu.ext( + tu.constant(zimm, 32U), + 32, + true)), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp0_val_v); + } + if(rd != 0){ + auto Xtmp1_val_v = tu.assignment("Xtmp1_val", res_val, 32); + tu.store(Xtmp1_val_v, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 50); + gen_trap_check(tu); + return std::make_tuple(CONT); } /* instruction 51: CSRRCI */ - compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRCI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 51); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto res_val = tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32); + if(rd != 0){ + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", res_val, 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + } + if(zimm != 0){ + auto CSRtmp1_val_v = tu.assignment("CSRtmp1_val", tu.l_and( + res_val, + tu.l_not(tu.ext( + tu.constant(zimm, 32U), + 32, + true))), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + CSRtmp1_val_v); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 51); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 52: C.ADDI4SPN */ + compile_ret_t __c_addi4spn(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADDI4SPN_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 52); + uint8_t rd = ((bit_sub<2,3>(instr))); + uint16_t imm = ((bit_sub<5,1>(instr) << 3) | (bit_sub<6,1>(instr) << 2) | (bit_sub<7,4>(instr) << 6) | (bit_sub<11,2>(instr) << 4)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.addi4spn"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(imm == 0){ + this->gen_raise_trap(tu, 0, 2); + } + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.load(2 + traits::X0, 0), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rd + 8 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 52); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 53: C.LW */ + compile_ret_t __c_lw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 53); + uint8_t rd = ((bit_sub<2,3>(instr))); + uint8_t uimm = ((bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.lw"), + fmt::arg("rd", name(8+rd)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.add( + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(uimm, 32U)); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), 32); + tu.store(Xtmp0_val_v, rd + 8 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 53); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 54: C.SW */ + compile_ret_t __c_sw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 54); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t uimm = ((bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.sw"), + fmt::arg("rs2", name(8+rs2)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.add( + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(uimm, 32U)); + auto MEMtmp0_val_v = tu.assignment("MEMtmp0_val", tu.load(rs2 + 8 + traits::X0, 0), 32); + tu.write_mem( + traits::MEM, + offs_val, + MEMtmp0_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 54); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 55: C.ADDI */ + compile_ret_t __c_addi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 55); + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.addi"), + fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rs1 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 55); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 56: C.NOP */ + compile_ret_t __c_nop(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_NOP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 56); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "c.nop"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.close_scope(); + /* TODO: describe operations for C.NOP ! */ + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 56); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 57: C.JAL */ + compile_ret_t __c_jal(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_JAL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 57); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (bit_sub<12,1>(instr) << 11)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.jal"), + fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + cur_pc_val, + tu.constant(2, 32U)), 32); + tu.store(Xtmp0_val_v, 1 + traits::X0); + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 57); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 58: C.LI */ + compile_ret_t __c_li(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 58); + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.li"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(rd == 0){ + this->gen_raise_trap(tu, 0, 2); + } + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.constant(imm, 32U), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 58); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 59: C.LUI */ + compile_ret_t __c_lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LUI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 59); + int32_t imm = signextend((bit_sub<2,5>(instr) << 12) | (bit_sub<12,1>(instr) << 17)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(rd == 0){ + this->gen_raise_trap(tu, 0, 2); + } + if(imm == 0){ + this->gen_raise_trap(tu, 0, 2); + } + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.constant(imm, 32U), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 59); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 60: C.ADDI16SP */ + compile_ret_t __c_addi16sp(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADDI16SP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 60); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 7) | (bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 4) | (bit_sub<12,1>(instr) << 9)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.addi16sp"), + fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.ext( + tu.load(2 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, 2 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 60); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 61: C.SRLI */ + compile_ret_t __c_srli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SRLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 61); + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srli"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rs1_idx_val = rs1 + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.lshr( + tu.load(rs1_idx_val + traits::X0, 0), + tu.constant(shamt, 32U)), 32); + tu.store(Xtmp0_val_v, rs1_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 61); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 62: C.SRAI */ + compile_ret_t __c_srai(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SRAI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 62); + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srai"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rs1_idx_val = rs1 + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ashr( + tu.load(rs1_idx_val + traits::X0, 0), + tu.constant(shamt, 32U)), 32); + tu.store(Xtmp0_val_v, rs1_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 62); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 63: C.ANDI */ + compile_ret_t __c_andi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ANDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 63); + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.andi"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rs1_idx_val = rs1 + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_and( + tu.ext( + tu.load(rs1_idx_val + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(Xtmp0_val_v, rs1_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 63); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 64: C.SUB */ + compile_ret_t __c_sub(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SUB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 64); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.sub"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.sub( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 64); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 65: C.XOR */ + compile_ret_t __c_xor(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_XOR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 65); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.xor"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_xor( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 65); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 66: C.OR */ + compile_ret_t __c_or(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_OR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 66); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.or"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_or( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 66); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 67: C.AND */ + compile_ret_t __c_and(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_AND_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 67); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.and"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.l_and( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 67); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 68: C.J */ + compile_ret_t __c_j(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_J_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 68); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (bit_sub<12,1>(instr) << 11)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.j"), + fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 68); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 69: C.BEQZ */ + compile_ret_t __c_beqz(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_BEQZ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 69); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.beqz"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(0, 32U)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(2, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 69); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 70: C.BNEZ */ + compile_ret_t __c_bnez(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_BNEZ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 70); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.bnez"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(0, 32U)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(2, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 70); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 71: C.SLLI */ + compile_ret_t __c_slli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SLLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 71); + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.slli"), + fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(rs1 == 0){ + this->gen_raise_trap(tu, 0, 2); + } + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), 32); + tu.store(Xtmp0_val_v, rs1 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 71); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 72: C.LWSP */ + compile_ret_t __c_lwsp(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LWSP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 72); + uint8_t uimm = ((bit_sub<2,2>(instr) << 6) | (bit_sub<4,3>(instr) << 2) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, sp, {uimm:#05x}", fmt::arg("mnemonic", "c.lwsp"), + fmt::arg("rd", name(rd)), fmt::arg("uimm", uimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.add( + tu.load(2 + traits::X0, 0), + tu.constant(uimm, 32U)); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 72); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 73: C.MV */ + compile_ret_t __c_mv(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_MV_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 73); + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.mv"), + fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.load(rs2 + traits::X0, 0), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 73); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 74: C.JR */ + compile_ret_t __c_jr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_JR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 74); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jr"), + fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits::X0, 0), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 74); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 75: C.ADD */ + compile_ret_t __c_add(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADD_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 75); + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.add"), + fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + tu.load(rd + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), 32); + tu.store(Xtmp0_val_v, rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 75); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 76: C.JALR */ + compile_ret_t __c_jalr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_JALR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 76); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jalr"), + fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto Xtmp0_val_v = tu.assignment("Xtmp0_val", tu.add( + cur_pc_val, + tu.constant(2, 32U)), 32); + tu.store(Xtmp0_val_v, 1 + traits::X0); + auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits::X0, 0), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 76); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 77: C.EBREAK */ + compile_ret_t __c_ebreak(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_EBREAK_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 77); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "c.ebreak"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 77); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 78: C.SWSP */ + compile_ret_t __c_swsp(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SWSP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 78); + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t uimm = ((bit_sub<7,2>(instr) << 6) | (bit_sub<9,4>(instr) << 2)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {uimm:#05x}(sp)", fmt::arg("mnemonic", "c.swsp"), + fmt::arg("rs2", name(rs2)), fmt::arg("uimm", uimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.add( + tu.load(2 + traits::X0, 0), + tu.constant(uimm, 32U)); + auto MEMtmp0_val_v = tu.assignment("MEMtmp0_val", tu.load(rs2 + traits::X0, 0), 32); + tu.write_mem( + traits::MEM, + offs_val, + MEMtmp0_val_v); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 78); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 79: DII */ + compile_ret_t __dii(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("DII_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 79); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "dii"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 2); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 79); + gen_trap_check(tu); + return std::make_tuple(BRANCH); } /**************************************************************************** * 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()); + compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) { + vm_impl::gen_sync(tu, 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); + gen_raise_trap(tu, 0, 2); // illegal instruction trap + vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size()); + vm_impl::gen_trap_check(tu); return BRANCH; } }; @@ -554,7 +2923,7 @@ vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) template std::tuple -vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, std::ostringstream& os) { +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; code_word_t insn = 0; @@ -580,22 +2949,28 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, if (f == nullptr) { f = &this_class::illegal_intruction; } - return (this->*f)(pc, insn, os); + return (this->*f)(pc, insn, tu); } -template void vm_impl::gen_leave_behavior(std::ostringstream& os) { +template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { + tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); } -template void vm_impl::gen_raise_trap(uint16_t trap_id, uint16_t cause) { +template void vm_impl::gen_leave_trap(tu_builder& tu, unsigned lvl) { + tu("leave_trap(core_ptr, {});", lvl); + tu.store(tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN),traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); } -template void vm_impl::gen_leave_trap(unsigned lvl) { +template void vm_impl::gen_wait(tu_builder& tu, unsigned type) { } -template void vm_impl::gen_wait(unsigned type) { -} - -template void vm_impl::gen_trap_behavior(std::ostringstream& os) { +template void vm_impl::gen_trap_behavior(tu_builder& tu) { + tu("trap_entry:"); + tu("enter_trap(core_ptr, *trap_state, *pc);"); + tu.store(tu.constant(std::numeric_limits::max(),32),traits::LAST_BRANCH); + tu("return *next_pc;"); } } // namespace mnrv32 diff --git a/src/vm/tcc/vm_rv64i.cpp b/src/vm/tcc/vm_rv64i.cpp index eed1ce4..5e28a30 100644 --- a/src/vm/tcc/vm_rv64i.cpp +++ b/src/vm/tcc/vm_rv64i.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #ifndef FMT_HEADER_ONLY @@ -57,11 +57,10 @@ namespace tcc { namespace rv64i { using namespace iss::arch; using namespace iss::debugger; -using namespace iss::vm::llvm; template class vm_impl : public vm_base { public: - using super = typename iss::vm::llvm::vm_base; + using super = typename iss::tcc::vm_base; 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; @@ -114,16 +113,14 @@ protected: void gen_trap_behavior(BasicBlock *) override; - void gen_trap_check(BasicBlock *bb); + std::string 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::XLEN, pc.val), - this->get_type(traits::XLEN)); - this->builder.CreateStore(next_pc_v, get_reg_ptr(reg_num), true); + inline std::string gen_set_pc(virt_addr_t pc, unsigned reg_num) { + return fmt::format("*((uint64_t*){}) = {}\n", get_reg_ptr(reg_num), next_pc_v.val); } // some compile time constants @@ -328,6 +325,33 @@ private: /* instruction 1: AUIPC */ compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, std::ostringstream& os){ + os<gen_sync(PRE_SYNC, 1); + + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + this->builder.CreateCall(this->mod->getFunction("print_disass"), args); + os<core_ptr, pc.val, mnemonic); + } + + Value* cur_pc_val = this->gen_const(64, pc.val); + pc=pc+4; + + if(rd != 0){ + os<::X0)); + } + os<gen_set_pc(pc, traits::NEXT_PC); + os<gen_sync(POST_SYNC, 1); + os<gen_trap_check(bb); + return std::make_tuple(CONT); + } /* instruction 2: JAL */ @@ -684,12 +708,9 @@ template void vm_impl::gen_trap_behavior(BasicBlock *trap_ this->builder.CreateRet(trap_addr_val); } -template inline void vm_impl::gen_trap_check(BasicBlock *bb) { - auto *v = this->builder.CreateLoad(get_reg_ptr(arch::traits::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); +template inline std::string vm_impl::gen_trap_check(BasicBlock *bb) { + return fmt::format("if(*(uint32_t){})!=0) goto trap_blk;\n", get_reg_ptr(arch::traits::TRAP_STATE)); + } } // namespace rv64i