From 8fce0c4759203c049a2dfae625ee38e7c0db6b40 Mon Sep 17 00:00:00 2001 From: Stanislaw Kaushanski Date: Thu, 20 Aug 2020 17:29:36 +0200 Subject: [PATCH] Generate TGF01 and TGF02 cores --- gen_input/TGFS.core_desc | 24 + incl/iss/arch/tgf01.h | 252 +++ incl/iss/arch/tgf02.h | 252 +++ src/iss/tgf01.cpp | 69 + src/iss/tgf02.cpp | 69 + src/vm/tcc/vm_tgf01.cpp | 2086 ++++++++++++++++++++++++ src/vm/tcc/vm_tgf02.cpp | 3278 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 6030 insertions(+) create mode 100644 gen_input/TGFS.core_desc create mode 100644 incl/iss/arch/tgf01.h create mode 100644 incl/iss/arch/tgf02.h create mode 100644 src/iss/tgf01.cpp create mode 100644 src/iss/tgf02.cpp create mode 100644 src/vm/tcc/vm_tgf01.cpp create mode 100644 src/vm/tcc/vm_tgf02.cpp diff --git a/gen_input/TGFS.core_desc b/gen_input/TGFS.core_desc new file mode 100644 index 0000000..c93377e --- /dev/null +++ b/gen_input/TGFS.core_desc @@ -0,0 +1,24 @@ +import "RV32I.core_desc" +import "RVM.core_desc" +import "RVC.core_desc" + +Core TGF01 provides RV32I { + constants { + XLEN:=32; + PCLEN:=32; + // definitions for the architecture wrapper + // XL ZYXWVUTSRQPONMLKJIHGFEDCBA + MISA_VAL:=0b01000000000000000000000100000000; + } +} + +Core TGF02 provides RV32I, RV32M, RV32IC { + constants { + XLEN:=32; + PCLEN:=32; + MUL_LEN:=64; + // definitions for the architecture wrapper + // XL ZYXWVUTSRQPONMLKJIHGFEDCBA + MISA_VAL:=0b01000000000000000001000100000100; + } +} \ No newline at end of file diff --git a/incl/iss/arch/tgf01.h b/incl/iss/arch/tgf01.h new file mode 100644 index 0000000..9d4fcb4 --- /dev/null +++ b/incl/iss/arch/tgf01.h @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (C) 2017, 2018 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + + +#ifndef _TGF01_H_ +#define _TGF01_H_ + +#include +#include +#include +#include + +namespace iss { +namespace arch { + +struct tgf01; + +template <> struct traits { + + constexpr static char const* const core_type = "TGF01"; + + static constexpr std::array reg_names{ + {"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc"}}; + + static constexpr std::array reg_aliases{ + {"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}}; + + enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000000000000000100000000}; + + constexpr static unsigned FP_REGS_SIZE = 0; + + enum reg_e { + X0, + X1, + X2, + X3, + X4, + X5, + X6, + X7, + X8, + X9, + X10, + X11, + X12, + X13, + X14, + X15, + X16, + X17, + X18, + X19, + X20, + X21, + X22, + X23, + X24, + X25, + X26, + X27, + X28, + X29, + X30, + X31, + PC, + NUM_REGS, + NEXT_PC=NUM_REGS, + TRAP_STATE, + PENDING_TRAP, + MACHINE_STATE, + LAST_BRANCH, + ICOUNT, + ZERO = X0, + RA = X1, + SP = X2, + GP = X3, + TP = X4, + T0 = X5, + T1 = X6, + T2 = X7, + S0 = X8, + S1 = X9, + A0 = X10, + A1 = X11, + A2 = X12, + A3 = X13, + A4 = X14, + A5 = X15, + A6 = X16, + A7 = X17, + S2 = X18, + S3 = X19, + S4 = X20, + S5 = X21, + S6 = X22, + S7 = X23, + S8 = X24, + S9 = X25, + S10 = X26, + S11 = X27, + T3 = X28, + T4 = X29, + T5 = X30, + T6 = X31 + }; + + using reg_t = uint32_t; + + using addr_t = uint32_t; + + using code_word_t = uint32_t; //TODO: check removal + + using virt_addr_t = iss::typed_addr_t; + + using phys_addr_t = iss::typed_addr_t; + + static constexpr std::array reg_bit_widths{ + {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64}}; + + static constexpr std::array reg_byte_offsets{ + {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,160}}; + + static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); + + enum sreg_flag_e { FLAGS }; + + enum mem_type_e { MEM, CSR, FENCE, RES }; +}; + +struct tgf01: public arch_if { + + using virt_addr_t = typename traits::virt_addr_t; + using phys_addr_t = typename traits::phys_addr_t; + using reg_t = typename traits::reg_t; + using addr_t = typename traits::addr_t; + + tgf01(); + ~tgf01(); + + void reset(uint64_t address=0) override; + + uint8_t* get_regs_base_ptr() override; + /// deprecated + void get_reg(short idx, std::vector& value) override {} + void set_reg(short idx, const std::vector& value) override {} + /// deprecated + bool get_flag(int flag) override {return false;} + void set_flag(int, bool value) override {}; + /// deprecated + void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {}; + + inline uint64_t get_icount() { return reg.icount; } + + inline bool should_stop() { return interrupt_sim; } + + inline uint64_t stop_code() { return interrupt_sim; } + + inline phys_addr_t v2p(const iss::addr_t& addr){ + if (addr.space != traits::MEM || addr.type == iss::address_type::PHYSICAL || + addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { + return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); + } else + return virt2phys(addr); + } + + virtual phys_addr_t virt2phys(const iss::addr_t& addr); + + virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + + inline uint32_t get_last_branch() { return reg.last_branch; } + +protected: + struct TGF01_regs { + uint32_t X0 = 0; + uint32_t X1 = 0; + uint32_t X2 = 0; + uint32_t X3 = 0; + uint32_t X4 = 0; + uint32_t X5 = 0; + uint32_t X6 = 0; + uint32_t X7 = 0; + uint32_t X8 = 0; + uint32_t X9 = 0; + uint32_t X10 = 0; + uint32_t X11 = 0; + uint32_t X12 = 0; + uint32_t X13 = 0; + uint32_t X14 = 0; + uint32_t X15 = 0; + uint32_t X16 = 0; + uint32_t X17 = 0; + uint32_t X18 = 0; + uint32_t X19 = 0; + uint32_t X20 = 0; + uint32_t X21 = 0; + uint32_t X22 = 0; + uint32_t X23 = 0; + uint32_t X24 = 0; + uint32_t X25 = 0; + uint32_t X26 = 0; + uint32_t X27 = 0; + uint32_t X28 = 0; + uint32_t X29 = 0; + uint32_t X30 = 0; + uint32_t X31 = 0; + uint32_t PC = 0; + uint32_t NEXT_PC = 0; + uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0; + uint64_t icount = 0; + } reg; + + std::array addr_mode; + + uint64_t interrupt_sim=0; + + uint32_t get_fcsr(){return 0;} + void set_fcsr(uint32_t val){} + +}; + +} +} +#endif /* _TGF01_H_ */ diff --git a/incl/iss/arch/tgf02.h b/incl/iss/arch/tgf02.h new file mode 100644 index 0000000..804971b --- /dev/null +++ b/incl/iss/arch/tgf02.h @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (C) 2017, 2018 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + + +#ifndef _TGF02_H_ +#define _TGF02_H_ + +#include +#include +#include +#include + +namespace iss { +namespace arch { + +struct tgf02; + +template <> struct traits { + + constexpr static char const* const core_type = "TGF02"; + + static constexpr std::array reg_names{ + {"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", "pc"}}; + + static constexpr std::array reg_aliases{ + {"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "pc"}}; + + enum constants {XLEN=32, PCLEN=32, MUL_LEN=64, MISA_VAL=0b1000000000000000001000100000100}; + + constexpr static unsigned FP_REGS_SIZE = 0; + + enum reg_e { + X0, + X1, + X2, + X3, + X4, + X5, + X6, + X7, + X8, + X9, + X10, + X11, + X12, + X13, + X14, + X15, + X16, + X17, + X18, + X19, + X20, + X21, + X22, + X23, + X24, + X25, + X26, + X27, + X28, + X29, + X30, + X31, + PC, + NUM_REGS, + NEXT_PC=NUM_REGS, + TRAP_STATE, + PENDING_TRAP, + MACHINE_STATE, + LAST_BRANCH, + ICOUNT, + ZERO = X0, + RA = X1, + SP = X2, + GP = X3, + TP = X4, + T0 = X5, + T1 = X6, + T2 = X7, + S0 = X8, + S1 = X9, + A0 = X10, + A1 = X11, + A2 = X12, + A3 = X13, + A4 = X14, + A5 = X15, + A6 = X16, + A7 = X17, + S2 = X18, + S3 = X19, + S4 = X20, + S5 = X21, + S6 = X22, + S7 = X23, + S8 = X24, + S9 = X25, + S10 = X26, + S11 = X27, + T3 = X28, + T4 = X29, + T5 = X30, + T6 = X31 + }; + + using reg_t = uint32_t; + + using addr_t = uint32_t; + + using code_word_t = uint32_t; //TODO: check removal + + using virt_addr_t = iss::typed_addr_t; + + using phys_addr_t = iss::typed_addr_t; + + static constexpr std::array reg_bit_widths{ + {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64}}; + + static constexpr std::array reg_byte_offsets{ + {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,160}}; + + static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); + + enum sreg_flag_e { FLAGS }; + + enum mem_type_e { MEM, CSR, FENCE, RES }; +}; + +struct tgf02: public arch_if { + + using virt_addr_t = typename traits::virt_addr_t; + using phys_addr_t = typename traits::phys_addr_t; + using reg_t = typename traits::reg_t; + using addr_t = typename traits::addr_t; + + tgf02(); + ~tgf02(); + + void reset(uint64_t address=0) override; + + uint8_t* get_regs_base_ptr() override; + /// deprecated + void get_reg(short idx, std::vector& value) override {} + void set_reg(short idx, const std::vector& value) override {} + /// deprecated + bool get_flag(int flag) override {return false;} + void set_flag(int, bool value) override {}; + /// deprecated + void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {}; + + inline uint64_t get_icount() { return reg.icount; } + + inline bool should_stop() { return interrupt_sim; } + + inline uint64_t stop_code() { return interrupt_sim; } + + inline phys_addr_t v2p(const iss::addr_t& addr){ + if (addr.space != traits::MEM || addr.type == iss::address_type::PHYSICAL || + addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { + return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); + } else + return virt2phys(addr); + } + + virtual phys_addr_t virt2phys(const iss::addr_t& addr); + + virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } + + inline uint32_t get_last_branch() { return reg.last_branch; } + +protected: + struct TGF02_regs { + uint32_t X0 = 0; + uint32_t X1 = 0; + uint32_t X2 = 0; + uint32_t X3 = 0; + uint32_t X4 = 0; + uint32_t X5 = 0; + uint32_t X6 = 0; + uint32_t X7 = 0; + uint32_t X8 = 0; + uint32_t X9 = 0; + uint32_t X10 = 0; + uint32_t X11 = 0; + uint32_t X12 = 0; + uint32_t X13 = 0; + uint32_t X14 = 0; + uint32_t X15 = 0; + uint32_t X16 = 0; + uint32_t X17 = 0; + uint32_t X18 = 0; + uint32_t X19 = 0; + uint32_t X20 = 0; + uint32_t X21 = 0; + uint32_t X22 = 0; + uint32_t X23 = 0; + uint32_t X24 = 0; + uint32_t X25 = 0; + uint32_t X26 = 0; + uint32_t X27 = 0; + uint32_t X28 = 0; + uint32_t X29 = 0; + uint32_t X30 = 0; + uint32_t X31 = 0; + uint32_t PC = 0; + uint32_t NEXT_PC = 0; + uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0; + uint64_t icount = 0; + } reg; + + std::array addr_mode; + + uint64_t interrupt_sim=0; + + uint32_t get_fcsr(){return 0;} + void set_fcsr(uint32_t val){} + +}; + +} +} +#endif /* _TGF02_H_ */ diff --git a/src/iss/tgf01.cpp b/src/iss/tgf01.cpp new file mode 100644 index 0000000..49200c3 --- /dev/null +++ b/src/iss/tgf01.cpp @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (C) 2017, 2018 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#include "util/ities.h" +#include +#include +#include +#include +#include + +using namespace iss::arch; + +constexpr std::array iss::arch::traits::reg_names; +constexpr std::array iss::arch::traits::reg_aliases; +constexpr std::array iss::arch::traits::reg_bit_widths; +constexpr std::array iss::arch::traits::reg_byte_offsets; + +tgf01::tgf01() { + reg.icount = 0; +} + +tgf01::~tgf01() = default; + +void tgf01::reset(uint64_t address) { + for(size_t i=0; i::NUM_REGS; ++i) set_reg(i, std::vector(sizeof(traits::reg_t),0)); + reg.PC=address; + reg.NEXT_PC=reg.PC; + reg.trap_state=0; + reg.machine_state=0x3; + reg.icount=0; +} + +uint8_t *tgf01::get_regs_base_ptr() { + return reinterpret_cast(®); +} + +tgf01::phys_addr_t tgf01::virt2phys(const iss::addr_t &pc) { + return phys_addr_t(pc); // change logical address to physical address +} + diff --git a/src/iss/tgf02.cpp b/src/iss/tgf02.cpp new file mode 100644 index 0000000..7a238c1 --- /dev/null +++ b/src/iss/tgf02.cpp @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (C) 2017, 2018 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#include "util/ities.h" +#include +#include +#include +#include +#include + +using namespace iss::arch; + +constexpr std::array iss::arch::traits::reg_names; +constexpr std::array iss::arch::traits::reg_aliases; +constexpr std::array iss::arch::traits::reg_bit_widths; +constexpr std::array iss::arch::traits::reg_byte_offsets; + +tgf02::tgf02() { + reg.icount = 0; +} + +tgf02::~tgf02() = default; + +void tgf02::reset(uint64_t address) { + for(size_t i=0; i::NUM_REGS; ++i) set_reg(i, std::vector(sizeof(traits::reg_t),0)); + reg.PC=address; + reg.NEXT_PC=reg.PC; + reg.trap_state=0; + reg.machine_state=0x3; + reg.icount=0; +} + +uint8_t *tgf02::get_regs_base_ptr() { + return reinterpret_cast(®); +} + +tgf02::phys_addr_t tgf02::virt2phys(const iss::addr_t &pc) { + return phys_addr_t(pc); // change logical address to physical address +} + diff --git a/src/vm/tcc/vm_tgf01.cpp b/src/vm/tcc/vm_tgf01.cpp new file mode 100644 index 0000000..02996cc --- /dev/null +++ b/src/vm/tcc/vm_tgf01.cpp @@ -0,0 +1,2086 @@ +/******************************************************************************* + * Copyright (C) 2020 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include + +#include +#include + +namespace iss { +namespace tcc { +namespace tgf01 { +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::tcc::vm_base { +public: + using super = typename iss::tcc::vm_base; + using virt_addr_t = typename super::virt_addr_t; + using phys_addr_t = typename super::phys_addr_t; + using code_word_t = typename super::code_word_t; + using addr_t = typename super::addr_t; + using tu_builder = typename super::tu_builder; + + 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_ret_t = std::tuple; + using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); + + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + void setup_module(std::string m) override { + super::setup_module(m); + } + + compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, tu_builder&) override; + + void gen_trap_behavior(tu_builder& tu) override; + + void gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause); + + void gen_leave_trap(tu_builder& tu, unsigned lvl); + + void gen_wait(tu_builder& tu, unsigned type); + + inline void gen_trap_check(tu_builder& tu) { + tu("if(*trap_state!=0) goto trap_entry;"); + } + + inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) { + switch(reg_num){ + case traits::NEXT_PC: + tu("*next_pc = {:#x};", pc.val); + break; + case traits::PC: + tu("*pc = {:#x};", pc.val); + break; + default: + if(!tu.defined_regs[reg_num]){ + tu("reg_t* reg{:02d} = (reg_t*){:#x};", reg_num, reinterpret_cast(get_reg_ptr(reg_num))); + tu.defined_regs[reg_num]=true; + } + tu("*reg{:02d} = {:#x};", reg_num, pc.val); + } + } + + // some compile time constants + // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; + enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; + enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; + enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; + + std::array lut; + + std::array lut_00, lut_01, lut_10; + std::array lut_11; + + std::array qlut; + + std::array lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; + + void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], + compile_func f) { + if (pos < 0) { + lut[idx] = f; + } else { + auto bitmask = 1UL << pos; + if ((mask & bitmask) == 0) { + expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); + } else { + if ((valid & bitmask) == 0) { + expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); + expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); + } else { + auto new_val = idx << 1; + if ((value & bitmask) != 0) new_val++; + expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); + } + } + } + } + + inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } + + uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { + if (pos >= 0) { + auto bitmask = 1UL << pos; + if ((mask & bitmask) == 0) { + lut_val = extract_fields(pos - 1, val, mask, lut_val); + } else { + auto new_val = lut_val << 1; + if ((val & bitmask) != 0) new_val++; + lut_val = extract_fields(pos - 1, val, mask, new_val); + } + } + return lut_val; + } + +private: + /**************************************************************************** + * start opcode definitions + ****************************************************************************/ + struct InstructionDesriptor { + size_t length; + uint32_t value; + uint32_t mask; + compile_func op; + }; + + const std::array instr_descr = {{ + /* entries are: size, valid value, valid mask, function ptr */ + /* instruction LUI, encoding '.........................0110111' */ + {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, + /* instruction AUIPC, encoding '.........................0010111' */ + {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc}, + /* instruction JAL, encoding '.........................1101111' */ + {32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal}, + /* instruction JALR, encoding '.................000.....1100111' */ + {32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr}, + /* instruction BEQ, encoding '.................000.....1100011' */ + {32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq}, + /* instruction BNE, encoding '.................001.....1100011' */ + {32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne}, + /* instruction BLT, encoding '.................100.....1100011' */ + {32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt}, + /* instruction BGE, encoding '.................101.....1100011' */ + {32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge}, + /* instruction BLTU, encoding '.................110.....1100011' */ + {32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu}, + /* instruction BGEU, encoding '.................111.....1100011' */ + {32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu}, + /* instruction LB, encoding '.................000.....0000011' */ + {32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb}, + /* instruction LH, encoding '.................001.....0000011' */ + {32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh}, + /* instruction LW, encoding '.................010.....0000011' */ + {32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw}, + /* instruction LBU, encoding '.................100.....0000011' */ + {32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu}, + /* instruction LHU, encoding '.................101.....0000011' */ + {32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu}, + /* instruction SB, encoding '.................000.....0100011' */ + {32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb}, + /* instruction SH, encoding '.................001.....0100011' */ + {32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh}, + /* instruction SW, encoding '.................010.....0100011' */ + {32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw}, + /* instruction ADDI, encoding '.................000.....0010011' */ + {32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi}, + /* instruction SLTI, encoding '.................010.....0010011' */ + {32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti}, + /* instruction SLTIU, encoding '.................011.....0010011' */ + {32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu}, + /* instruction XORI, encoding '.................100.....0010011' */ + {32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori}, + /* instruction ORI, encoding '.................110.....0010011' */ + {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, + /* instruction ANDI, encoding '.................111.....0010011' */ + {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, + /* instruction SLLI, encoding '0000000..........001.....0010011' */ + {32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli}, + /* instruction SRLI, encoding '0000000..........101.....0010011' */ + {32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli}, + /* instruction SRAI, encoding '0100000..........101.....0010011' */ + {32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai}, + /* instruction ADD, encoding '0000000..........000.....0110011' */ + {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, + /* instruction SUB, encoding '0100000..........000.....0110011' */ + {32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub}, + /* instruction SLL, encoding '0000000..........001.....0110011' */ + {32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll}, + /* instruction SLT, encoding '0000000..........010.....0110011' */ + {32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt}, + /* instruction SLTU, encoding '0000000..........011.....0110011' */ + {32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu}, + /* instruction XOR, encoding '0000000..........100.....0110011' */ + {32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor}, + /* instruction SRL, encoding '0000000..........101.....0110011' */ + {32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl}, + /* instruction SRA, encoding '0100000..........101.....0110011' */ + {32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra}, + /* instruction OR, encoding '0000000..........110.....0110011' */ + {32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or}, + /* instruction AND, encoding '0000000..........111.....0110011' */ + {32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and}, + /* instruction FENCE, encoding '0000.............000.....0001111' */ + {32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence}, + /* instruction FENCE_I, encoding '.................001.....0001111' */ + {32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i}, + /* instruction ECALL, encoding '00000000000000000000000001110011' */ + {32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall}, + /* instruction EBREAK, encoding '00000000000100000000000001110011' */ + {32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak}, + /* instruction URET, encoding '00000000001000000000000001110011' */ + {32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret}, + /* instruction SRET, encoding '00010000001000000000000001110011' */ + {32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret}, + /* instruction MRET, encoding '00110000001000000000000001110011' */ + {32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret}, + /* instruction WFI, encoding '00010000010100000000000001110011' */ + {32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi}, + /* instruction SFENCE.VMA, encoding '0001001..........000000001110011' */ + {32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma}, + /* instruction CSRRW, encoding '.................001.....1110011' */ + {32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw}, + /* instruction CSRRS, encoding '.................010.....1110011' */ + {32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs}, + /* instruction CSRRC, encoding '.................011.....1110011' */ + {32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc}, + /* instruction CSRRWI, encoding '.................101.....1110011' */ + {32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi}, + /* instruction CSRRSI, encoding '.................110.....1110011' */ + {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, + /* instruction CSRRCI, encoding '.................111.....1110011' */ + {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, + }}; + + /* instruction definitions */ + /* instruction 0: LUI */ + compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LUI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 0); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.constant(imm, 32U), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 0); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 1: AUIPC */ + compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("AUIPC_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 1); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 1); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 2: JAL */ + compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("JAL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 2); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,8>(instr) << 12) | (bit_sub<20,1>(instr) << 11) | (bit_sub<21,10>(instr) << 1) | (bit_sub<31,1>(instr) << 20)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + cur_pc_val, + tu.constant(4, 32U)), rd + traits::X0); + } + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 2); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 3: JALR */ + compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("JALR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 3); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm:#0x}", fmt::arg("mnemonic", "jalr"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto new_pc_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + auto align_val = tu.assignment(tu.l_and( + new_pc_val, + tu.constant(0x2, 32U)), 32); + tu( " if({}) {{", tu.icmp( + ICmpInst::ICMP_NE, + align_val, + tu.constant(0, 32U))); + this->gen_raise_trap(tu, 0, 0); + tu(" }} else {{"); + if(rd != 0){ + tu.store(tu.add( + cur_pc_val, + tu.constant(4, 32U)), rd + traits::X0); + } + auto PC_val_v = tu.assignment("PC_val", tu.l_and( + new_pc_val, + tu.l_not(tu.constant(0x1, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 3); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 4: BEQ */ + compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BEQ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 4); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 4); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 5: BNE */ + compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BNE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 5); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 5); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 6: BLT */ + compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BLT_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 6); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 6); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 7: BGE */ + compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BGE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 7); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SGE, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 7); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 8: BLTU */ + compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BLTU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 8); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 8); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 9: BGEU */ + compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BGEU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 9); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_UGE, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 9); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 10: LB */ + compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 10); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 8), + 32, + false), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 10); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 11: LH */ + compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 11); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 16), + 32, + false), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 11); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 12: LW */ + compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 12); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 12); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 13: LBU */ + compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LBU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 13); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 8), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 13); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 14: LHU */ + compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LHU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 14); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 16), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 14); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 15: SB */ + compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 15); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 8)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 15); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 16: SH */ + compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 16); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 16)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 16); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 17: SW */ + compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 17); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 17); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 18: ADDI */ + compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ADDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 18); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "addi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 18); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 19: SLTI */ + compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 19); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "slti"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 19); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 20: SLTIU */ + compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTIU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 20); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "sltiu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + int32_t full_imm_val = imm; + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.load(rs1 + traits::X0, 0), + tu.constant(full_imm_val, 32U)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 20); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 21: XORI */ + compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("XORI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 21); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "xori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_xor( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 21); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 22: ORI */ + compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ORI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 22); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "ori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_or( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 22); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 23: ANDI */ + compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ANDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 23); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "andi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_and( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 23); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 24: SLLI */ + compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 24); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + tu.store(tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 24); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 25: SRLI */ + compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 25); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + tu.store(tu.lshr( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 25); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 26: SRAI */ + compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRAI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 26); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + tu.store(tu.ashr( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 26); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 27: ADD */ + compile_ret_t __add(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ADD_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 27); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 27); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 28: SUB */ + compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SUB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 28); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.sub( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 28); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 29: SLL */ + compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 29); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 29); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 30: SLT */ + compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLT_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 30); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 30); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 31: SLTU */ + compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 31); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, + true), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, + true)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 31); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 32: XOR */ + compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("XOR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 32); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_xor( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 32); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 33: SRL */ + compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 33); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.lshr( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 33); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 34: SRA */ + compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRA_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 34); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.ashr( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 34); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 35: OR */ + compile_ret_t __or(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("OR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 35); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_or( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 35); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 36: AND */ + compile_ret_t __and(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("AND_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 36); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_and( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 36); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 37: FENCE */ + compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("FENCE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 37); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t succ = ((bit_sub<20,4>(instr))); + uint8_t pred = ((bit_sub<24,4>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "fence"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + tu.write_mem( + traits::FENCE, + tu.constant(0, 64U), + tu.trunc(tu.l_or( + tu.shl( + tu.constant(pred, 32U), + tu.constant(4, 32U)), + tu.constant(succ, 32U)), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 37); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 38: FENCE_I */ + compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("FENCE_I_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 38); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t imm = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "fence_i"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + tu.write_mem( + traits::FENCE, + tu.constant(1, 64U), + tu.trunc(tu.constant(imm, 32U), 32)); + tu.close_scope(); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 38); + gen_trap_check(tu); + return std::make_tuple(FLUSH); + } + + /* instruction 39: ECALL */ + compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ECALL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 39); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "ecall"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 11); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 39); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 40: EBREAK */ + compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("EBREAK_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 40); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "ebreak"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 40); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 41: URET */ + compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("URET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 41); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "uret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 0); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 41); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 42: SRET */ + compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 42); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "sret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 1); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 42); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 43: MRET */ + compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MRET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 43); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "mret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 43); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 44: WFI */ + compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("WFI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 44); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "wfi"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_wait(tu, 1); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 44); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 45: SFENCE.VMA */ + compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SFENCE_VMA_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 45); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "sfence.vma"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + tu.write_mem( + traits::FENCE, + tu.constant(2, 64U), + tu.trunc(tu.constant(rs1, 32U), 32)); + tu.write_mem( + traits::FENCE, + tu.constant(3, 64U), + tu.trunc(tu.constant(rs2, 32U), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 45); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 46: CSRRW */ + compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 46); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto rs_val_val = tu.assignment(tu.load(rs1 + traits::X0, 0), 32); + if(rd != 0){ + auto csr_val_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(rs_val_val, 32)); + tu.store(csr_val_val, rd + traits::X0); + } else { + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(rs_val_val, 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 46); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 47: CSRRS */ + compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRS_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 47); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto xrd_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + auto xrs1_val = tu.assignment(tu.load(rs1 + traits::X0, 0), 32); + if(rd != 0){ + tu.store(xrd_val, rd + traits::X0); + } + if(rs1 != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_or( + xrd_val, + xrs1_val), 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 47); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 48: CSRRC */ + compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRC_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 48); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto xrd_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + auto xrs1_val = tu.assignment(tu.load(rs1 + traits::X0, 0), 32); + if(rd != 0){ + tu.store(xrd_val, rd + traits::X0); + } + if(rs1 != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_and( + xrd_val, + tu.l_not(xrs1_val)), 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 48); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 49: CSRRWI */ + compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRWI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 49); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), rd + traits::X0); + } + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.ext( + tu.constant(zimm, 32U), + 32, + true), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 49); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 50: CSRRSI */ + compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRSI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 50); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto res_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + if(zimm != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_or( + res_val, + tu.ext( + tu.constant(zimm, 32U), + 32, + true)), 32)); + } + if(rd != 0){ + tu.store(res_val, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 50); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 51: CSRRCI */ + compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRCI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 51); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto res_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + if(rd != 0){ + tu.store(res_val, rd + traits::X0); + } + if(zimm != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_and( + res_val, + tu.l_not(tu.ext( + tu.constant(zimm, 32U), + 32, + true))), 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 51); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) { + vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size()); + pc = pc + ((instr & 3) == 3 ? 4 : 2); + gen_raise_trap(tu, 0, 2); // illegal instruction trap + vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size()); + vm_impl::gen_trap_check(tu); + return BRANCH; + } +}; + +template void debug_fn(CODE_WORD insn) { + volatile CODE_WORD x = insn; + insn = 2 * x; +} + +template vm_impl::vm_impl() { this(new ARCH()); } + +template +vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) +: vm_base(core, core_id, cluster_id) { + qlut[0] = lut_00.data(); + qlut[1] = lut_01.data(); + qlut[2] = lut_10.data(); + qlut[3] = lut_11.data(); + for (auto instr : instr_descr) { + auto quantrant = instr.value & 0x3; + expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); + } +} + +template +std::tuple +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { + // we fetch at max 4 byte, alignment is 2 + enum {TRAP_ID=1<<16}; + code_word_t insn = 0; + const typename traits::addr_t upper_bits = ~traits::PGMASK; + phys_addr_t paddr(pc); + auto *const data = (uint8_t *)&insn; + paddr = this->core.v2p(pc); + if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary + auto res = this->core.read(paddr, 2, data); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if ((insn & 0x3) == 0x3) { // this is a 32bit instruction + res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); + } + } else { + auto res = this->core.read(paddr, 4, data); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + } + if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' + // curr pc on stack + ++inst_cnt; + auto lut_val = extract_fields(insn); + auto f = qlut[insn & 0x3][lut_val]; + if (f == nullptr) { + f = &this_class::illegal_intruction; + } + return (this->*f)(pc, insn, tu); +} + +template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { + tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); +} + +template void vm_impl::gen_leave_trap(tu_builder& tu, unsigned lvl) { + tu("leave_trap(core_ptr, {});", lvl); + tu.store(tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN),traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); +} + +template void vm_impl::gen_wait(tu_builder& tu, unsigned type) { +} + +template void vm_impl::gen_trap_behavior(tu_builder& tu) { + tu("trap_entry:"); + tu("enter_trap(core_ptr, *trap_state, *pc);"); + tu.store(tu.constant(std::numeric_limits::max(),32),traits::LAST_BRANCH); + tu("return *next_pc;"); +} + +} // namespace mnrv32 + +template <> +std::unique_ptr create(arch::tgf01 *core, unsigned short port, bool dump) { + auto ret = new tgf01::vm_impl(*core, dump); + if (port != 0) debugger::server::run_server(ret, port); + return std::unique_ptr(ret); +} +} +} // namespace iss diff --git a/src/vm/tcc/vm_tgf02.cpp b/src/vm/tcc/vm_tgf02.cpp new file mode 100644 index 0000000..7813c5c --- /dev/null +++ b/src/vm/tcc/vm_tgf02.cpp @@ -0,0 +1,3278 @@ +/******************************************************************************* + * Copyright (C) 2020 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include + +#include +#include + +namespace iss { +namespace tcc { +namespace tgf02 { +using namespace iss::arch; +using namespace iss::debugger; + +template class vm_impl : public iss::tcc::vm_base { +public: + using super = typename iss::tcc::vm_base; + using virt_addr_t = typename super::virt_addr_t; + using phys_addr_t = typename super::phys_addr_t; + using code_word_t = typename super::code_word_t; + using addr_t = typename super::addr_t; + using tu_builder = typename super::tu_builder; + + 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_ret_t = std::tuple; + using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); + + inline const char *name(size_t index){return traits::reg_aliases.at(index);} + + void setup_module(std::string m) override { + super::setup_module(m); + } + + compile_ret_t gen_single_inst_behavior(virt_addr_t &, unsigned int &, tu_builder&) override; + + void gen_trap_behavior(tu_builder& tu) override; + + void gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause); + + void gen_leave_trap(tu_builder& tu, unsigned lvl); + + void gen_wait(tu_builder& tu, unsigned type); + + inline void gen_trap_check(tu_builder& tu) { + tu("if(*trap_state!=0) goto trap_entry;"); + } + + inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) { + switch(reg_num){ + case traits::NEXT_PC: + tu("*next_pc = {:#x};", pc.val); + break; + case traits::PC: + tu("*pc = {:#x};", pc.val); + break; + default: + if(!tu.defined_regs[reg_num]){ + tu("reg_t* reg{:02d} = (reg_t*){:#x};", reg_num, reinterpret_cast(get_reg_ptr(reg_num))); + tu.defined_regs[reg_num]=true; + } + tu("*reg{:02d} = {:#x};", reg_num, pc.val); + } + } + + // some compile time constants + // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; + enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; + enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; + enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; + + std::array lut; + + std::array lut_00, lut_01, lut_10; + std::array lut_11; + + std::array qlut; + + std::array lutmasks = {{EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32}}; + + void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], + compile_func f) { + if (pos < 0) { + lut[idx] = f; + } else { + auto bitmask = 1UL << pos; + if ((mask & bitmask) == 0) { + expand_bit_mask(pos - 1, mask, value, valid, idx, lut, f); + } else { + if ((valid & bitmask) == 0) { + expand_bit_mask(pos - 1, mask, value, valid, (idx << 1), lut, f); + expand_bit_mask(pos - 1, mask, value, valid, (idx << 1) + 1, lut, f); + } else { + auto new_val = idx << 1; + if ((value & bitmask) != 0) new_val++; + expand_bit_mask(pos - 1, mask, value, valid, new_val, lut, f); + } + } + } + } + + inline uint32_t extract_fields(uint32_t val) { return extract_fields(29, val >> 2, lutmasks[val & 0x3], 0); } + + uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val) { + if (pos >= 0) { + auto bitmask = 1UL << pos; + if ((mask & bitmask) == 0) { + lut_val = extract_fields(pos - 1, val, mask, lut_val); + } else { + auto new_val = lut_val << 1; + if ((val & bitmask) != 0) new_val++; + lut_val = extract_fields(pos - 1, val, mask, new_val); + } + } + return lut_val; + } + +private: + /**************************************************************************** + * start opcode definitions + ****************************************************************************/ + struct InstructionDesriptor { + size_t length; + uint32_t value; + uint32_t mask; + compile_func op; + }; + + const std::array instr_descr = {{ + /* entries are: size, valid value, valid mask, function ptr */ + /* instruction LUI, encoding '.........................0110111' */ + {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, &this_class::__lui}, + /* instruction AUIPC, encoding '.........................0010111' */ + {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, &this_class::__auipc}, + /* instruction JAL, encoding '.........................1101111' */ + {32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, &this_class::__jal}, + /* instruction JALR, encoding '.................000.....1100111' */ + {32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, &this_class::__jalr}, + /* instruction BEQ, encoding '.................000.....1100011' */ + {32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, &this_class::__beq}, + /* instruction BNE, encoding '.................001.....1100011' */ + {32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, &this_class::__bne}, + /* instruction BLT, encoding '.................100.....1100011' */ + {32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, &this_class::__blt}, + /* instruction BGE, encoding '.................101.....1100011' */ + {32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, &this_class::__bge}, + /* instruction BLTU, encoding '.................110.....1100011' */ + {32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, &this_class::__bltu}, + /* instruction BGEU, encoding '.................111.....1100011' */ + {32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, &this_class::__bgeu}, + /* instruction LB, encoding '.................000.....0000011' */ + {32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, &this_class::__lb}, + /* instruction LH, encoding '.................001.....0000011' */ + {32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, &this_class::__lh}, + /* instruction LW, encoding '.................010.....0000011' */ + {32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, &this_class::__lw}, + /* instruction LBU, encoding '.................100.....0000011' */ + {32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, &this_class::__lbu}, + /* instruction LHU, encoding '.................101.....0000011' */ + {32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, &this_class::__lhu}, + /* instruction SB, encoding '.................000.....0100011' */ + {32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, &this_class::__sb}, + /* instruction SH, encoding '.................001.....0100011' */ + {32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, &this_class::__sh}, + /* instruction SW, encoding '.................010.....0100011' */ + {32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, &this_class::__sw}, + /* instruction ADDI, encoding '.................000.....0010011' */ + {32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, &this_class::__addi}, + /* instruction SLTI, encoding '.................010.....0010011' */ + {32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, &this_class::__slti}, + /* instruction SLTIU, encoding '.................011.....0010011' */ + {32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, &this_class::__sltiu}, + /* instruction XORI, encoding '.................100.....0010011' */ + {32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, &this_class::__xori}, + /* instruction ORI, encoding '.................110.....0010011' */ + {32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, &this_class::__ori}, + /* instruction ANDI, encoding '.................111.....0010011' */ + {32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, &this_class::__andi}, + /* instruction SLLI, encoding '0000000..........001.....0010011' */ + {32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, &this_class::__slli}, + /* instruction SRLI, encoding '0000000..........101.....0010011' */ + {32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srli}, + /* instruction SRAI, encoding '0100000..........101.....0010011' */ + {32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, &this_class::__srai}, + /* instruction ADD, encoding '0000000..........000.....0110011' */ + {32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__add}, + /* instruction SUB, encoding '0100000..........000.....0110011' */ + {32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__sub}, + /* instruction SLL, encoding '0000000..........001.....0110011' */ + {32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__sll}, + /* instruction SLT, encoding '0000000..........010.....0110011' */ + {32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__slt}, + /* instruction SLTU, encoding '0000000..........011.....0110011' */ + {32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__sltu}, + /* instruction XOR, encoding '0000000..........100.....0110011' */ + {32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__xor}, + /* instruction SRL, encoding '0000000..........101.....0110011' */ + {32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__srl}, + /* instruction SRA, encoding '0100000..........101.....0110011' */ + {32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__sra}, + /* instruction OR, encoding '0000000..........110.....0110011' */ + {32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__or}, + /* instruction AND, encoding '0000000..........111.....0110011' */ + {32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__and}, + /* instruction FENCE, encoding '0000.............000.....0001111' */ + {32, 0b00000000000000000000000000001111, 0b11110000000000000111000001111111, &this_class::__fence}, + /* instruction FENCE_I, encoding '.................001.....0001111' */ + {32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, &this_class::__fence_i}, + /* instruction ECALL, encoding '00000000000000000000000001110011' */ + {32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, &this_class::__ecall}, + /* instruction EBREAK, encoding '00000000000100000000000001110011' */ + {32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, &this_class::__ebreak}, + /* instruction URET, encoding '00000000001000000000000001110011' */ + {32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__uret}, + /* instruction SRET, encoding '00010000001000000000000001110011' */ + {32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__sret}, + /* instruction MRET, encoding '00110000001000000000000001110011' */ + {32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, &this_class::__mret}, + /* instruction WFI, encoding '00010000010100000000000001110011' */ + {32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, &this_class::__wfi}, + /* instruction SFENCE.VMA, encoding '0001001..........000000001110011' */ + {32, 0b00010010000000000000000001110011, 0b11111110000000000111111111111111, &this_class::__sfence_vma}, + /* instruction CSRRW, encoding '.................001.....1110011' */ + {32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, &this_class::__csrrw}, + /* instruction CSRRS, encoding '.................010.....1110011' */ + {32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, &this_class::__csrrs}, + /* instruction CSRRC, encoding '.................011.....1110011' */ + {32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, &this_class::__csrrc}, + /* instruction CSRRWI, encoding '.................101.....1110011' */ + {32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, &this_class::__csrrwi}, + /* instruction CSRRSI, encoding '.................110.....1110011' */ + {32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, &this_class::__csrrsi}, + /* instruction CSRRCI, encoding '.................111.....1110011' */ + {32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, &this_class::__csrrci}, + /* instruction MUL, encoding '0000001..........000.....0110011' */ + {32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, &this_class::__mul}, + /* instruction MULH, encoding '0000001..........001.....0110011' */ + {32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, &this_class::__mulh}, + /* instruction MULHSU, encoding '0000001..........010.....0110011' */ + {32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, &this_class::__mulhsu}, + /* instruction MULHU, encoding '0000001..........011.....0110011' */ + {32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, &this_class::__mulhu}, + /* instruction DIV, encoding '0000001..........100.....0110011' */ + {32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, &this_class::__div}, + /* instruction DIVU, encoding '0000001..........101.....0110011' */ + {32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, &this_class::__divu}, + /* instruction REM, encoding '0000001..........110.....0110011' */ + {32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, &this_class::__rem}, + /* instruction REMU, encoding '0000001..........111.....0110011' */ + {32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, &this_class::__remu}, + /* instruction C.ADDI4SPN, encoding '000...........00' */ + {16, 0b0000000000000000, 0b1110000000000011, &this_class::__c_addi4spn}, + /* instruction C.LW, encoding '010...........00' */ + {16, 0b0100000000000000, 0b1110000000000011, &this_class::__c_lw}, + /* instruction C.SW, encoding '110...........00' */ + {16, 0b1100000000000000, 0b1110000000000011, &this_class::__c_sw}, + /* instruction C.ADDI, encoding '000...........01' */ + {16, 0b0000000000000001, 0b1110000000000011, &this_class::__c_addi}, + /* instruction C.NOP, encoding '0000000000000001' */ + {16, 0b0000000000000001, 0b1111111111111111, &this_class::__c_nop}, + /* instruction C.JAL, encoding '001...........01' */ + {16, 0b0010000000000001, 0b1110000000000011, &this_class::__c_jal}, + /* instruction C.LI, encoding '010...........01' */ + {16, 0b0100000000000001, 0b1110000000000011, &this_class::__c_li}, + /* instruction C.LUI, encoding '011...........01' */ + {16, 0b0110000000000001, 0b1110000000000011, &this_class::__c_lui}, + /* instruction C.ADDI16SP, encoding '011.00010.....01' */ + {16, 0b0110000100000001, 0b1110111110000011, &this_class::__c_addi16sp}, + /* instruction C.SRLI, encoding '100000........01' */ + {16, 0b1000000000000001, 0b1111110000000011, &this_class::__c_srli}, + /* instruction C.SRAI, encoding '100001........01' */ + {16, 0b1000010000000001, 0b1111110000000011, &this_class::__c_srai}, + /* instruction C.ANDI, encoding '100.10........01' */ + {16, 0b1000100000000001, 0b1110110000000011, &this_class::__c_andi}, + /* instruction C.SUB, encoding '100011...00...01' */ + {16, 0b1000110000000001, 0b1111110001100011, &this_class::__c_sub}, + /* instruction C.XOR, encoding '100011...01...01' */ + {16, 0b1000110000100001, 0b1111110001100011, &this_class::__c_xor}, + /* instruction C.OR, encoding '100011...10...01' */ + {16, 0b1000110001000001, 0b1111110001100011, &this_class::__c_or}, + /* instruction C.AND, encoding '100011...11...01' */ + {16, 0b1000110001100001, 0b1111110001100011, &this_class::__c_and}, + /* instruction C.J, encoding '101...........01' */ + {16, 0b1010000000000001, 0b1110000000000011, &this_class::__c_j}, + /* instruction C.BEQZ, encoding '110...........01' */ + {16, 0b1100000000000001, 0b1110000000000011, &this_class::__c_beqz}, + /* instruction C.BNEZ, encoding '111...........01' */ + {16, 0b1110000000000001, 0b1110000000000011, &this_class::__c_bnez}, + /* instruction C.SLLI, encoding '0000..........10' */ + {16, 0b0000000000000010, 0b1111000000000011, &this_class::__c_slli}, + /* instruction C.LWSP, encoding '010...........10' */ + {16, 0b0100000000000010, 0b1110000000000011, &this_class::__c_lwsp}, + /* instruction C.MV, encoding '1000..........10' */ + {16, 0b1000000000000010, 0b1111000000000011, &this_class::__c_mv}, + /* instruction C.JR, encoding '1000.....0000010' */ + {16, 0b1000000000000010, 0b1111000001111111, &this_class::__c_jr}, + /* instruction C.ADD, encoding '1001..........10' */ + {16, 0b1001000000000010, 0b1111000000000011, &this_class::__c_add}, + /* instruction C.JALR, encoding '1001.....0000010' */ + {16, 0b1001000000000010, 0b1111000001111111, &this_class::__c_jalr}, + /* instruction C.EBREAK, encoding '1001000000000010' */ + {16, 0b1001000000000010, 0b1111111111111111, &this_class::__c_ebreak}, + /* instruction C.SWSP, encoding '110...........10' */ + {16, 0b1100000000000010, 0b1110000000000011, &this_class::__c_swsp}, + /* instruction DII, encoding '0000000000000000' */ + {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, + }}; + + /* instruction definitions */ + /* instruction 0: LUI */ + compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LUI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 0); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.constant(imm, 32U), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 0); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 1: AUIPC */ + compile_ret_t __auipc(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("AUIPC_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 1); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,20>(instr) << 12)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 1); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 2: JAL */ + compile_ret_t __jal(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("JAL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 2); + uint8_t rd = ((bit_sub<7,5>(instr))); + int32_t imm = signextend((bit_sub<12,8>(instr) << 12) | (bit_sub<20,1>(instr) << 11) | (bit_sub<21,10>(instr) << 1) | (bit_sub<31,1>(instr) << 20)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + cur_pc_val, + tu.constant(4, 32U)), rd + traits::X0); + } + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 2); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 3: JALR */ + compile_ret_t __jalr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("JALR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 3); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm:#0x}", fmt::arg("mnemonic", "jalr"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto new_pc_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.add( + cur_pc_val, + tu.constant(4, 32U)), rd + traits::X0); + } + auto PC_val_v = tu.assignment("PC_val", tu.l_and( + new_pc_val, + tu.l_not(tu.constant(0x1, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 3); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 4: BEQ */ + compile_ret_t __beq(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BEQ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 4); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 4); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 5: BNE */ + compile_ret_t __bne(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BNE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 5); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 5); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 6: BLT */ + compile_ret_t __blt(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BLT_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 6); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 6); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 7: BGE */ + compile_ret_t __bge(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BGE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 7); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_SGE, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 7); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 8: BLTU */ + compile_ret_t __bltu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BLTU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 8); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 8); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 9: BGEU */ + compile_ret_t __bgeu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("BGEU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 9); + int16_t imm = signextend((bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (bit_sub<31,1>(instr) << 12)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), + fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_UGE, + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(4, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 9); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 10: LB */ + compile_ret_t __lb(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 10); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 8), + 32, + false), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 10); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 11: LH */ + compile_ret_t __lh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 11); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 16), + 32, + false), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 11); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 12: LW */ + compile_ret_t __lw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 12); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 12); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 13: LBU */ + compile_ret_t __lbu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LBU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 13); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 8), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 13); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 14: LHU */ + compile_ret_t __lhu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("LHU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 14); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + if(rd != 0){ + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 16), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 14); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 15: SB */ + compile_ret_t __sb(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 15); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 8)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 15); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 16: SH */ + compile_ret_t __sh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 16); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 16)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 16); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 17: SW */ + compile_ret_t __sw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 17); + int16_t imm = signextend((bit_sub<7,5>(instr)) | (bit_sub<25,7>(instr) << 5)); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), + fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 17); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 18: ADDI */ + compile_ret_t __addi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ADDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 18); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "addi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 18); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 19: SLTI */ + compile_ret_t __slti(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 19); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "slti"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 19); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 20: SLTIU */ + compile_ret_t __sltiu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTIU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 20); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "sltiu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + int32_t full_imm_val = imm; + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.load(rs1 + traits::X0, 0), + tu.constant(full_imm_val, 32U)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 20); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 21: XORI */ + compile_ret_t __xori(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("XORI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 21); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "xori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_xor( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 21); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 22: ORI */ + compile_ret_t __ori(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ORI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 22); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "ori"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_or( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 22); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 23: ANDI */ + compile_ret_t __andi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ANDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 23); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + int16_t imm = signextend((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "andi"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_and( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 23); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 24: SLLI */ + compile_ret_t __slli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 24); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + tu.store(tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 24); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 25: SRLI */ + compile_ret_t __srli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 25); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + tu.store(tu.lshr( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 25); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 26: SRAI */ + compile_ret_t __srai(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRAI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 26); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t shamt = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(shamt > 31){ + this->gen_raise_trap(tu, 0, 0); + } else { + if(rd != 0){ + tu.store(tu.ashr( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rd + traits::X0); + } + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 26); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 27: ADD */ + compile_ret_t __add(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ADD_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 27); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.add( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 27); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 28: SUB */ + compile_ret_t __sub(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SUB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 28); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.sub( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 28); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 29: SLL */ + compile_ret_t __sll(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 29); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 29); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 30: SLT */ + compile_ret_t __slt(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLT_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 30); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_SLT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 30); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 31: SLTU */ + compile_ret_t __sltu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SLTU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 31); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.choose( + tu.icmp( + ICmpInst::ICMP_ULT, + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, + true), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, + true)), + tu.constant(1, 32U), + tu.constant(0, 32U)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 31); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 32: XOR */ + compile_ret_t __xor(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("XOR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 32); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_xor( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 32); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 33: SRL */ + compile_ret_t __srl(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 33); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.lshr( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 33); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 34: SRA */ + compile_ret_t __sra(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRA_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 34); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.ashr( + tu.load(rs1 + traits::X0, 0), + tu.l_and( + tu.load(rs2 + traits::X0, 0), + tu.sub( + tu.constant(32, 32U), + tu.constant(1, 32U)))), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 34); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 35: OR */ + compile_ret_t __or(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("OR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 35); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_or( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 35); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 36: AND */ + compile_ret_t __and(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("AND_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 36); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.l_and( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 36); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 37: FENCE */ + compile_ret_t __fence(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("FENCE_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 37); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t succ = ((bit_sub<20,4>(instr))); + uint8_t pred = ((bit_sub<24,4>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "fence"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + tu.write_mem( + traits::FENCE, + tu.constant(0, 64U), + tu.trunc(tu.l_or( + tu.shl( + tu.constant(pred, 32U), + tu.constant(4, 32U)), + tu.constant(succ, 32U)), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 37); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 38: FENCE_I */ + compile_ret_t __fence_i(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("FENCE_I_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 38); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t imm = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "fence_i"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + tu.write_mem( + traits::FENCE, + tu.constant(1, 64U), + tu.trunc(tu.constant(imm, 32U), 32)); + tu.close_scope(); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 38); + gen_trap_check(tu); + return std::make_tuple(FLUSH); + } + + /* instruction 39: ECALL */ + compile_ret_t __ecall(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("ECALL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 39); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "ecall"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 11); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 39); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 40: EBREAK */ + compile_ret_t __ebreak(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("EBREAK_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 40); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "ebreak"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 40); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 41: URET */ + compile_ret_t __uret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("URET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 41); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "uret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 0); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 41); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 42: SRET */ + compile_ret_t __sret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SRET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 42); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "sret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 1); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 42); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 43: MRET */ + compile_ret_t __mret(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MRET_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 43); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "mret"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_leave_trap(tu, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 43); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 44: WFI */ + compile_ret_t __wfi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("WFI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 44); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "wfi"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + this->gen_wait(tu, 1); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 44); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 45: SFENCE.VMA */ + compile_ret_t __sfence_vma(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("SFENCE_VMA_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 45); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "sfence.vma"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + tu.write_mem( + traits::FENCE, + tu.constant(2, 64U), + tu.trunc(tu.constant(rs1, 32U), 32)); + tu.write_mem( + traits::FENCE, + tu.constant(3, 64U), + tu.trunc(tu.constant(rs2, 32U), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 45); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 46: CSRRW */ + compile_ret_t __csrrw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 46); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto rs_val_val = tu.assignment(tu.load(rs1 + traits::X0, 0), 32); + if(rd != 0){ + auto csr_val_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(rs_val_val, 32)); + tu.store(csr_val_val, rd + traits::X0); + } else { + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(rs_val_val, 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 46); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 47: CSRRS */ + compile_ret_t __csrrs(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRS_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 47); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto xrd_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + auto xrs1_val = tu.assignment(tu.load(rs1 + traits::X0, 0), 32); + if(rd != 0){ + tu.store(xrd_val, rd + traits::X0); + } + if(rs1 != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_or( + xrd_val, + xrs1_val), 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 47); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 48: CSRRC */ + compile_ret_t __csrrc(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRC_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 48); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto xrd_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + auto xrs1_val = tu.assignment(tu.load(rs1 + traits::X0, 0), 32); + if(rd != 0){ + tu.store(xrd_val, rd + traits::X0); + } + if(rs1 != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_and( + xrd_val, + tu.l_not(xrs1_val)), 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 48); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 49: CSRRWI */ + compile_ret_t __csrrwi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRWI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 49); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu.store(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), rd + traits::X0); + } + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.ext( + tu.constant(zimm, 32U), + 32, + true), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 49); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 50: CSRRSI */ + compile_ret_t __csrrsi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRSI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 50); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto res_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + if(zimm != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_or( + res_val, + tu.ext( + tu.constant(zimm, 32U), + 32, + true)), 32)); + } + if(rd != 0){ + tu.store(res_val, rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 50); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 51: CSRRCI */ + compile_ret_t __csrrci(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("CSRRCI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 51); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t zimm = ((bit_sub<15,5>(instr))); + uint16_t csr = ((bit_sub<20,12>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), + fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + auto res_val = tu.assignment(tu.read_mem(traits::CSR, tu.constant(csr, 16U), 32), 32); + if(rd != 0){ + tu.store(res_val, rd + traits::X0); + } + if(zimm != 0){ + tu.write_mem( + traits::CSR, + tu.constant(csr, 16U), + tu.trunc(tu.l_and( + res_val, + tu.l_not(tu.ext( + tu.constant(zimm, 32U), + 32, + true))), 32)); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 51); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 52: MUL */ + compile_ret_t __mul(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MUL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 52); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mul"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto res_val = tu.assignment(tu.mul( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 64, + true), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 64, + true)), 64); + tu.store(tu.ext( + res_val, + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 52); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 53: MULH */ + compile_ret_t __mulh(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MULH_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 53); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulh"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto res_val = tu.assignment(tu.mul( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 64, + false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 64, + false)), 64); + tu.store(tu.ext( + tu.lshr( + res_val, + tu.constant(32, 32U)), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 53); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 54: MULHSU */ + compile_ret_t __mulhsu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MULHSU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 54); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulhsu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto res_val = tu.assignment(tu.mul( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 64, + false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 64, + true)), 64); + tu.store(tu.ext( + tu.lshr( + res_val, + tu.constant(32, 32U)), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 54); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 55: MULHU */ + compile_ret_t __mulhu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("MULHU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 55); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulhu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + auto res_val = tu.assignment(tu.mul( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 64, + true), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 64, + true)), 64); + tu.store(tu.ext( + tu.lshr( + res_val, + tu.constant(32, 32U)), + 32, + true), rd + traits::X0); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 55); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 56: DIV */ + compile_ret_t __div(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("DIV_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 56); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "div"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu( " if({}) {{", tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs2 + traits::X0, 0), + tu.constant(0, 32U))); + uint32_t M1_val = - 1; + uint8_t XLM1_val = 32 - 1; + uint32_t ONE_val = 1; + uint32_t MMIN_val = ONE_val << XLM1_val; + tu( " if({}) {{", tu.b_and( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + traits::X0, 0), + tu.constant(MMIN_val, 32U)), + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs2 + traits::X0, 0), + tu.constant(M1_val, 32U)))); + tu.store(tu.constant(MMIN_val, 32U), rd + traits::X0); + tu(" }} else {{"); + tu.store(tu.sdiv( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), rd + traits::X0); + tu.close_scope(); + tu(" }} else {{"); + tu.store(tu.neg(tu.constant(1, 32U)), rd + traits::X0); + tu.close_scope(); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 56); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 57: DIVU */ + compile_ret_t __divu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("DIVU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 57); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "divu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu( " if({}) {{", tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs2 + traits::X0, 0), + tu.constant(0, 32U))); + tu.store(tu.udiv( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + tu(" }} else {{"); + tu.store(tu.neg(tu.constant(1, 32U)), rd + traits::X0); + tu.close_scope(); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 57); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 58: REM */ + compile_ret_t __rem(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("REM_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 58); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "rem"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu( " if({}) {{", tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs2 + traits::X0, 0), + tu.constant(0, 32U))); + uint32_t M1_val = - 1; + uint32_t XLM1_val = 32 - 1; + uint32_t ONE_val = 1; + uint32_t MMIN_val = ONE_val << XLM1_val; + tu( " if({}) {{", tu.b_and( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + traits::X0, 0), + tu.constant(MMIN_val, 32U)), + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs2 + traits::X0, 0), + tu.constant(M1_val, 32U)))); + tu.store(tu.constant(0, 32U), rd + traits::X0); + tu(" }} else {{"); + tu.store(tu.srem( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.ext( + tu.load(rs2 + traits::X0, 0), + 32, false)), rd + traits::X0); + tu.close_scope(); + tu(" }} else {{"); + tu.store(tu.load(rs1 + traits::X0, 0), rd + traits::X0); + tu.close_scope(); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 58); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 59: REMU */ + compile_ret_t __remu(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("REMU_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 59); + uint8_t rd = ((bit_sub<7,5>(instr))); + uint8_t rs1 = ((bit_sub<15,5>(instr))); + uint8_t rs2 = ((bit_sub<20,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "remu"), + fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+4; + tu.open_scope(); + if(rd != 0){ + tu( " if({}) {{", tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs2 + traits::X0, 0), + tu.constant(0, 32U))); + tu.store(tu.urem( + tu.load(rs1 + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + tu(" }} else {{"); + tu.store(tu.load(rs1 + traits::X0, 0), rd + traits::X0); + tu.close_scope(); + } + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 59); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 60: C.ADDI4SPN */ + compile_ret_t __c_addi4spn(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADDI4SPN_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 60); + uint8_t rd = ((bit_sub<2,3>(instr))); + uint16_t imm = ((bit_sub<5,1>(instr) << 3) | (bit_sub<6,1>(instr) << 2) | (bit_sub<7,4>(instr) << 6) | (bit_sub<11,2>(instr) << 4)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.addi4spn"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(imm == 0){ + this->gen_raise_trap(tu, 0, 2); + } + tu.store(tu.add( + tu.load(2 + traits::X0, 0), + tu.constant(imm, 32U)), rd + 8 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 60); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 61: C.LW */ + compile_ret_t __c_lw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 61); + uint8_t rd = ((bit_sub<2,3>(instr))); + uint8_t uimm = ((bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.lw"), + fmt::arg("rd", name(8+rd)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(uimm, 32U)), 32); + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), rd + 8 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 61); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 62: C.SW */ + compile_ret_t __c_sw(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SW_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 62); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t uimm = ((bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.sw"), + fmt::arg("rs2", name(8+rs2)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(uimm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + 8 + traits::X0, 0), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 62); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 63: C.ADDI */ + compile_ret_t __c_addi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 63); + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.addi"), + fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.store(tu.add( + tu.ext( + tu.load(rs1 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rs1 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 63); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 64: C.NOP */ + compile_ret_t __c_nop(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_NOP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 64); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "c.nop"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.close_scope(); + /* TODO: describe operations for C.NOP ! */ + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 64); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 65: C.JAL */ + compile_ret_t __c_jal(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_JAL_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 65); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (bit_sub<12,1>(instr) << 11)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.jal"), + fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.store(tu.add( + cur_pc_val, + tu.constant(2, 32U)), 1 + traits::X0); + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 65); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 66: C.LI */ + compile_ret_t __c_li(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 66); + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.li"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(rd == 0){ + this->gen_raise_trap(tu, 0, 2); + } + tu.store(tu.constant(imm, 32U), rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 66); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 67: C.LUI */ + compile_ret_t __c_lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LUI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 67); + int32_t imm = signextend((bit_sub<2,5>(instr) << 12) | (bit_sub<12,1>(instr) << 17)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.lui"), + fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(rd == 0){ + this->gen_raise_trap(tu, 0, 2); + } + if(imm == 0){ + this->gen_raise_trap(tu, 0, 2); + } + tu.store(tu.constant(imm, 32U), rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 67); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 68: C.ADDI16SP */ + compile_ret_t __c_addi16sp(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADDI16SP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 68); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 7) | (bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 4) | (bit_sub<12,1>(instr) << 9)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.addi16sp"), + fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.store(tu.add( + tu.ext( + tu.load(2 + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), 2 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 68); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 69: C.SRLI */ + compile_ret_t __c_srli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SRLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 69); + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srli"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rs1_idx_val = rs1 + 8; + tu.store(tu.lshr( + tu.load(rs1_idx_val + traits::X0, 0), + tu.constant(shamt, 32U)), rs1_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 69); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 70: C.SRAI */ + compile_ret_t __c_srai(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SRAI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 70); + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srai"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rs1_idx_val = rs1 + 8; + tu.store(tu.ashr( + tu.load(rs1_idx_val + traits::X0, 0), + tu.constant(shamt, 32U)), rs1_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 70); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 71: C.ANDI */ + compile_ret_t __c_andi(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ANDI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 71); + int8_t imm = signextend((bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.andi"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rs1_idx_val = rs1 + 8; + tu.store(tu.l_and( + tu.ext( + tu.load(rs1_idx_val + traits::X0, 0), + 32, false), + tu.constant(imm, 32U)), rs1_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 71); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 72: C.SUB */ + compile_ret_t __c_sub(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SUB_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 72); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.sub"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + tu.store(tu.sub( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 72); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 73: C.XOR */ + compile_ret_t __c_xor(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_XOR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 73); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.xor"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + tu.store(tu.l_xor( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 73); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 74: C.OR */ + compile_ret_t __c_or(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_OR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 74); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.or"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + tu.store(tu.l_or( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 74); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 75: C.AND */ + compile_ret_t __c_and(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_AND_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 75); + uint8_t rs2 = ((bit_sub<2,3>(instr))); + uint8_t rd = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.and"), + fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + uint8_t rd_idx_val = rd + 8; + tu.store(tu.l_and( + tu.load(rd_idx_val + traits::X0, 0), + tu.load(rs2 + 8 + traits::X0, 0)), rd_idx_val + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 75); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 76: C.J */ + compile_ret_t __c_j(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_J_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 76); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (bit_sub<12,1>(instr) << 11)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.j"), + fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 76); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 77: C.BEQZ */ + compile_ret_t __c_beqz(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_BEQZ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 77); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.beqz"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_EQ, + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(0, 32U)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(2, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 77); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 78: C.BNEZ */ + compile_ret_t __c_bnez(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_BNEZ_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 78); + int16_t imm = signextend((bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8)); + uint8_t rs1 = ((bit_sub<7,3>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.bnez"), + fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.choose( + tu.icmp( + ICmpInst::ICMP_NE, + tu.load(rs1 + 8 + traits::X0, 0), + tu.constant(0, 32U)), + tu.add( + tu.ext( + cur_pc_val, + 32, false), + tu.constant(imm, 32U)), + tu.add( + cur_pc_val, + tu.constant(2, 32U))), 32); + tu.store(PC_val_v, traits::NEXT_PC); + auto is_cont_v = tu.choose( + tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)), + tu.constant(0U, 32), tu.constant(1U, 32)); + tu.store(is_cont_v, traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 78); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 79: C.SLLI */ + compile_ret_t __c_slli(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SLLI_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 79); + uint8_t shamt = ((bit_sub<2,5>(instr))); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.slli"), + fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + if(rs1 == 0){ + this->gen_raise_trap(tu, 0, 2); + } + tu.store(tu.shl( + tu.load(rs1 + traits::X0, 0), + tu.constant(shamt, 32U)), rs1 + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 79); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 80: C.LWSP */ + compile_ret_t __c_lwsp(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_LWSP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 80); + uint8_t uimm = ((bit_sub<2,2>(instr) << 6) | (bit_sub<4,3>(instr) << 2) | (bit_sub<12,1>(instr) << 5)); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, sp, {uimm:#05x}", fmt::arg("mnemonic", "c.lwsp"), + fmt::arg("rd", name(rd)), fmt::arg("uimm", uimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.load(2 + traits::X0, 0), + tu.constant(uimm, 32U)), 32); + tu.store(tu.ext( + tu.read_mem(traits::MEM, offs_val, 32), + 32, + false), rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 80); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 81: C.MV */ + compile_ret_t __c_mv(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_MV_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 81); + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.mv"), + fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.store(tu.load(rs2 + traits::X0, 0), rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 81); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 82: C.JR */ + compile_ret_t __c_jr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_JR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 82); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jr"), + fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits::X0, 0), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 82); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 83: C.ADD */ + compile_ret_t __c_add(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_ADD_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 83); + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t rd = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.add"), + fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.store(tu.add( + tu.load(rd + traits::X0, 0), + tu.load(rs2 + traits::X0, 0)), rd + traits::X0); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 83); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 84: C.JALR */ + compile_ret_t __c_jalr(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_JALR_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 84); + uint8_t rs1 = ((bit_sub<7,5>(instr))); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jalr"), + fmt::arg("rs1", name(rs1))); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + tu.store(tu.add( + cur_pc_val, + tu.constant(2, 32U)), 1 + traits::X0); + auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits::X0, 0), 32); + tu.store(PC_val_v, traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32U), traits::LAST_BRANCH); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 84); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 85: C.EBREAK */ + compile_ret_t __c_ebreak(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_EBREAK_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 85); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "c.ebreak"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 3); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 85); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /* instruction 86: C.SWSP */ + compile_ret_t __c_swsp(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("C_SWSP_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 86); + uint8_t rs2 = ((bit_sub<2,5>(instr))); + uint8_t uimm = ((bit_sub<7,2>(instr) << 6) | (bit_sub<9,4>(instr) << 2)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + auto mnemonic = fmt::format( + "{mnemonic:10} {rs2}, {uimm:#05x}(sp)", fmt::arg("mnemonic", "c.swsp"), + fmt::arg("rs2", name(rs2)), fmt::arg("uimm", uimm)); + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, mnemonic); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + auto offs_val = tu.assignment(tu.add( + tu.load(2 + traits::X0, 0), + tu.constant(uimm, 32U)), 32); + tu.write_mem( + traits::MEM, + offs_val, + tu.trunc(tu.load(rs2 + traits::X0, 0), 32)); + tu.close_scope(); + gen_set_pc(tu, pc, traits::NEXT_PC); + vm_base::gen_sync(tu, POST_SYNC, 86); + gen_trap_check(tu); + return std::make_tuple(CONT); + } + + /* instruction 87: DII */ + compile_ret_t __dii(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ + tu("DII_{:#010x}:", pc.val); + vm_base::gen_sync(tu, PRE_SYNC, 87); + if(this->disass_enabled){ + /* generate console output when executing the command */ + tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, "dii"); + } + auto cur_pc_val = tu.constant(pc.val, arch::traits::reg_bit_widths[traits::PC]); + pc=pc+2; + tu.open_scope(); + this->gen_raise_trap(tu, 0, 2); + tu.close_scope(); + vm_base::gen_sync(tu, POST_SYNC, 87); + gen_trap_check(tu); + return std::make_tuple(BRANCH); + } + + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) { + vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size()); + pc = pc + ((instr & 3) == 3 ? 4 : 2); + gen_raise_trap(tu, 0, 2); // illegal instruction trap + vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size()); + vm_impl::gen_trap_check(tu); + return BRANCH; + } +}; + +template void debug_fn(CODE_WORD insn) { + volatile CODE_WORD x = insn; + insn = 2 * x; +} + +template vm_impl::vm_impl() { this(new ARCH()); } + +template +vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) +: vm_base(core, core_id, cluster_id) { + qlut[0] = lut_00.data(); + qlut[1] = lut_01.data(); + qlut[2] = lut_10.data(); + qlut[3] = lut_11.data(); + for (auto instr : instr_descr) { + auto quantrant = instr.value & 0x3; + expand_bit_mask(29, lutmasks[quantrant], instr.value >> 2, instr.mask >> 2, 0, qlut[quantrant], instr.op); + } +} + +template +std::tuple +vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { + // we fetch at max 4 byte, alignment is 2 + enum {TRAP_ID=1<<16}; + code_word_t insn = 0; + const typename traits::addr_t upper_bits = ~traits::PGMASK; + phys_addr_t paddr(pc); + auto *const data = (uint8_t *)&insn; + paddr = this->core.v2p(pc); + if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary + auto res = this->core.read(paddr, 2, data); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + if ((insn & 0x3) == 0x3) { // this is a 32bit instruction + res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); + } + } else { + auto res = this->core.read(paddr, 4, data); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + } + if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' + // curr pc on stack + ++inst_cnt; + auto lut_val = extract_fields(insn); + auto f = qlut[insn & 0x3][lut_val]; + if (f == nullptr) { + f = &this_class::illegal_intruction; + } + return (this->*f)(pc, insn, tu); +} + +template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { + tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); +} + +template void vm_impl::gen_leave_trap(tu_builder& tu, unsigned lvl) { + tu("leave_trap(core_ptr, {});", lvl); + tu.store(tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN),traits::NEXT_PC); + tu.store(tu.constant(std::numeric_limits::max(), 32),traits::LAST_BRANCH); +} + +template void vm_impl::gen_wait(tu_builder& tu, unsigned type) { +} + +template void vm_impl::gen_trap_behavior(tu_builder& tu) { + tu("trap_entry:"); + tu("enter_trap(core_ptr, *trap_state, *pc);"); + tu.store(tu.constant(std::numeric_limits::max(),32),traits::LAST_BRANCH); + tu("return *next_pc;"); +} + +} // namespace mnrv32 + +template <> +std::unique_ptr create(arch::tgf02 *core, unsigned short port, bool dump) { + auto ret = new tgf02::vm_impl(*core, dump); + if (port != 0) debugger::server::run_server(ret, port); + return std::unique_ptr(ret); +} +} +} // namespace iss