From 60c926c921a8403b58a1ebee4eee47fbb48416a7 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Sun, 22 Oct 2023 15:11:20 +0200 Subject: [PATCH] adds asmjit --- gen_input/templates/asmjit/CORENAME.cpp.gtl | 280 ++ src/vm/asmjit/helper_func.h | 474 +++ src/vm/asmjit/vm_tgc5c.cpp | 3786 +++++++++++++++++++ 3 files changed, 4540 insertions(+) create mode 100644 gen_input/templates/asmjit/CORENAME.cpp.gtl create mode 100644 src/vm/asmjit/helper_func.h create mode 100644 src/vm/asmjit/vm_tgc5c.cpp diff --git a/gen_input/templates/asmjit/CORENAME.cpp.gtl b/gen_input/templates/asmjit/CORENAME.cpp.gtl new file mode 100644 index 0000000..ad40e74 --- /dev/null +++ b/gen_input/templates/asmjit/CORENAME.cpp.gtl @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (C) 2017, 2023 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 asmjit { + + +namespace ${coreDef.name.toLowerCase()} { +using namespace ::asmjit; +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::asmjit::vm_base { +public: + using traits = arch::traits; + using super = typename iss::asmjit::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 mem_type_e = typename super::mem_type_e; + 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; + using this_class = vm_impl; + using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&); + + continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override; + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + template::type> + inline S sext(U from) { + auto mask = (1ULL< instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; + + decoding_tree_node* root {nullptr}; + + const std::array instr_descr = {{ + /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> + /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ + {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> + }}; + + /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> + /* instruction ${idx}: ${instr.name} */ + continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + <%instr.fields.eachLine{%>${it} + <%}%>if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\\n${instr.name}_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, ${idx}); + pc=pc+ ${instr.length/8}; + + gen_instr_prologue(jh, pc.val); + cc.comment("\\n//behavior:"); + /*generate behavior*/ + <%instr.behavior.eachLine{%>${it} + <%}%> + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, ${idx}); + return returnValue; + } + <%}%> + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) { + + return BRANCH; + } + //decoding functionality + + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + compile_func decode_instr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decode_instr(child, word); + } + } + } + return nullptr; + } +}; + +template void debug_fn(CODE_WORD instr) { + volatile CODE_WORD x = instr; + instr = 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) { + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr: instr_descr){ + root->instrs.push_back(instr); + } + populate_decoding_tree(root); +} + +template +continuation_e +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) { + enum {TRAP_ID=1<<16}; + code_word_t instr = 0; + phys_addr_t paddr(pc); + auto *const data = (uint8_t *)&instr; + if(this->core.has_mmu()) + paddr = this->core.virt2phys(pc); + auto res = this->core.read(paddr, 4, data); + if (res != iss::Ok) + throw trap_access(TRAP_ID, pc.val); + if (instr == 0x0000006f || (instr&0xffff)==0xa001) + throw simulation_stopped(0); // 'J 0' or 'C.J 0' + ++inst_cnt; + auto f = decode_instr(root, instr); + if (f == nullptr) + f = &this_class::illegal_intruction; + return (this->*f)(pc, instr, jh); +} + + + +} // namespace ${coreDef.name.toLowerCase()} + +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 asmjit +} // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|asmjit", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_m_p(); + auto* vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }), + core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|asmjit", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_mu_p(); + auto* vm = new asmjit::${coreDef.name.toLowerCase()}::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }) +}; +} +} diff --git a/src/vm/asmjit/helper_func.h b/src/vm/asmjit/helper_func.h new file mode 100644 index 0000000..1abd7dd --- /dev/null +++ b/src/vm/asmjit/helper_func.h @@ -0,0 +1,474 @@ + + +x86::Mem get_reg_ptr(jit_holder& jh, unsigned idx){ + + x86::Gp tmp_ptr = jh.cc.newUIntPtr("tmp_ptr"); + jh.cc.mov(tmp_ptr, jh.regs_base_ptr); + jh.cc.add(tmp_ptr, traits::reg_byte_offsets[idx]); + switch(traits::reg_bit_widths[idx]){ + case 8: + return x86::ptr_8(tmp_ptr); + case 16: + return x86::ptr_16(tmp_ptr); + case 32: + return x86::ptr_32(tmp_ptr); + case 64: + return x86::ptr_64(tmp_ptr); + default: + throw std::runtime_error("Invalid reg size in get_reg_ptr"); + } +} +x86::Gp get_reg_for(jit_holder& jh, unsigned idx){ + //can check for regs in jh and return them instead of creating new ones + switch(traits::reg_bit_widths[idx]){ + case 8: + return jh.cc.newInt8(); + case 16: + return jh.cc.newInt16(); + case 32: + return jh.cc.newInt32(); + case 64: + return jh.cc.newInt64(); + default: + throw std::runtime_error("Invalid reg size in get_reg_ptr"); + } +} +x86::Gp get_reg_for(jit_holder& jh, unsigned size, bool is_signed){ + if(is_signed) + switch(size){ + case 8: + return jh.cc.newInt8(); + case 16: + return jh.cc.newInt16(); + case 32: + return jh.cc.newInt32(); + case 64: + return jh.cc.newInt64(); + default: + throw std::runtime_error("Invalid reg size in get_reg_ptr"); + } + else + switch(size){ + case 8: + return jh.cc.newUInt8(); + case 16: + return jh.cc.newUInt16(); + case 32: + return jh.cc.newUInt32(); + case 64: + return jh.cc.newUInt64(); + default: + throw std::runtime_error("Invalid reg size in get_reg_ptr"); + } +} +inline x86::Gp load_reg_from_mem(jit_holder& jh, unsigned idx){ + auto ptr = get_reg_ptr(jh, idx); + auto reg = get_reg_for(jh, idx); + jh.cc.mov(reg, ptr); + return reg; +} +inline void write_reg_to_mem(jit_holder& jh, x86::Gp reg, unsigned idx){ + auto ptr = get_reg_ptr(jh, idx); + jh.cc.mov(ptr, reg); +} + +void gen_instr_prologue(jit_holder& jh, addr_t pc){ + auto& cc = jh.cc; + + cc.comment("\n//(*icount)++;"); + cc.inc(get_reg_ptr(jh, traits::ICOUNT)); + + cc.comment("\n//*pc=*next_pc;"); + cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc); + + cc.comment("\n//*trap_state=*pending_trap;"); + cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), jh.trap_state); + + cc.comment("\n//increment *next_pc"); + cc.mov(jh.next_pc, pc); + +} +void gen_instr_epilogue(jit_holder& jh){ + auto& cc = jh.cc; + + cc.comment("\n//if(*trap_state!=0) goto trap_entry;"); + cc.test(jh.trap_state, jh.trap_state); + cc.jnz(jh.trap_entry); + + //Does this need to be done after every single instruction? + cc.comment("\n//write back regs to mem"); + write_reg_to_mem(jh, jh.pc, traits::PC); + write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC); + write_reg_to_mem(jh, jh.trap_state, traits::TRAP_STATE); + + +} +void gen_block_prologue(jit_holder& jh) override{ + + jh.pc = load_reg_from_mem(jh, traits::PC); + jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC); + jh.trap_state = load_reg_from_mem(jh, traits::TRAP_STATE); +} +void gen_block_epilogue(jit_holder& jh) override{ + x86::Compiler& cc = jh.cc; + cc.comment("\n//return *next_pc;"); + cc.ret(jh.next_pc); + + cc.bind(jh.trap_entry); + cc.comment("\n//enter_trap(core_ptr, *trap_state, *pc, 0);"); + + x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE); + cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE)); + + x86::Gp current_pc = get_reg_for(jh, traits::PC); + cc.mov(current_pc, get_reg_ptr(jh, traits::PC)); + + x86::Gp instr = cc.newInt32("instr"); + cc.mov(instr, 0); + InvokeNode* call_enter_trap; + cc.invoke(&call_enter_trap, &enter_trap, FuncSignatureT()); + call_enter_trap->setArg(0, jh.arch_if_ptr); + call_enter_trap->setArg(1, current_trap_state); + call_enter_trap->setArg(2, current_pc); + call_enter_trap->setArg(3, instr); + cc.comment("\n//*last_branch = std::numeric_limits::max();"); + cc.mov(get_reg_ptr(jh,traits::LAST_BRANCH), std::numeric_limits::max()); + cc.comment("\n//return *next_pc;"); + cc.ret(jh.next_pc); + +} +//TODO implement + +void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) { + jh.cc.comment("//gen_raise"); +} +void gen_wait(jit_holder& jh, unsigned type) { + jh.cc.comment("//gen_wait"); +} +void gen_leave(jit_holder& jh, unsigned lvl){ + jh.cc.comment("//gen_leave"); +} + +enum operation {add, sub, band, bor, bxor, shl, sar , shr}; + +template ::value || std::is_same::value>> +x86::Gp gen_operation(jit_holder& jh, operation op, x86::Gp a, T b){ + x86::Compiler& cc = jh.cc; + switch (op) { + case add: { cc.add(a, b); break; } + case sub: { cc.sub(a, b); break; } + case band: { cc.and_(a, b); break; } + case bor: { cc.or_(a, b); break; } + case bxor: { cc.xor_(a, b); break; } + case shl: { cc.shl(a, b); break; } + case sar: { cc.sar(a, b); break; } + case shr: { cc.shr(a, b); break; } + default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (operation)", op)); + } + return a; +} + +enum three_operand_operation{imul, mul, idiv, div, srem, urem}; + +x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, x86::Gp b){ + x86::Compiler& cc = jh.cc; + switch (op) { + case imul: { + x86::Gp dummy = cc.newInt64(); + cc.imul(dummy, a.r64(), b.r64()); + return a; + } + case mul: { + x86::Gp dummy = cc.newInt64(); + cc.mul(dummy, a.r64(), b.r64()); + return a; + } + case idiv: { + x86::Gp dummy = cc.newInt64(); + cc.mov(dummy, 0); + cc.idiv(dummy, a.r64(), b.r64()); + return a; + } + case div: { + x86::Gp dummy = cc.newInt64(); + cc.mov(dummy, 0); + cc.div(dummy, a.r64(), b.r64()); + return a; + } + case srem:{ + x86::Gp rem = cc.newInt32(); + cc.mov(rem, 0); + auto a_reg = cc.newInt32(); + cc.mov(a_reg, a.r32()); + cc.idiv(rem, a_reg, b.r32()); + return rem; + } + case urem:{ + x86::Gp rem = cc.newInt32(); + cc.mov(rem, 0); + auto a_reg = cc.newInt32(); + cc.mov(a_reg, a.r32()); + cc.div(rem, a_reg, b.r32()); + return rem; + } + + default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (three_operand)", op)); + } + return a; +} +template ::value>> +x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, T b){ + x86::Gp b_reg = jh.cc.newInt32(); +/* switch(a.size()){ + case 1: b_reg = jh.cc.newInt8(); break; + case 2: b_reg = jh.cc.newInt16(); break; + case 4: b_reg = jh.cc.newInt32(); break; + case 8: b_reg = jh.cc.newInt64(); break; + default: throw std::runtime_error(fmt::format("Invalid size ({}) in gen operation", a.size())); + } */ + jh.cc.mov(b_reg, b); + return gen_operation(jh, op, a, b_reg); +} +enum comparison_operation{land, lor, eq, ne, lt, ltu, gt, gtu, lte, lteu, gte, gteu}; + +template ::value || std::is_same::value>> +x86::Gp gen_operation(jit_holder& jh, comparison_operation op, x86::Gp a, T b){ + x86::Compiler& cc = jh.cc; + x86::Gp tmp = cc.newInt8(); + cc.mov(tmp,1); + Label label_then = cc.newLabel(); + cc.cmp(a,b); + switch (op) { + case eq: cc.je(label_then); break; + case ne: cc.jne(label_then); break; + case lt: cc.jl(label_then); break; + case ltu: cc.jb(label_then); break; + case gt: cc.jg(label_then); break; + case gtu: cc.ja(label_then); break; + case lte: cc.jle(label_then); break; + case lteu: cc.jbe(label_then); break; + case gte: cc.jge(label_then); break; + case gteu: cc.jae(label_then); break; + case land: { + Label label_false = cc.newLabel(); + cc.cmp(a, 0); + cc.je(label_false); + auto b_reg = cc.newInt8(); + cc.mov(b_reg, b); + cc.cmp(b_reg, 0); + cc.je(label_false); + cc.jmp(label_then); + cc.bind(label_false); + break; + } + case lor: { + cc.cmp(a, 0); + cc.jne(label_then); + auto b_reg = cc.newInt8(); + cc.mov(b_reg, b); + cc.cmp(b_reg, 0); + cc.jne(label_then); + break; + } + default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (comparison)", op)); + } + cc.mov(tmp,0); + cc.bind(label_then); + return tmp; +} +enum binary_operation{lnot, inc, dec, bnot, neg}; + +x86::Gp gen_operation(jit_holder& jh, binary_operation op, x86::Gp a){ + x86::Compiler& cc = jh.cc; + switch (op) { + case lnot: throw std::runtime_error("Current operation not supported in gen_operation(lnot)"); + case inc: { cc.inc(a); break; } + case dec: { cc.dec(a); break; } + case bnot: { cc.not_(a); break; } + case neg: { cc.neg(a); break; } + default: throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (unary)", op)); + } + return a; +} + +/* template +inline typename std::enable_if_t::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) const { + auto val_reg = get_reg_for(jh, sizeof(val)*8); + auto tmp = get_reg_for(jh, size); + jh.cc.mov(val_reg, val); + if(is_signed) jh.cc.movsx(tmp, val_reg); + else jh.cc.movzx(tmp,val_reg); + return tmp; +} + +template +inline typename std::enable_if_t::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) const { + auto val_reg = get_reg_for(jh, sizeof(val)*8); + auto tmp = get_reg_for(jh, size); + jh.cc.mov(val_reg, val); + if(is_signed) jh.cc.movsx(tmp, val_reg); + else jh.cc.movzx(tmp,val_reg); + return tmp; +} */ +template ::value>> +inline x86::Gp gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) { + auto val_reg = get_reg_for(jh, sizeof(val)*8); + jh.cc.mov(val_reg, val); + return gen_ext(jh, val_reg, size, is_signed); +} +//explicit Gp size cast +inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) { + auto& cc = jh.cc; + if(is_signed){ + switch(val.size()){ + case 1: cc.cbw(val); break; + case 2: cc.cwde(val); break; + case 4: cc.cdqe(val); break; + case 8: break; + default: throw std::runtime_error("Invalid register size in gen_ext"); + } + } + switch(size){ + case 8: cc.and_(val,std::numeric_limits::max()); return val.r8(); + case 16: cc.and_(val,std::numeric_limits::max()); return val.r16(); + case 32: cc.and_(val,std::numeric_limits::max()); return val.r32(); + case 64: cc.and_(val,std::numeric_limits::max()); return val.r64(); + case 128: return val.r64(); + default: throw std::runtime_error("Invalid size in gen_ext"); + } +} + +inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint32_t length){ + x86::Compiler& cc = jh.cc; + auto ret_reg = cc.newInt32(); + + auto mem_type_reg = cc.newInt32(); + cc.mov(mem_type_reg, type); + + auto space_reg = cc.newInt32(); + cc.mov(space_reg, static_cast(iss::address_type::VIRTUAL)); + + auto val_ptr = cc.newUIntPtr(); + cc.mov(val_ptr, read_mem_buf); + + InvokeNode* invokeNode; + uint64_t mask = 0; + x86::Gp val_reg = cc.newInt64(); + + switch(length){ + case 1:{ + cc.invoke(&invokeNode, &read_mem1, FuncSignatureT()); + mask = std::numeric_limits::max(); + break; + } + case 2:{ + cc.invoke(&invokeNode, &read_mem2, FuncSignatureT()); + mask = std::numeric_limits::max(); + break; + } + case 4:{ + cc.invoke(&invokeNode, &read_mem4, FuncSignatureT()); + mask = std::numeric_limits::max(); + break; + } + case 8:{ + cc.invoke(&invokeNode, &read_mem8, FuncSignatureT()); + mask = std::numeric_limits::max(); + break; + } + default: throw std::runtime_error(fmt::format("Invalid length ({}) in gen_read_mem",length)); + } + + invokeNode->setRet(0, ret_reg); + invokeNode->setArg(0, jh.arch_if_ptr); + invokeNode->setArg(1, space_reg); + invokeNode->setArg(2, mem_type_reg); + invokeNode->setArg(3, addr); + invokeNode->setArg(4, val_ptr); + + cc.mov(val_reg, x86::ptr_64(val_ptr)); + cc.and_(val_reg, mask); + cc.cmp(ret_reg,0); + cc.jne(jh.trap_entry); + return val_reg; +} +inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length){ + uint32_t length_val = 0; + auto length_ptr = jh.cc.newIntPtr(); + jh.cc.mov(length_ptr, &length_val); + jh.cc.mov(x86::ptr_32(length_ptr),length); + + return gen_read_mem(jh, type, addr, length); +} +inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length){ + auto addr_reg = jh.cc.newInt64(); + jh.cc.mov(addr_reg, addr); + + uint32_t length_val = 0; + auto length_ptr = jh.cc.newIntPtr(); + jh.cc.mov(length_ptr, &length_val); + jh.cc.mov(x86::ptr_32(length_ptr),length); + + return gen_read_mem(jh, type, addr_reg, length_val); +} +inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint32_t length){ + auto addr_reg = jh.cc.newInt64(); + jh.cc.mov(addr_reg, addr); + + return gen_read_mem(jh, type, addr_reg, length); +} +inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val){ + auto val_reg = jh.cc.newInt64(); + jh.cc.mov(val_reg, val); + gen_write_mem(jh, type, addr, val_reg); + +} +inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val){ + x86::Compiler& cc = jh.cc; + + auto mem_type_reg = cc.newInt32(); + jh.cc.mov(mem_type_reg, type); + auto space_reg = cc.newInt32(); + jh.cc.mov(space_reg, static_cast(iss::address_type::VIRTUAL)); + auto ret_reg = cc.newInt32(); + InvokeNode* invokeNode; + + if(val.isGpb()){ + cc.invoke(&invokeNode, &write_mem1, FuncSignatureT()); + } + else if(val.isGpw()){ + cc.invoke(&invokeNode, &write_mem2, FuncSignatureT()); + } + else if(val.isGpd()){ + cc.invoke(&invokeNode, &write_mem4, FuncSignatureT()); + } + else if(val.isGpq()){ + cc.invoke(&invokeNode, &write_mem8, FuncSignatureT()); + } + else throw std::runtime_error("Invalid register size in gen_write_mem"); + + invokeNode->setRet(0,ret_reg); + invokeNode->setArg(0, jh.arch_if_ptr); + invokeNode->setArg(1, space_reg); + invokeNode->setArg(2, mem_type_reg); + invokeNode->setArg(3, addr); + invokeNode->setArg(4, val); + + cc.cmp(ret_reg,0); + cc.jne(jh.trap_entry); + +} +inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val){ + auto addr_reg = jh.cc.newInt64(); + jh.cc.mov(addr_reg, addr); + gen_write_mem(jh, type, addr_reg, val); +} +inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val){ + auto val_reg = jh.cc.newInt64(); + jh.cc.mov(val_reg, val); + + auto addr_reg = jh.cc.newInt64(); + jh.cc.mov(addr_reg, addr); + gen_write_mem(jh, type, addr_reg, val_reg); + +} \ No newline at end of file diff --git a/src/vm/asmjit/vm_tgc5c.cpp b/src/vm/asmjit/vm_tgc5c.cpp new file mode 100644 index 0000000..c50aedc --- /dev/null +++ b/src/vm/asmjit/vm_tgc5c.cpp @@ -0,0 +1,3786 @@ +/******************************************************************************* + * Copyright (C) 2017, 2023 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 asmjit { + + +namespace tgc5c { +using namespace ::asmjit; +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::asmjit::vm_base { +public: + using traits = arch::traits; + using super = typename iss::asmjit::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 mem_type_e = typename super::mem_type_e; + 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; + using this_class = vm_impl; + using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&); + + continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override; + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + template::type> + inline S sext(U from) { + auto mask = (1ULL< instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; + + decoding_tree_node* root {nullptr}; + + const std::array instr_descr = {{ + /* entries are: size, valid value, valid mask, function ptr */ + /* instruction LUI, encoding '0b00000000000000000000000000110111' */ + {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, + /* instruction AUIPC, encoding '0b00000000000000000000000000010111' */ + {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc}, + /* instruction JAL, encoding '0b00000000000000000000000001101111' */ + {32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal}, + /* instruction JALR, encoding '0b00000000000000000000000001100111' */ + {32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr}, + /* instruction BEQ, encoding '0b00000000000000000000000001100011' */ + {32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq}, + /* instruction BNE, encoding '0b00000000000000000001000001100011' */ + {32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne}, + /* instruction BLT, encoding '0b00000000000000000100000001100011' */ + {32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt}, + /* instruction BGE, encoding '0b00000000000000000101000001100011' */ + {32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge}, + /* instruction BLTU, encoding '0b00000000000000000110000001100011' */ + {32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu}, + /* instruction BGEU, encoding '0b00000000000000000111000001100011' */ + {32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu}, + /* instruction LB, encoding '0b00000000000000000000000000000011' */ + {32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb}, + /* instruction LH, encoding '0b00000000000000000001000000000011' */ + {32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh}, + /* instruction LW, encoding '0b00000000000000000010000000000011' */ + {32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw}, + /* instruction LBU, encoding '0b00000000000000000100000000000011' */ + {32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu}, + /* instruction LHU, encoding '0b00000000000000000101000000000011' */ + {32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu}, + /* instruction SB, encoding '0b00000000000000000000000000100011' */ + {32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb}, + /* instruction SH, encoding '0b00000000000000000001000000100011' */ + {32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh}, + /* instruction SW, encoding '0b00000000000000000010000000100011' */ + {32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw}, + /* instruction ADDI, encoding '0b00000000000000000000000000010011' */ + {32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi}, + /* instruction SLTI, encoding '0b00000000000000000010000000010011' */ + {32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti}, + /* instruction SLTIU, encoding '0b00000000000000000011000000010011' */ + {32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu}, + /* instruction XORI, encoding '0b00000000000000000100000000010011' */ + {32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori}, + /* instruction ORI, encoding '0b00000000000000000110000000010011' */ + {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, + /* instruction ANDI, encoding '0b00000000000000000111000000010011' */ + {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, + /* instruction SLLI, encoding '0b00000000000000000001000000010011' */ + {32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli}, + /* instruction SRLI, encoding '0b00000000000000000101000000010011' */ + {32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli}, + /* instruction SRAI, encoding '0b01000000000000000101000000010011' */ + {32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai}, + /* instruction ADD, encoding '0b00000000000000000000000000110011' */ + {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, + /* instruction SUB, encoding '0b01000000000000000000000000110011' */ + {32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub}, + /* instruction SLL, encoding '0b00000000000000000001000000110011' */ + {32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll}, + /* instruction SLT, encoding '0b00000000000000000010000000110011' */ + {32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt}, + /* instruction SLTU, encoding '0b00000000000000000011000000110011' */ + {32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu}, + /* instruction XOR, encoding '0b00000000000000000100000000110011' */ + {32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor}, + /* instruction SRL, encoding '0b00000000000000000101000000110011' */ + {32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl}, + /* instruction SRA, encoding '0b01000000000000000101000000110011' */ + {32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra}, + /* instruction OR, encoding '0b00000000000000000110000000110011' */ + {32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or}, + /* instruction AND, encoding '0b00000000000000000111000000110011' */ + {32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and}, + /* instruction FENCE, encoding '0b00000000000000000000000000001111' */ + {32, 0b00000000000000000000000000001111, 0b00000000000000000111000001111111, &this_class::__fence}, + /* instruction ECALL, encoding '0b00000000000000000000000001110011' */ + {32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall}, + /* instruction EBREAK, encoding '0b00000000000100000000000001110011' */ + {32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak}, + /* instruction MRET, encoding '0b00110000001000000000000001110011' */ + {32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret}, + /* instruction WFI, encoding '0b00010000010100000000000001110011' */ + {32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi}, + /* instruction CSRRW, encoding '0b00000000000000000001000001110011' */ + {32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw}, + /* instruction CSRRS, encoding '0b00000000000000000010000001110011' */ + {32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs}, + /* instruction CSRRC, encoding '0b00000000000000000011000001110011' */ + {32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc}, + /* instruction CSRRWI, encoding '0b00000000000000000101000001110011' */ + {32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi}, + /* instruction CSRRSI, encoding '0b00000000000000000110000001110011' */ + {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, + /* instruction CSRRCI, encoding '0b00000000000000000111000001110011' */ + {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, + /* instruction FENCE_I, encoding '0b00000000000000000001000000001111' */ + {32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i}, + /* instruction MUL, encoding '0b00000010000000000000000000110011' */ + {32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__mul}, + /* instruction MULH, encoding '0b00000010000000000001000000110011' */ + {32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__mulh}, + /* instruction MULHSU, encoding '0b00000010000000000010000000110011' */ + {32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__mulhsu}, + /* instruction MULHU, encoding '0b00000010000000000011000000110011' */ + {32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__mulhu}, + /* instruction DIV, encoding '0b00000010000000000100000000110011' */ + {32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__div}, + /* instruction DIVU, encoding '0b00000010000000000101000000110011' */ + {32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__divu}, + /* instruction REM, encoding '0b00000010000000000110000000110011' */ + {32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__rem}, + /* instruction REMU, encoding '0b00000010000000000111000000110011' */ + {32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__remu}, + /* instruction C__ADDI4SPN, encoding '0b0000000000000000' */ + {16, 0b0000000000000000, 0b1110000000000011, &this_class::__c__addi4spn}, + /* instruction C__LW, encoding '0b0100000000000000' */ + {16, 0b0100000000000000, 0b1110000000000011, &this_class::__c__lw}, + /* instruction C__SW, encoding '0b1100000000000000' */ + {16, 0b1100000000000000, 0b1110000000000011, &this_class::__c__sw}, + /* instruction C__ADDI, encoding '0b0000000000000001' */ + {16, 0b0000000000000001, 0b1110000000000011, &this_class::__c__addi}, + /* instruction C__NOP, encoding '0b0000000000000001' */ + {16, 0b0000000000000001, 0b1110111110000011, &this_class::__c__nop}, + /* instruction C__JAL, encoding '0b0010000000000001' */ + {16, 0b0010000000000001, 0b1110000000000011, &this_class::__c__jal}, + /* instruction C__LI, encoding '0b0100000000000001' */ + {16, 0b0100000000000001, 0b1110000000000011, &this_class::__c__li}, + /* instruction C__LUI, encoding '0b0110000000000001' */ + {16, 0b0110000000000001, 0b1110000000000011, &this_class::__c__lui}, + /* instruction C__ADDI16SP, encoding '0b0110000100000001' */ + {16, 0b0110000100000001, 0b1110111110000011, &this_class::__c__addi16sp}, + /* instruction __reserved_clui, encoding '0b0110000000000001' */ + {16, 0b0110000000000001, 0b1111000001111111, &this_class::____reserved_clui}, + /* instruction C__SRLI, encoding '0b1000000000000001' */ + {16, 0b1000000000000001, 0b1111110000000011, &this_class::__c__srli}, + /* instruction C__SRAI, encoding '0b1000010000000001' */ + {16, 0b1000010000000001, 0b1111110000000011, &this_class::__c__srai}, + /* instruction C__ANDI, encoding '0b1000100000000001' */ + {16, 0b1000100000000001, 0b1110110000000011, &this_class::__c__andi}, + /* instruction C__SUB, encoding '0b1000110000000001' */ + {16, 0b1000110000000001, 0b1111110001100011, &this_class::__c__sub}, + /* instruction C__XOR, encoding '0b1000110000100001' */ + {16, 0b1000110000100001, 0b1111110001100011, &this_class::__c__xor}, + /* instruction C__OR, encoding '0b1000110001000001' */ + {16, 0b1000110001000001, 0b1111110001100011, &this_class::__c__or}, + /* instruction C__AND, encoding '0b1000110001100001' */ + {16, 0b1000110001100001, 0b1111110001100011, &this_class::__c__and}, + /* instruction C__J, encoding '0b1010000000000001' */ + {16, 0b1010000000000001, 0b1110000000000011, &this_class::__c__j}, + /* instruction C__BEQZ, encoding '0b1100000000000001' */ + {16, 0b1100000000000001, 0b1110000000000011, &this_class::__c__beqz}, + /* instruction C__BNEZ, encoding '0b1110000000000001' */ + {16, 0b1110000000000001, 0b1110000000000011, &this_class::__c__bnez}, + /* instruction C__SLLI, encoding '0b0000000000000010' */ + {16, 0b0000000000000010, 0b1111000000000011, &this_class::__c__slli}, + /* instruction C__LWSP, encoding '0b0100000000000010' */ + {16, 0b0100000000000010, 0b1110000000000011, &this_class::__c__lwsp}, + /* instruction C__MV, encoding '0b1000000000000010' */ + {16, 0b1000000000000010, 0b1111000000000011, &this_class::__c__mv}, + /* instruction C__JR, encoding '0b1000000000000010' */ + {16, 0b1000000000000010, 0b1111000001111111, &this_class::__c__jr}, + /* instruction __reserved_cmv, encoding '0b1000000000000010' */ + {16, 0b1000000000000010, 0b1111111111111111, &this_class::____reserved_cmv}, + /* instruction C__ADD, encoding '0b1001000000000010' */ + {16, 0b1001000000000010, 0b1111000000000011, &this_class::__c__add}, + /* instruction C__JALR, encoding '0b1001000000000010' */ + {16, 0b1001000000000010, 0b1111000001111111, &this_class::__c__jalr}, + /* instruction C__EBREAK, encoding '0b1001000000000010' */ + {16, 0b1001000000000010, 0b1111111111111111, &this_class::__c__ebreak}, + /* instruction C__SWSP, encoding '0b1100000000000010' */ + {16, 0b1100000000000010, 0b1110000000000011, &this_class::__c__swsp}, + /* instruction DII, encoding '0b0000000000000000' */ + {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, + }}; + + /* instruction definitions */ + /* instruction 0: LUI */ + continuation_e __lui(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rd = ((bit_sub<7,5>(instr))); + uint32_t imm = ((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nLUI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 0); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)((int32_t)imm)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 0); + return returnValue; + } + + /* instruction 1: AUIPC */ + continuation_e __auipc(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rd = ((bit_sub<7,5>(instr))); + uint32_t imm = ((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nAUIPC_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 1); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)(PC+(int32_t)imm)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 1); + return returnValue; + } + + /* instruction 2: JAL */ + continuation_e __jal(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rd = ((bit_sub<7,5>(instr))); + uint32_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nJAL_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 2); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)(PC+ 4)); + } + auto PC_val_v = (uint32_t)(PC+(int32_t)sext<21>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 2); + return returnValue; + } + + /* instruction 3: JALR */ + continuation_e __jalr(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nJALR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 3); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto addr_mask = (uint32_t)- 2; + auto new_pc = gen_ext(jh, + (gen_operation(jh, band, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), gen_ext(jh, addr_mask, 64, false)) + ), 32, true); + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, urem, + new_pc, static_cast(traits::INSTR_ALIGNMENT)) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + gen_raise(jh, 0, 0); + } + cc.jmp(label_merge); + cc.bind(label_else); + { + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)(PC+ 4)); + } + auto PC_val_v = new_pc; + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 3); + return returnValue; + } + + /* instruction 4: BEQ */ + continuation_e __beq(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nBEQ_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 4); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, eq, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ,0); + cc.je(label_merge); + { + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<13>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 4); + return returnValue; + } + + /* instruction 5: BNE */ + continuation_e __bne(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nBNE_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 5); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ne, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ,0); + cc.je(label_merge); + { + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<13>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 5); + return returnValue; + } + + /* instruction 6: BLT */ + continuation_e __blt(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nBLT_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 6); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, lt, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, false), gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false)) + ,0); + cc.je(label_merge); + { + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<13>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 6); + return returnValue; + } + + /* instruction 7: BGE */ + continuation_e __bge(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nBGE_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 7); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, gte, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, false), gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false)) + ,0); + cc.je(label_merge); + { + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<13>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 7); + return returnValue; + } + + /* instruction 8: BLTU */ + continuation_e __bltu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nBLTU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 8); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ltu, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ,0); + cc.je(label_merge); + { + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<13>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 8); + return returnValue; + } + + /* instruction 9: BGEU */ + continuation_e __bgeu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nBGEU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 9); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, gteu, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ,0); + cc.je(label_merge); + { + if(imm%static_cast(traits::INSTR_ALIGNMENT)){ gen_raise(jh, 0, 0); + } + else{ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<13>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + } + cc.bind(label_merge); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 9); + return returnValue; + } + + /* instruction 10: LB */ + continuation_e __lb(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nLB_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 10); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto load_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + auto res = gen_ext(jh, + gen_read_mem(jh, traits::MEM, load_address, 1), 8, false); + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + res, 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 10); + return returnValue; + } + + /* instruction 11: LH */ + continuation_e __lh(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nLH_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 11); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto load_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + auto res = gen_ext(jh, + gen_read_mem(jh, traits::MEM, load_address, 2), 16, false); + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + res, 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 11); + return returnValue; + } + + /* instruction 12: LW */ + continuation_e __lw(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nLW_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 12); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto load_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + auto res = gen_ext(jh, + gen_read_mem(jh, traits::MEM, load_address, 4), 32, false); + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + res, 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 12); + return returnValue; + } + + /* instruction 13: LBU */ + continuation_e __lbu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nLBU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 13); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto load_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + auto res = gen_read_mem(jh, traits::MEM, load_address, 1); + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + res, 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 13); + return returnValue; + } + + /* instruction 14: LHU */ + continuation_e __lhu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nLHU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 14); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto load_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + auto res = gen_read_mem(jh, traits::MEM, load_address, 2); + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + res, 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 14); + return returnValue; + } + + /* instruction 15: SB */ + continuation_e __sb(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSB_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 15); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto store_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + gen_write_mem(jh, traits::MEM, + store_address, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 8, false)); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 15); + return returnValue; + } + + /* instruction 16: SH */ + continuation_e __sh(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSH_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 16); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto store_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + gen_write_mem(jh, traits::MEM, + store_address, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 16, false)); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 16); + return returnValue; + } + + /* instruction 17: SW */ + continuation_e __sw(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSW_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 17); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto store_address = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true); + gen_write_mem(jh, traits::MEM, + store_address, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false)); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 17); + return returnValue; + } + + /* instruction 18: ADDI */ + continuation_e __addi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nADDI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 18); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int16_t)sext<12>(imm), 64, true)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 18); + return returnValue; + } + + /* instruction 19: SLTI */ + continuation_e __slti(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSLTI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 19); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + { + auto label_then = cc.newLabel(); + auto label_merge = cc.newLabel(); + auto tmp_reg = get_reg_for(jh, 1); + cc.cmp(gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), (int16_t)sext<12>(imm)); + cc.jl(label_then); + cc.mov(tmp_reg, 0); + cc.jmp(label_merge); + cc.bind(label_then); + cc.mov(tmp_reg, 1); + cc.bind(label_merge); + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, tmp_reg + , 32, false) + ); + } + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 19); + return returnValue; + } + + /* instruction 20: SLTIU */ + continuation_e __sltiu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSLTIU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 20); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + { + auto label_then = cc.newLabel(); + auto label_merge = cc.newLabel(); + auto tmp_reg = get_reg_for(jh, 1); + cc.cmp(load_reg_from_mem(jh, traits::X0 + rs1), (uint32_t)((int16_t)sext<12>(imm))); + cc.jb(label_then); + cc.mov(tmp_reg, 0); + cc.jmp(label_merge); + cc.bind(label_then); + cc.mov(tmp_reg, 1); + cc.bind(label_merge); + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, tmp_reg + , 32, false) + ); + } + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 20); + return returnValue; + } + + /* instruction 21: XORI */ + continuation_e __xori(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nXORI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 21); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, bxor, + load_reg_from_mem(jh, traits::X0 + rs1), (uint32_t)((int16_t)sext<12>(imm))) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 21); + return returnValue; + } + + /* instruction 22: ORI */ + continuation_e __ori(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nORI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 22); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, bor, + load_reg_from_mem(jh, traits::X0 + rs1), (uint32_t)((int16_t)sext<12>(imm))) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 22); + return returnValue; + } + + /* instruction 23: ANDI */ + continuation_e __andi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nANDI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 23); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, band, + load_reg_from_mem(jh, traits::X0 + rs1), (uint32_t)((int16_t)sext<12>(imm))) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 23); + return returnValue; + } + + /* instruction 24: SLLI */ + continuation_e __slli(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSLLI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 24); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, shl, + load_reg_from_mem(jh, traits::X0 + rs1), gen_ext(jh, shamt, 32, false)) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 24); + return returnValue; + } + + /* instruction 25: SRLI */ + continuation_e __srli(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSRLI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 25); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, shr, + load_reg_from_mem(jh, traits::X0 + rs1), gen_ext(jh, shamt, 32, false)) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 25); + return returnValue; + } + + /* instruction 26: SRAI */ + continuation_e __srai(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSRAI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 26); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, sar, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), gen_ext(jh, shamt, 32, false)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 26); + return returnValue; + } + + /* instruction 27: ADD */ + continuation_e __add(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nADD_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 27); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2), 64, false)) + ), 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 27); + return returnValue; + } + + /* instruction 28: SUB */ + continuation_e __sub(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSUB_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 28); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, sub, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2), 64, false)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 28); + return returnValue; + } + + /* instruction 29: SLL */ + continuation_e __sll(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSLL_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 29); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, gen_operation(jh, shl, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), (gen_operation(jh, band, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2), 64, false), (static_cast(traits::XLEN)- 1)) + )) + , 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 29); + return returnValue; + } + + /* instruction 30: SLT */ + continuation_e __slt(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSLT_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 30); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + { + auto label_then = cc.newLabel(); + auto label_merge = cc.newLabel(); + auto tmp_reg = get_reg_for(jh, 1); + cc.cmp(gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, true)); + cc.jl(label_then); + cc.mov(tmp_reg, 0); + cc.jmp(label_merge); + cc.bind(label_then); + cc.mov(tmp_reg, 1); + cc.bind(label_merge); + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, tmp_reg + , 32, false) + ); + } + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 30); + return returnValue; + } + + /* instruction 31: SLTU */ + continuation_e __sltu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSLTU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 31); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + { + auto label_then = cc.newLabel(); + auto label_merge = cc.newLabel(); + auto tmp_reg = get_reg_for(jh, 1); + cc.cmp(load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)); + cc.jb(label_then); + cc.mov(tmp_reg, 0); + cc.jmp(label_merge); + cc.bind(label_then); + cc.mov(tmp_reg, 1); + cc.bind(label_merge); + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, tmp_reg + , 32, false) + ); + } + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 31); + return returnValue; + } + + /* instruction 32: XOR */ + continuation_e __xor(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nXOR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 32); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, bxor, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 32); + return returnValue; + } + + /* instruction 33: SRL */ + continuation_e __srl(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSRL_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 33); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, gen_operation(jh, shr, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), (gen_operation(jh, band, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2), 64, false), (static_cast(traits::XLEN)- 1)) + )) + , 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 33); + return returnValue; + } + + /* instruction 34: SRA */ + continuation_e __sra(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nSRA_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 34); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_ext(jh, gen_operation(jh, sar, + gen_ext(jh, gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), 64, true), (gen_operation(jh, band, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2), 64, false), (static_cast(traits::XLEN)- 1)) + )) + , 32, true)), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 34); + return returnValue; + } + + /* instruction 35: OR */ + continuation_e __or(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nOR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 35); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, bor, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 35); + return returnValue; + } + + /* instruction 36: AND */ + continuation_e __and(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nAND_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 36); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, band, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 36); + return returnValue; + } + + /* instruction 37: FENCE */ + continuation_e __fence(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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))); + uint8_t fm = ((bit_sub<28,4>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nFENCE_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 37); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_write_mem(jh, traits::FENCE, + static_cast(traits::fence), + (uint8_t)pred<< 4|succ); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 37); + return returnValue; + } + + /* instruction 38: ECALL */ + continuation_e __ecall(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nECALL_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 38); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_raise(jh, 0, 11); + auto returnValue = TRAP; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 38); + return returnValue; + } + + /* instruction 39: EBREAK */ + continuation_e __ebreak(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nEBREAK_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 39); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_raise(jh, 0, 3); + auto returnValue = TRAP; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 39); + return returnValue; + } + + /* instruction 40: MRET */ + continuation_e __mret(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nMRET_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 40); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_leave(jh, 3); + auto returnValue = TRAP; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 40); + return returnValue; + } + + /* instruction 41: WFI */ + continuation_e __wfi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nWFI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 41); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_wait(jh, 1); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 41); + return returnValue; + } + + /* instruction 42: CSRRW */ + continuation_e __csrrw(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nCSRRW_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 42); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto xrs1 = load_reg_from_mem(jh, traits::X0 + rs1); + if(rd!= 0){ auto xrd = gen_read_mem(jh, traits::CSR, csr, 4); + gen_write_mem(jh, traits::CSR, + csr, + xrs1); + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + xrd); + } + else{ + gen_write_mem(jh, traits::CSR, + csr, + xrs1); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 42); + return returnValue; + } + + /* instruction 43: CSRRS */ + continuation_e __csrrs(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nCSRRS_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 43); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto xrd = gen_read_mem(jh, traits::CSR, csr, 4); + auto xrs1 = load_reg_from_mem(jh, traits::X0 + rs1); + if(rs1!= 0) { + gen_write_mem(jh, traits::CSR, + csr, + gen_operation(jh, bor, + xrd, xrs1) + ); + } + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + xrd); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 43); + return returnValue; + } + + /* instruction 44: CSRRC */ + continuation_e __csrrc(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nCSRRC_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 44); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto xrd = gen_read_mem(jh, traits::CSR, csr, 4); + auto xrs1 = load_reg_from_mem(jh, traits::X0 + rs1); + if(rs1!= 0) { + gen_write_mem(jh, traits::CSR, + csr, + gen_operation(jh, band, + xrd, gen_operation(jh, bnot, xrs1)) + ); + } + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + xrd); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 44); + return returnValue; + } + + /* instruction 45: CSRRWI */ + continuation_e __csrrwi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nCSRRWI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 45); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto xrd = gen_read_mem(jh, traits::CSR, csr, 4); + gen_write_mem(jh, traits::CSR, + csr, + (uint32_t)zimm); + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + xrd); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 45); + return returnValue; + } + + /* instruction 46: CSRRSI */ + continuation_e __csrrsi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nCSRRSI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 46); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto xrd = gen_read_mem(jh, traits::CSR, csr, 4); + if(zimm!= 0) { + gen_write_mem(jh, traits::CSR, + csr, + gen_operation(jh, bor, + xrd, (uint32_t)zimm) + ); + } + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + xrd); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 46); + return returnValue; + } + + /* instruction 47: CSRRCI */ + continuation_e __csrrci(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nCSRRCI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 47); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto xrd = gen_read_mem(jh, traits::CSR, csr, 4); + if(zimm!= 0) { + gen_write_mem(jh, traits::CSR, + csr, + gen_operation(jh, band, + xrd, ~ ((uint32_t)zimm)) + ); + } + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + xrd); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 47); + return returnValue; + } + + /* instruction 48: FENCE_I */ + continuation_e __fence_i(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nFENCE_I_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 48); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_write_mem(jh, traits::FENCE, + static_cast(traits::fencei), + imm); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 48); + return returnValue; + } + + /* instruction 49: MUL */ + continuation_e __mul(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nMUL_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 49); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto res = gen_ext(jh, + (gen_operation(jh, imul, + gen_ext(jh, gen_ext(jh, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), 64, true), 128, true), gen_ext(jh, gen_ext(jh, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, true), 64, true), 128, true)) + ), 64, true); + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + res, 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 49); + return returnValue; + } + + /* instruction 50: MULH */ + continuation_e __mulh(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nMULH_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 50); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto res = gen_ext(jh, + (gen_operation(jh, imul, + gen_ext(jh, gen_ext(jh, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), 64, true), 128, true), gen_ext(jh, gen_ext(jh, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, true), 64, true), 128, true)) + ), 64, true); + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, sar, + res, gen_ext(jh, static_cast(traits::XLEN), 64, false)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 50); + return returnValue; + } + + /* instruction 51: MULHSU */ + continuation_e __mulhsu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nMULHSU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 51); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto res = gen_ext(jh, + (gen_operation(jh, imul, + gen_ext(jh, gen_ext(jh, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, true), 64, true), 128, true), gen_ext(jh, gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 64, false), 128, false)) + ), 64, true); + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, sar, + res, gen_ext(jh, static_cast(traits::XLEN), 64, false)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 51); + return returnValue; + } + + /* instruction 52: MULHU */ + continuation_e __mulhu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nMULHU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 52); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto res = gen_ext(jh, + (gen_operation(jh, mul, + gen_ext(jh, gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 64, false), 128, false), gen_ext(jh, gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 64, false), 128, false)) + ), 64, false); + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, shr, + res, gen_ext(jh, static_cast(traits::XLEN), 64, false)) + ), 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 52); + return returnValue; + } + + /* instruction 53: DIV */ + continuation_e __div(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nDIV_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 53); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto dividend = gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, false); + auto divisor = gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false); + if(rd!= 0){ auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ne, + divisor, gen_ext(jh, 0, 32, false)) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + auto MMIN = ((uint32_t)1)<<(static_cast(traits::XLEN)-1); + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, land, + gen_operation(jh, eq, + load_reg_from_mem(jh, traits::X0 + rs1), MMIN) + , gen_operation(jh, eq, + divisor, gen_ext(jh, - 1, 32, true)) + ) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + MMIN); + } + cc.jmp(label_merge); + cc.bind(label_else); + { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, idiv, + gen_ext(jh, dividend, 64, true), gen_ext(jh, divisor, 64, true)) + ), 32, true)); + } + cc.bind(label_merge); + } + cc.jmp(label_merge); + cc.bind(label_else); + { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)- 1); + } + cc.bind(label_merge); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 53); + return returnValue; + } + + /* instruction 54: DIVU */ + continuation_e __divu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nDIVU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 54); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ne, + load_reg_from_mem(jh, traits::X0 + rs2), gen_ext(jh, 0, 32, false)) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, div, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ), 32, false)); + } + } + cc.jmp(label_merge); + cc.bind(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)- 1); + } + } + cc.bind(label_merge); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 54); + return returnValue; + } + + /* instruction 55: REM */ + continuation_e __rem(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nREM_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 55); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ne, + load_reg_from_mem(jh, traits::X0 + rs2), gen_ext(jh, 0, 32, false)) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + auto MMIN = (uint32_t)1<<(static_cast(traits::XLEN)-1); + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, land, + gen_operation(jh, eq, + load_reg_from_mem(jh, traits::X0 + rs1), MMIN) + , gen_operation(jh, eq, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false), gen_ext(jh, - 1, 32, true)) + ) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, 0, 32, false) + ); + } + } + cc.jmp(label_merge); + cc.bind(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, srem, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1), 32, false), gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false)) + ), 32, true)); + } + } + cc.bind(label_merge); + } + cc.jmp(label_merge); + cc.bind(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + load_reg_from_mem(jh, traits::X0 + rs1)); + } + } + cc.bind(label_merge); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 55); + return returnValue; + } + + /* instruction 56: REMU */ + continuation_e __remu(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nREMU_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 56); + pc=pc+ 4; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rs1>=static_cast(traits::RFS)||rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ne, + load_reg_from_mem(jh, traits::X0 + rs2), gen_ext(jh, 0, 32, false)) + ,0); + auto label_else = cc.newLabel(); + cc.je(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_operation(jh, urem, + load_reg_from_mem(jh, traits::X0 + rs1), load_reg_from_mem(jh, traits::X0 + rs2)) + ); + } + } + cc.jmp(label_merge); + cc.bind(label_else); + { + if(rd!=0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + load_reg_from_mem(jh, traits::X0 + rs1)); + } + } + cc.bind(label_merge); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 56); + return returnValue; + } + + /* instruction 57: C__ADDI4SPN */ + continuation_e __c__addi4spn(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__ADDI4SPN_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 57); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(imm) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd+ 8), + gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + 2), 64, false), gen_ext(jh, imm, 64, false)) + ), 32, false)); + } + else{ + gen_raise(jh, 0, 2); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 57); + return returnValue; + } + + /* instruction 58: C__LW */ + continuation_e __c__lw(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__LW_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 58); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + auto offs = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1+ 8), 64, false), gen_ext(jh, uimm, 64, false)) + ), 32, false); + cc.mov(get_reg_ptr(jh, traits::X0+ rd+ 8), + gen_ext(jh, + gen_ext(jh, + gen_read_mem(jh, traits::MEM, offs, 4), 32, false), 32, true)); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 58); + return returnValue; + } + + /* instruction 59: C__SW */ + continuation_e __c__sw(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__SW_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 59); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + auto offs = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1+ 8), 64, false), gen_ext(jh, uimm, 64, false)) + ), 32, false); + gen_write_mem(jh, traits::MEM, + offs, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2+ 8), 32, false)); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 59); + return returnValue; + } + + /* instruction 60: C__ADDI */ + continuation_e __c__addi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t imm = ((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__ADDI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 60); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rs1!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rs1), + gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs1), 64, false), gen_ext(jh, (int8_t)sext<6>(imm), 64, true)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 60); + return returnValue; + } + + /* instruction 61: C__NOP */ + continuation_e __c__nop(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t nzimm = ((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__NOP_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 61); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 61); + return returnValue; + } + + /* instruction 62: C__JAL */ + continuation_e __c__jal(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__JAL_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 62); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ 1), + (uint32_t)(PC+ 2)); + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<12>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 62); + return returnValue; + } + + /* instruction 63: C__LI */ + continuation_e __c__li(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t imm = ((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__LI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 63); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)((int8_t)sext<6>(imm))); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 63); + return returnValue; + } + + /* instruction 64: C__LUI */ + continuation_e __c__lui(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint32_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__LUI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 64); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(imm== 0||rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + (uint32_t)((int32_t)sext<18>(imm))); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 64); + return returnValue; + } + + /* instruction 65: C__ADDI16SP */ + continuation_e __c__addi16sp(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t nzimm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__ADDI16SP_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 65); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(nzimm) { + cc.mov(get_reg_ptr(jh, traits::X0+ 2), + gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + 2), 64, false), gen_ext(jh, (int16_t)sext<10>(nzimm), 64, true)) + ), 32, true)); + } + else{ + gen_raise(jh, 0, 2); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 65); + return returnValue; + } + + /* instruction 66: __reserved_clui */ + continuation_e ____reserved_clui(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\n__reserved_clui_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 66); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_raise(jh, 0, 2); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 66); + return returnValue; + } + + /* instruction 67: C__SRLI */ + continuation_e __c__srli(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__SRLI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 67); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ rs1+ 8), + gen_operation(jh, shr, + load_reg_from_mem(jh, traits::X0 + rs1+ 8), gen_ext(jh, shamt, 32, false)) + ); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 67); + return returnValue; + } + + /* instruction 68: C__SRAI */ + continuation_e __c__srai(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__SRAI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 68); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(shamt){ cc.mov(get_reg_ptr(jh, traits::X0+ rs1+ 8), + gen_ext(jh, + (gen_operation(jh, sar, + (gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1+ 8), 32, false)), gen_ext(jh, shamt, 32, false)) + ), 32, true)); + } + else{ + if(static_cast(traits::XLEN)== 128){ cc.mov(get_reg_ptr(jh, traits::X0+ rs1+ 8), + gen_ext(jh, + (gen_operation(jh, sar, + (gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs1+ 8), 32, false)), gen_ext(jh, 64, 32, false)) + ), 32, true)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 68); + return returnValue; + } + + /* instruction 69: C__ANDI */ + continuation_e __c__andi(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t imm = ((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__ANDI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 69); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ rs1+ 8), + gen_ext(jh, + (gen_operation(jh, band, + load_reg_from_mem(jh, traits::X0 + rs1+ 8), gen_ext(jh, (int8_t)sext<6>(imm), 32, true)) + ), 32, true)); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 69); + return returnValue; + } + + /* instruction 70: C__SUB */ + continuation_e __c__sub(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__SUB_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 70); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ rd+ 8), + gen_ext(jh, + (gen_operation(jh, sub, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rd+ 8), 64, false), gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2+ 8), 64, false)) + ), 32, true)); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 70); + return returnValue; + } + + /* instruction 71: C__XOR */ + continuation_e __c__xor(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__XOR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 71); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ rd+ 8), + gen_operation(jh, bxor, + load_reg_from_mem(jh, traits::X0 + rd+ 8), load_reg_from_mem(jh, traits::X0 + rs2+ 8)) + ); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 71); + return returnValue; + } + + /* instruction 72: C__OR */ + continuation_e __c__or(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__OR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 72); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ rd+ 8), + gen_operation(jh, bor, + load_reg_from_mem(jh, traits::X0 + rd+ 8), load_reg_from_mem(jh, traits::X0 + rs2+ 8)) + ); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 72); + return returnValue; + } + + /* instruction 73: C__AND */ + continuation_e __c__and(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__AND_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 73); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + cc.mov(get_reg_ptr(jh, traits::X0+ rd+ 8), + gen_operation(jh, band, + load_reg_from_mem(jh, traits::X0 + rd+ 8), load_reg_from_mem(jh, traits::X0 + rs2+ 8)) + ); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 73); + return returnValue; + } + + /* instruction 74: C__J */ + continuation_e __c__j(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__J_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 74); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<12>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 74); + return returnValue; + } + + /* instruction 75: C__BEQZ */ + continuation_e __c__beqz(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__BEQZ_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 75); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, eq, + load_reg_from_mem(jh, traits::X0 + rs1+ 8), gen_ext(jh, 0, 32, false)) + ,0); + cc.je(label_merge); + { + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<9>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + cc.bind(label_merge); + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 75); + return returnValue; + } + + /* instruction 76: C__BNEZ */ + continuation_e __c__bnez(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint16_t imm = ((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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__BNEZ_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 76); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + auto label_merge = cc.newLabel(); + cc.cmp(gen_operation(jh, ne, + load_reg_from_mem(jh, traits::X0 + rs1+ 8), gen_ext(jh, 0, 32, false)) + ,0); + cc.je(label_merge); + { + auto PC_val_v = (uint32_t)(PC+(int16_t)sext<9>(imm)); + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + cc.bind(label_merge); + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 76); + return returnValue; + } + + /* instruction 77: C__SLLI */ + continuation_e __c__slli(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t nzuimm = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__SLLI_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 77); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rs1!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rs1), + gen_operation(jh, shl, + load_reg_from_mem(jh, traits::X0 + rs1), gen_ext(jh, nzuimm, 32, false)) + ); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 77); + return returnValue; + } + + /* instruction 78: C__LWSP */ + continuation_e __c__lwsp(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__LWSP_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 78); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)||rd== 0) { + gen_raise(jh, 0, 2); + } + else{ + auto offs = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + 2), 64, false), gen_ext(jh, uimm, 64, false)) + ), 32, false); + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + gen_ext(jh, + gen_read_mem(jh, traits::MEM, offs, 4), 32, false), 32, true)); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 78); + return returnValue; + } + + /* instruction 79: C__MV */ + continuation_e __c__mv(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__MV_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 79); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + load_reg_from_mem(jh, traits::X0 + rs2)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 79); + return returnValue; + } + + /* instruction 80: C__JR */ + continuation_e __c__jr(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__JR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 80); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs1&&rs1(traits::RFS)) { + auto PC_val_v = gen_operation(jh, band, + load_reg_from_mem(jh, traits::X0 + rs1%static_cast(traits::RFS)), gen_ext(jh, ~ 0x1, 32, false)) + ; + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + else{ + gen_raise(jh, 0, 2); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 80); + return returnValue; + } + + /* instruction 81: __reserved_cmv */ + continuation_e ____reserved_cmv(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\n__reserved_cmv_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 81); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_raise(jh, 0, 2); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 81); + return returnValue; + } + + /* instruction 82: C__ADD */ + continuation_e __c__add(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__ADD_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 82); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rd>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + if(rd!= 0) { + cc.mov(get_reg_ptr(jh, traits::X0+ rd), + gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rd), 64, false), gen_ext(jh, load_reg_from_mem(jh, traits::X0 + rs2), 64, false)) + ), 32, false)); + } + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 82); + return returnValue; + } + + /* instruction 83: C__JALR */ + continuation_e __c__jalr(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__JALR_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 83); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs1>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto new_pc = load_reg_from_mem(jh, traits::X0 + rs1); + cc.mov(get_reg_ptr(jh, traits::X0+ 1), + (uint32_t)(PC+ 2)); + auto PC_val_v = gen_operation(jh, band, + new_pc, gen_ext(jh, ~ 0x1, 32, false)) + ; + cc.mov(jh.next_pc, PC_val_v); + cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), 32U); + } + auto returnValue = BRANCH; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 83); + return returnValue; + } + + /* instruction 84: C__EBREAK */ + continuation_e __c__ebreak(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__EBREAK_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 84); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_raise(jh, 0, 3); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 84); + return returnValue; + } + + /* instruction 85: C__SWSP */ + continuation_e __c__swsp(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + 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 disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nC__SWSP_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 85); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + if(rs2>=static_cast(traits::RFS)) { + gen_raise(jh, 0, 2); + } + else{ + auto offs = gen_ext(jh, + (gen_operation(jh, add, + gen_ext(jh, load_reg_from_mem(jh, traits::X0 + 2), 64, false), gen_ext(jh, uimm, 64, false)) + ), 32, false); + gen_write_mem(jh, traits::MEM, + offs, + gen_ext(jh, + load_reg_from_mem(jh, traits::X0 + rs2), 32, false)); + } + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 85); + return returnValue; + } + + /* instruction 86: DII */ + continuation_e __dii(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ + uint64_t PC = pc.val; + if(this->disass_enabled){ + /* generate disass */ + } + x86::Compiler& cc = jh.cc; + //ideally only do this if necessary (someone / plugin needs it) + cc.mov(jh.pc,PC); + cc.comment(fmt::format("\nDII_{:#x}:",pc.val).c_str()); + this->gen_sync(jh, PRE_SYNC, 86); + pc=pc+ 2; + + gen_instr_prologue(jh, pc.val); + cc.comment("\n//behavior:"); + /*generate behavior*/ + gen_raise(jh, 0, 2); + auto returnValue = CONT; + + gen_instr_epilogue(jh); + this->gen_sync(jh, POST_SYNC, 86); + return returnValue; + } + + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) { + + return BRANCH; + } + //decoding functionality + + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + compile_func decode_instr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decode_instr(child, word); + } + } + } + return nullptr; + } +}; + +template void debug_fn(CODE_WORD instr) { + volatile CODE_WORD x = instr; + instr = 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) { + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr: instr_descr){ + root->instrs.push_back(instr); + } + populate_decoding_tree(root); +} + +template +continuation_e +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) { + enum {TRAP_ID=1<<16}; + code_word_t instr = 0; + phys_addr_t paddr(pc); + auto *const data = (uint8_t *)&instr; + if(this->core.has_mmu()) + paddr = this->core.virt2phys(pc); + auto res = this->core.read(paddr, 4, data); + if (res != iss::Ok) + throw trap_access(TRAP_ID, pc.val); + if (instr == 0x0000006f || (instr&0xffff)==0xa001) + throw simulation_stopped(0); // 'J 0' or 'C.J 0' + ++inst_cnt; + auto f = decode_instr(root, instr); + if (f == nullptr) + f = &this_class::illegal_intruction; + return (this->*f)(pc, instr, jh); +} + + + +} // namespace tgc5c + +template <> +std::unique_ptr create(arch::tgc5c *core, unsigned short port, bool dump) { + auto ret = new tgc5c::vm_impl(*core, dump); + if (port != 0) debugger::server::run_server(ret, port); + return std::unique_ptr(ret); +} +} // namespace asmjit +} // namespace iss + +#include +#include +#include +namespace iss { +namespace { +volatile std::array dummy = { + core_factory::instance().register_creator("tgc5c|m_p|asmjit", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_m_p(); + auto* vm = new asmjit::tgc5c::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }), + core_factory::instance().register_creator("tgc5c|mu_p|asmjit", [](unsigned port, void*) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_mu_p(); + auto* vm = new asmjit::tgc5c::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + return {cpu_ptr{cpu}, vm_ptr{vm}}; + }) +}; +} +}