1bdd1243dSDimitry Andric //===-- EmulateInstructionRISCV.cpp ---------------------------------------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric 9bdd1243dSDimitry Andric #include "EmulateInstructionRISCV.h" 10bdd1243dSDimitry Andric #include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h" 11bdd1243dSDimitry Andric #include "Plugins/Process/Utility/lldb-riscv-register-enums.h" 12bdd1243dSDimitry Andric #include "RISCVCInstructions.h" 13bdd1243dSDimitry Andric #include "RISCVInstructions.h" 14bdd1243dSDimitry Andric 15bdd1243dSDimitry Andric #include "lldb/Core/Address.h" 16bdd1243dSDimitry Andric #include "lldb/Core/PluginManager.h" 17bdd1243dSDimitry Andric #include "lldb/Interpreter/OptionValueArray.h" 18bdd1243dSDimitry Andric #include "lldb/Interpreter/OptionValueDictionary.h" 19bdd1243dSDimitry Andric #include "lldb/Symbol/UnwindPlan.h" 20bdd1243dSDimitry Andric #include "lldb/Utility/ArchSpec.h" 21bdd1243dSDimitry Andric #include "lldb/Utility/LLDBLog.h" 22bdd1243dSDimitry Andric #include "lldb/Utility/Stream.h" 23bdd1243dSDimitry Andric 24bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 25bdd1243dSDimitry Andric #include "llvm/Support/MathExtras.h" 26bdd1243dSDimitry Andric #include <optional> 27bdd1243dSDimitry Andric 28bdd1243dSDimitry Andric using namespace llvm; 29bdd1243dSDimitry Andric using namespace lldb; 30bdd1243dSDimitry Andric using namespace lldb_private; 31bdd1243dSDimitry Andric 32bdd1243dSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV) 33bdd1243dSDimitry Andric 34bdd1243dSDimitry Andric namespace lldb_private { 35bdd1243dSDimitry Andric 36bdd1243dSDimitry Andric /// Returns all values wrapped in Optional, or std::nullopt if any of the values 37bdd1243dSDimitry Andric /// is std::nullopt. 38bdd1243dSDimitry Andric template <typename... Ts> 39bdd1243dSDimitry Andric static std::optional<std::tuple<Ts...>> zipOpt(std::optional<Ts> &&...ts) { 40bdd1243dSDimitry Andric if ((ts.has_value() && ...)) 41bdd1243dSDimitry Andric return std::optional<std::tuple<Ts...>>(std::make_tuple(std::move(*ts)...)); 42bdd1243dSDimitry Andric else 43bdd1243dSDimitry Andric return std::nullopt; 44bdd1243dSDimitry Andric } 45bdd1243dSDimitry Andric 46bdd1243dSDimitry Andric // The funct3 is the type of compare in B<CMP> instructions. 47bdd1243dSDimitry Andric // funct3 means "3-bits function selector", which RISC-V ISA uses as minor 48bdd1243dSDimitry Andric // opcode. It reuses the major opcode encoding space. 49bdd1243dSDimitry Andric constexpr uint32_t BEQ = 0b000; 50bdd1243dSDimitry Andric constexpr uint32_t BNE = 0b001; 51bdd1243dSDimitry Andric constexpr uint32_t BLT = 0b100; 52bdd1243dSDimitry Andric constexpr uint32_t BGE = 0b101; 53bdd1243dSDimitry Andric constexpr uint32_t BLTU = 0b110; 54bdd1243dSDimitry Andric constexpr uint32_t BGEU = 0b111; 55bdd1243dSDimitry Andric 56bdd1243dSDimitry Andric // used in decoder 57bdd1243dSDimitry Andric constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); } 58bdd1243dSDimitry Andric 59bdd1243dSDimitry Andric // used in executor 60bdd1243dSDimitry Andric template <typename T> 61bdd1243dSDimitry Andric constexpr std::enable_if_t<sizeof(T) <= 4, uint64_t> SextW(T value) { 62bdd1243dSDimitry Andric return uint64_t(int64_t(int32_t(value))); 63bdd1243dSDimitry Andric } 64bdd1243dSDimitry Andric 65bdd1243dSDimitry Andric // used in executor 66bdd1243dSDimitry Andric template <typename T> constexpr uint64_t ZextD(T value) { 67bdd1243dSDimitry Andric return uint64_t(value); 68bdd1243dSDimitry Andric } 69bdd1243dSDimitry Andric 70bdd1243dSDimitry Andric constexpr uint32_t DecodeJImm(uint32_t inst) { 71bdd1243dSDimitry Andric return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 11)) // imm[20] 72bdd1243dSDimitry Andric | (inst & 0xff000) // imm[19:12] 73bdd1243dSDimitry Andric | ((inst >> 9) & 0x800) // imm[11] 74bdd1243dSDimitry Andric | ((inst >> 20) & 0x7fe); // imm[10:1] 75bdd1243dSDimitry Andric } 76bdd1243dSDimitry Andric 77bdd1243dSDimitry Andric constexpr uint32_t DecodeIImm(uint32_t inst) { 78bdd1243dSDimitry Andric return int64_t(int32_t(inst)) >> 20; // imm[11:0] 79bdd1243dSDimitry Andric } 80bdd1243dSDimitry Andric 81bdd1243dSDimitry Andric constexpr uint32_t DecodeBImm(uint32_t inst) { 82bdd1243dSDimitry Andric return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 19)) // imm[12] 83bdd1243dSDimitry Andric | ((inst & 0x80) << 4) // imm[11] 84bdd1243dSDimitry Andric | ((inst >> 20) & 0x7e0) // imm[10:5] 85bdd1243dSDimitry Andric | ((inst >> 7) & 0x1e); // imm[4:1] 86bdd1243dSDimitry Andric } 87bdd1243dSDimitry Andric 88bdd1243dSDimitry Andric constexpr uint32_t DecodeSImm(uint32_t inst) { 89bdd1243dSDimitry Andric return (uint64_t(int64_t(int32_t(inst & 0xFE000000)) >> 20)) // imm[11:5] 90bdd1243dSDimitry Andric | ((inst & 0xF80) >> 7); // imm[4:0] 91bdd1243dSDimitry Andric } 92bdd1243dSDimitry Andric 93bdd1243dSDimitry Andric constexpr uint32_t DecodeUImm(uint32_t inst) { 94bdd1243dSDimitry Andric return SextW(inst & 0xFFFFF000); // imm[31:12] 95bdd1243dSDimitry Andric } 96bdd1243dSDimitry Andric 97bdd1243dSDimitry Andric static uint32_t GPREncodingToLLDB(uint32_t reg_encode) { 98bdd1243dSDimitry Andric if (reg_encode == 0) 99bdd1243dSDimitry Andric return gpr_x0_riscv; 100bdd1243dSDimitry Andric if (reg_encode >= 1 && reg_encode <= 31) 101bdd1243dSDimitry Andric return gpr_x1_riscv + reg_encode - 1; 102bdd1243dSDimitry Andric return LLDB_INVALID_REGNUM; 103bdd1243dSDimitry Andric } 104bdd1243dSDimitry Andric 105bdd1243dSDimitry Andric static uint32_t FPREncodingToLLDB(uint32_t reg_encode) { 106bdd1243dSDimitry Andric if (reg_encode <= 31) 107bdd1243dSDimitry Andric return fpr_f0_riscv + reg_encode; 108bdd1243dSDimitry Andric return LLDB_INVALID_REGNUM; 109bdd1243dSDimitry Andric } 110bdd1243dSDimitry Andric 111bdd1243dSDimitry Andric bool Rd::Write(EmulateInstructionRISCV &emulator, uint64_t value) { 112bdd1243dSDimitry Andric uint32_t lldb_reg = GPREncodingToLLDB(rd); 113bdd1243dSDimitry Andric EmulateInstruction::Context ctx; 114bdd1243dSDimitry Andric ctx.type = EmulateInstruction::eContextRegisterStore; 115bdd1243dSDimitry Andric ctx.SetNoArgs(); 116bdd1243dSDimitry Andric RegisterValue registerValue; 117bdd1243dSDimitry Andric registerValue.SetUInt64(value); 118bdd1243dSDimitry Andric return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg, 119bdd1243dSDimitry Andric registerValue); 120bdd1243dSDimitry Andric } 121bdd1243dSDimitry Andric 122bdd1243dSDimitry Andric bool Rd::WriteAPFloat(EmulateInstructionRISCV &emulator, APFloat value) { 123bdd1243dSDimitry Andric uint32_t lldb_reg = FPREncodingToLLDB(rd); 124bdd1243dSDimitry Andric EmulateInstruction::Context ctx; 125bdd1243dSDimitry Andric ctx.type = EmulateInstruction::eContextRegisterStore; 126bdd1243dSDimitry Andric ctx.SetNoArgs(); 127bdd1243dSDimitry Andric RegisterValue registerValue; 128bdd1243dSDimitry Andric registerValue.SetUInt64(value.bitcastToAPInt().getZExtValue()); 129bdd1243dSDimitry Andric return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg, 130bdd1243dSDimitry Andric registerValue); 131bdd1243dSDimitry Andric } 132bdd1243dSDimitry Andric 133bdd1243dSDimitry Andric std::optional<uint64_t> Rs::Read(EmulateInstructionRISCV &emulator) { 134bdd1243dSDimitry Andric uint32_t lldbReg = GPREncodingToLLDB(rs); 135bdd1243dSDimitry Andric RegisterValue value; 136bdd1243dSDimitry Andric return emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value) 137bdd1243dSDimitry Andric ? std::optional<uint64_t>(value.GetAsUInt64()) 138bdd1243dSDimitry Andric : std::nullopt; 139bdd1243dSDimitry Andric } 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric std::optional<int32_t> Rs::ReadI32(EmulateInstructionRISCV &emulator) { 142bdd1243dSDimitry Andric return transformOptional( 143bdd1243dSDimitry Andric Read(emulator), [](uint64_t value) { return int32_t(uint32_t(value)); }); 144bdd1243dSDimitry Andric } 145bdd1243dSDimitry Andric 146bdd1243dSDimitry Andric std::optional<int64_t> Rs::ReadI64(EmulateInstructionRISCV &emulator) { 147bdd1243dSDimitry Andric return transformOptional(Read(emulator), 148bdd1243dSDimitry Andric [](uint64_t value) { return int64_t(value); }); 149bdd1243dSDimitry Andric } 150bdd1243dSDimitry Andric 151bdd1243dSDimitry Andric std::optional<uint32_t> Rs::ReadU32(EmulateInstructionRISCV &emulator) { 152bdd1243dSDimitry Andric return transformOptional(Read(emulator), 153bdd1243dSDimitry Andric [](uint64_t value) { return uint32_t(value); }); 154bdd1243dSDimitry Andric } 155bdd1243dSDimitry Andric 156bdd1243dSDimitry Andric std::optional<APFloat> Rs::ReadAPFloat(EmulateInstructionRISCV &emulator, 157bdd1243dSDimitry Andric bool isDouble) { 158bdd1243dSDimitry Andric uint32_t lldbReg = FPREncodingToLLDB(rs); 159bdd1243dSDimitry Andric RegisterValue value; 160bdd1243dSDimitry Andric if (!emulator.ReadRegister(eRegisterKindLLDB, lldbReg, value)) 161bdd1243dSDimitry Andric return std::nullopt; 162bdd1243dSDimitry Andric uint64_t bits = value.GetAsUInt64(); 163bdd1243dSDimitry Andric APInt api(64, bits, false); 164bdd1243dSDimitry Andric return APFloat(isDouble ? APFloat(api.bitsToDouble()) 165bdd1243dSDimitry Andric : APFloat(api.bitsToFloat())); 166bdd1243dSDimitry Andric } 167bdd1243dSDimitry Andric 168bdd1243dSDimitry Andric static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) { 169bdd1243dSDimitry Andric switch (funct3) { 170bdd1243dSDimitry Andric case BEQ: 171bdd1243dSDimitry Andric return rs1 == rs2; 172bdd1243dSDimitry Andric case BNE: 173bdd1243dSDimitry Andric return rs1 != rs2; 174bdd1243dSDimitry Andric case BLT: 175bdd1243dSDimitry Andric return int64_t(rs1) < int64_t(rs2); 176bdd1243dSDimitry Andric case BGE: 177bdd1243dSDimitry Andric return int64_t(rs1) >= int64_t(rs2); 178bdd1243dSDimitry Andric case BLTU: 179bdd1243dSDimitry Andric return rs1 < rs2; 180bdd1243dSDimitry Andric case BGEU: 181bdd1243dSDimitry Andric return rs1 >= rs2; 182bdd1243dSDimitry Andric default: 183bdd1243dSDimitry Andric llvm_unreachable("unexpected funct3"); 184bdd1243dSDimitry Andric } 185bdd1243dSDimitry Andric } 186bdd1243dSDimitry Andric 187bdd1243dSDimitry Andric template <typename T> 188bdd1243dSDimitry Andric constexpr bool is_load = 189bdd1243dSDimitry Andric std::is_same_v<T, LB> || std::is_same_v<T, LH> || std::is_same_v<T, LW> || 190bdd1243dSDimitry Andric std::is_same_v<T, LD> || std::is_same_v<T, LBU> || std::is_same_v<T, LHU> || 191bdd1243dSDimitry Andric std::is_same_v<T, LWU>; 192bdd1243dSDimitry Andric 193bdd1243dSDimitry Andric template <typename T> 194bdd1243dSDimitry Andric constexpr bool is_store = std::is_same_v<T, SB> || std::is_same_v<T, SH> || 195bdd1243dSDimitry Andric std::is_same_v<T, SW> || std::is_same_v<T, SD>; 196bdd1243dSDimitry Andric 197bdd1243dSDimitry Andric template <typename T> 198bdd1243dSDimitry Andric constexpr bool is_amo_add = 199bdd1243dSDimitry Andric std::is_same_v<T, AMOADD_W> || std::is_same_v<T, AMOADD_D>; 200bdd1243dSDimitry Andric 201bdd1243dSDimitry Andric template <typename T> 202bdd1243dSDimitry Andric constexpr bool is_amo_bit_op = 203bdd1243dSDimitry Andric std::is_same_v<T, AMOXOR_W> || std::is_same_v<T, AMOXOR_D> || 204bdd1243dSDimitry Andric std::is_same_v<T, AMOAND_W> || std::is_same_v<T, AMOAND_D> || 205bdd1243dSDimitry Andric std::is_same_v<T, AMOOR_W> || std::is_same_v<T, AMOOR_D>; 206bdd1243dSDimitry Andric 207bdd1243dSDimitry Andric template <typename T> 208bdd1243dSDimitry Andric constexpr bool is_amo_swap = 209bdd1243dSDimitry Andric std::is_same_v<T, AMOSWAP_W> || std::is_same_v<T, AMOSWAP_D>; 210bdd1243dSDimitry Andric 211bdd1243dSDimitry Andric template <typename T> 212bdd1243dSDimitry Andric constexpr bool is_amo_cmp = 213bdd1243dSDimitry Andric std::is_same_v<T, AMOMIN_W> || std::is_same_v<T, AMOMIN_D> || 214bdd1243dSDimitry Andric std::is_same_v<T, AMOMAX_W> || std::is_same_v<T, AMOMAX_D> || 215bdd1243dSDimitry Andric std::is_same_v<T, AMOMINU_W> || std::is_same_v<T, AMOMINU_D> || 216bdd1243dSDimitry Andric std::is_same_v<T, AMOMAXU_W> || std::is_same_v<T, AMOMAXU_D>; 217bdd1243dSDimitry Andric 218bdd1243dSDimitry Andric template <typename I> 219bdd1243dSDimitry Andric static std::enable_if_t<is_load<I> || is_store<I>, std::optional<uint64_t>> 220bdd1243dSDimitry Andric LoadStoreAddr(EmulateInstructionRISCV &emulator, I inst) { 221bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(emulator), [&](uint64_t rs1) { 222bdd1243dSDimitry Andric return rs1 + uint64_t(SignExt(inst.imm)); 223bdd1243dSDimitry Andric }); 224bdd1243dSDimitry Andric } 225bdd1243dSDimitry Andric 226bdd1243dSDimitry Andric // Read T from memory, then load its sign-extended value m_emu to register. 227bdd1243dSDimitry Andric template <typename I, typename T, typename E> 228bdd1243dSDimitry Andric static std::enable_if_t<is_load<I>, bool> 229bdd1243dSDimitry Andric Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) { 230bdd1243dSDimitry Andric auto addr = LoadStoreAddr(emulator, inst); 231bdd1243dSDimitry Andric if (!addr) 232bdd1243dSDimitry Andric return false; 233bdd1243dSDimitry Andric return transformOptional( 234bdd1243dSDimitry Andric emulator.ReadMem<T>(*addr), 235bdd1243dSDimitry Andric [&](T t) { return inst.rd.Write(emulator, extend(E(t))); }) 236bdd1243dSDimitry Andric .value_or(false); 237bdd1243dSDimitry Andric } 238bdd1243dSDimitry Andric 239bdd1243dSDimitry Andric template <typename I, typename T> 240bdd1243dSDimitry Andric static std::enable_if_t<is_store<I>, bool> 241bdd1243dSDimitry Andric Store(EmulateInstructionRISCV &emulator, I inst) { 242bdd1243dSDimitry Andric auto addr = LoadStoreAddr(emulator, inst); 243bdd1243dSDimitry Andric if (!addr) 244bdd1243dSDimitry Andric return false; 245bdd1243dSDimitry Andric return transformOptional( 246bdd1243dSDimitry Andric inst.rs2.Read(emulator), 247bdd1243dSDimitry Andric [&](uint64_t rs2) { return emulator.WriteMem<T>(*addr, rs2); }) 248bdd1243dSDimitry Andric .value_or(false); 249bdd1243dSDimitry Andric } 250bdd1243dSDimitry Andric 251bdd1243dSDimitry Andric template <typename I> 252bdd1243dSDimitry Andric static std::enable_if_t<is_amo_add<I> || is_amo_bit_op<I> || is_amo_swap<I> || 253bdd1243dSDimitry Andric is_amo_cmp<I>, 254bdd1243dSDimitry Andric std::optional<uint64_t>> 255bdd1243dSDimitry Andric AtomicAddr(EmulateInstructionRISCV &emulator, I inst, unsigned int align) { 256bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(emulator), 257bdd1243dSDimitry Andric [&](uint64_t rs1) { 258bdd1243dSDimitry Andric return rs1 % align == 0 259bdd1243dSDimitry Andric ? std::optional<uint64_t>(rs1) 260bdd1243dSDimitry Andric : std::nullopt; 261bdd1243dSDimitry Andric }) 262bdd1243dSDimitry Andric .value_or(std::nullopt); 263bdd1243dSDimitry Andric } 264bdd1243dSDimitry Andric 265bdd1243dSDimitry Andric template <typename I, typename T> 266bdd1243dSDimitry Andric static std::enable_if_t<is_amo_swap<I>, bool> 267bdd1243dSDimitry Andric AtomicSwap(EmulateInstructionRISCV &emulator, I inst, int align, 268bdd1243dSDimitry Andric uint64_t (*extend)(T)) { 269bdd1243dSDimitry Andric auto addr = AtomicAddr(emulator, inst, align); 270bdd1243dSDimitry Andric if (!addr) 271bdd1243dSDimitry Andric return false; 272bdd1243dSDimitry Andric return transformOptional( 273bdd1243dSDimitry Andric zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)), 274bdd1243dSDimitry Andric [&](auto &&tup) { 275bdd1243dSDimitry Andric auto [tmp, rs2] = tup; 276bdd1243dSDimitry Andric return emulator.WriteMem<T>(*addr, T(rs2)) && 277bdd1243dSDimitry Andric inst.rd.Write(emulator, extend(tmp)); 278bdd1243dSDimitry Andric }) 279bdd1243dSDimitry Andric .value_or(false); 280bdd1243dSDimitry Andric } 281bdd1243dSDimitry Andric 282bdd1243dSDimitry Andric template <typename I, typename T> 283bdd1243dSDimitry Andric static std::enable_if_t<is_amo_add<I>, bool> 284bdd1243dSDimitry Andric AtomicADD(EmulateInstructionRISCV &emulator, I inst, int align, 285bdd1243dSDimitry Andric uint64_t (*extend)(T)) { 286bdd1243dSDimitry Andric auto addr = AtomicAddr(emulator, inst, align); 287bdd1243dSDimitry Andric if (!addr) 288bdd1243dSDimitry Andric return false; 289bdd1243dSDimitry Andric return transformOptional( 290bdd1243dSDimitry Andric zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)), 291bdd1243dSDimitry Andric [&](auto &&tup) { 292bdd1243dSDimitry Andric auto [tmp, rs2] = tup; 293bdd1243dSDimitry Andric return emulator.WriteMem<T>(*addr, T(tmp + rs2)) && 294bdd1243dSDimitry Andric inst.rd.Write(emulator, extend(tmp)); 295bdd1243dSDimitry Andric }) 296bdd1243dSDimitry Andric .value_or(false); 297bdd1243dSDimitry Andric } 298bdd1243dSDimitry Andric 299bdd1243dSDimitry Andric template <typename I, typename T> 300bdd1243dSDimitry Andric static std::enable_if_t<is_amo_bit_op<I>, bool> 301bdd1243dSDimitry Andric AtomicBitOperate(EmulateInstructionRISCV &emulator, I inst, int align, 302bdd1243dSDimitry Andric uint64_t (*extend)(T), T (*operate)(T, T)) { 303bdd1243dSDimitry Andric auto addr = AtomicAddr(emulator, inst, align); 304bdd1243dSDimitry Andric if (!addr) 305bdd1243dSDimitry Andric return false; 306bdd1243dSDimitry Andric return transformOptional( 307bdd1243dSDimitry Andric zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)), 308bdd1243dSDimitry Andric [&](auto &&tup) { 309bdd1243dSDimitry Andric auto [value, rs2] = tup; 310bdd1243dSDimitry Andric return emulator.WriteMem<T>(*addr, operate(value, T(rs2))) && 311bdd1243dSDimitry Andric inst.rd.Write(emulator, extend(value)); 312bdd1243dSDimitry Andric }) 313bdd1243dSDimitry Andric .value_or(false); 314bdd1243dSDimitry Andric } 315bdd1243dSDimitry Andric 316bdd1243dSDimitry Andric template <typename I, typename T> 317bdd1243dSDimitry Andric static std::enable_if_t<is_amo_cmp<I>, bool> 318bdd1243dSDimitry Andric AtomicCmp(EmulateInstructionRISCV &emulator, I inst, int align, 319bdd1243dSDimitry Andric uint64_t (*extend)(T), T (*cmp)(T, T)) { 320bdd1243dSDimitry Andric auto addr = AtomicAddr(emulator, inst, align); 321bdd1243dSDimitry Andric if (!addr) 322bdd1243dSDimitry Andric return false; 323bdd1243dSDimitry Andric return transformOptional( 324bdd1243dSDimitry Andric zipOpt(emulator.ReadMem<T>(*addr), inst.rs2.Read(emulator)), 325bdd1243dSDimitry Andric [&](auto &&tup) { 326bdd1243dSDimitry Andric auto [value, rs2] = tup; 327bdd1243dSDimitry Andric return emulator.WriteMem<T>(*addr, cmp(value, T(rs2))) && 328bdd1243dSDimitry Andric inst.rd.Write(emulator, extend(value)); 329bdd1243dSDimitry Andric }) 330bdd1243dSDimitry Andric .value_or(false); 331bdd1243dSDimitry Andric } 332bdd1243dSDimitry Andric 333bdd1243dSDimitry Andric bool AtomicSequence(EmulateInstructionRISCV &emulator) { 334bdd1243dSDimitry Andric // The atomic sequence is always 4 instructions long: 335bdd1243dSDimitry Andric // example: 336bdd1243dSDimitry Andric // 110cc: 100427af lr.w a5,(s0) 337bdd1243dSDimitry Andric // 110d0: 00079663 bnez a5,110dc 338bdd1243dSDimitry Andric // 110d4: 1ce426af sc.w.aq a3,a4,(s0) 339bdd1243dSDimitry Andric // 110d8: fe069ae3 bnez a3,110cc 340bdd1243dSDimitry Andric // 110dc: ........ <next instruction> 341bdd1243dSDimitry Andric const auto pc = emulator.ReadPC(); 342bdd1243dSDimitry Andric if (!pc) 343bdd1243dSDimitry Andric return false; 344bdd1243dSDimitry Andric auto current_pc = *pc; 345bdd1243dSDimitry Andric const auto entry_pc = current_pc; 346bdd1243dSDimitry Andric 347bdd1243dSDimitry Andric // The first instruction should be LR.W or LR.D 348bdd1243dSDimitry Andric auto inst = emulator.ReadInstructionAt(current_pc); 349bdd1243dSDimitry Andric if (!inst || (!std::holds_alternative<LR_W>(inst->decoded) && 350bdd1243dSDimitry Andric !std::holds_alternative<LR_D>(inst->decoded))) 351bdd1243dSDimitry Andric return false; 352bdd1243dSDimitry Andric 353bdd1243dSDimitry Andric // The second instruction should be BNE to exit address 354bdd1243dSDimitry Andric inst = emulator.ReadInstructionAt(current_pc += 4); 355bdd1243dSDimitry Andric if (!inst || !std::holds_alternative<B>(inst->decoded)) 356bdd1243dSDimitry Andric return false; 357bdd1243dSDimitry Andric auto bne_exit = std::get<B>(inst->decoded); 358bdd1243dSDimitry Andric if (bne_exit.funct3 != BNE) 359bdd1243dSDimitry Andric return false; 360bdd1243dSDimitry Andric // save the exit address to check later 361bdd1243dSDimitry Andric const auto exit_pc = current_pc + SextW(bne_exit.imm); 362bdd1243dSDimitry Andric 363bdd1243dSDimitry Andric // The third instruction should be SC.W or SC.D 364bdd1243dSDimitry Andric inst = emulator.ReadInstructionAt(current_pc += 4); 365bdd1243dSDimitry Andric if (!inst || (!std::holds_alternative<SC_W>(inst->decoded) && 366bdd1243dSDimitry Andric !std::holds_alternative<SC_D>(inst->decoded))) 367bdd1243dSDimitry Andric return false; 368bdd1243dSDimitry Andric 369bdd1243dSDimitry Andric // The fourth instruction should be BNE to entry address 370bdd1243dSDimitry Andric inst = emulator.ReadInstructionAt(current_pc += 4); 371bdd1243dSDimitry Andric if (!inst || !std::holds_alternative<B>(inst->decoded)) 372bdd1243dSDimitry Andric return false; 373bdd1243dSDimitry Andric auto bne_start = std::get<B>(inst->decoded); 374bdd1243dSDimitry Andric if (bne_start.funct3 != BNE) 375bdd1243dSDimitry Andric return false; 376bdd1243dSDimitry Andric if (entry_pc != current_pc + SextW(bne_start.imm)) 377bdd1243dSDimitry Andric return false; 378bdd1243dSDimitry Andric 379bdd1243dSDimitry Andric current_pc += 4; 380bdd1243dSDimitry Andric // check the exit address and jump to it 381bdd1243dSDimitry Andric return exit_pc == current_pc && emulator.WritePC(current_pc); 382bdd1243dSDimitry Andric } 383bdd1243dSDimitry Andric 384bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeUType(uint32_t inst) { 385bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, DecodeUImm(inst)}; 386bdd1243dSDimitry Andric } 387bdd1243dSDimitry Andric 388bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeJType(uint32_t inst) { 389bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, DecodeJImm(inst)}; 390bdd1243dSDimitry Andric } 391bdd1243dSDimitry Andric 392bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeIType(uint32_t inst) { 393bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeIImm(inst)}; 394bdd1243dSDimitry Andric } 395bdd1243dSDimitry Andric 396bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeBType(uint32_t inst) { 397bdd1243dSDimitry Andric return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeBImm(inst), 398bdd1243dSDimitry Andric DecodeFunct3(inst)}; 399bdd1243dSDimitry Andric } 400bdd1243dSDimitry Andric 401bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeSType(uint32_t inst) { 402bdd1243dSDimitry Andric return T{Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, DecodeSImm(inst)}; 403bdd1243dSDimitry Andric } 404bdd1243dSDimitry Andric 405bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeRType(uint32_t inst) { 406bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}}; 407bdd1243dSDimitry Andric } 408bdd1243dSDimitry Andric 409bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeRShamtType(uint32_t inst) { 410bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, DecodeRS2(inst)}; 411bdd1243dSDimitry Andric } 412bdd1243dSDimitry Andric 413bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeRRS1Type(uint32_t inst) { 414bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}}; 415bdd1243dSDimitry Andric } 416bdd1243dSDimitry Andric 417bdd1243dSDimitry Andric template <typename T> static RISCVInst DecodeR4Type(uint32_t inst) { 418bdd1243dSDimitry Andric return T{Rd{DecodeRD(inst)}, Rs{DecodeRS1(inst)}, Rs{DecodeRS2(inst)}, 419bdd1243dSDimitry Andric Rs{DecodeRS3(inst)}, DecodeRM(inst)}; 420bdd1243dSDimitry Andric } 421bdd1243dSDimitry Andric 422bdd1243dSDimitry Andric static const InstrPattern PATTERNS[] = { 423bdd1243dSDimitry Andric // RV32I & RV64I (The base integer ISA) // 424bdd1243dSDimitry Andric {"LUI", 0x7F, 0x37, DecodeUType<LUI>}, 425bdd1243dSDimitry Andric {"AUIPC", 0x7F, 0x17, DecodeUType<AUIPC>}, 426bdd1243dSDimitry Andric {"JAL", 0x7F, 0x6F, DecodeJType<JAL>}, 427bdd1243dSDimitry Andric {"JALR", 0x707F, 0x67, DecodeIType<JALR>}, 428bdd1243dSDimitry Andric {"B", 0x7F, 0x63, DecodeBType<B>}, 429bdd1243dSDimitry Andric {"LB", 0x707F, 0x3, DecodeIType<LB>}, 430bdd1243dSDimitry Andric {"LH", 0x707F, 0x1003, DecodeIType<LH>}, 431bdd1243dSDimitry Andric {"LW", 0x707F, 0x2003, DecodeIType<LW>}, 432bdd1243dSDimitry Andric {"LBU", 0x707F, 0x4003, DecodeIType<LBU>}, 433bdd1243dSDimitry Andric {"LHU", 0x707F, 0x5003, DecodeIType<LHU>}, 434bdd1243dSDimitry Andric {"SB", 0x707F, 0x23, DecodeSType<SB>}, 435bdd1243dSDimitry Andric {"SH", 0x707F, 0x1023, DecodeSType<SH>}, 436bdd1243dSDimitry Andric {"SW", 0x707F, 0x2023, DecodeSType<SW>}, 437bdd1243dSDimitry Andric {"ADDI", 0x707F, 0x13, DecodeIType<ADDI>}, 438bdd1243dSDimitry Andric {"SLTI", 0x707F, 0x2013, DecodeIType<SLTI>}, 439bdd1243dSDimitry Andric {"SLTIU", 0x707F, 0x3013, DecodeIType<SLTIU>}, 440bdd1243dSDimitry Andric {"XORI", 0x707F, 0x4013, DecodeIType<XORI>}, 441bdd1243dSDimitry Andric {"ORI", 0x707F, 0x6013, DecodeIType<ORI>}, 442bdd1243dSDimitry Andric {"ANDI", 0x707F, 0x7013, DecodeIType<ANDI>}, 443bdd1243dSDimitry Andric {"SLLI", 0xF800707F, 0x1013, DecodeRShamtType<SLLI>}, 444bdd1243dSDimitry Andric {"SRLI", 0xF800707F, 0x5013, DecodeRShamtType<SRLI>}, 445bdd1243dSDimitry Andric {"SRAI", 0xF800707F, 0x40005013, DecodeRShamtType<SRAI>}, 446bdd1243dSDimitry Andric {"ADD", 0xFE00707F, 0x33, DecodeRType<ADD>}, 447bdd1243dSDimitry Andric {"SUB", 0xFE00707F, 0x40000033, DecodeRType<SUB>}, 448bdd1243dSDimitry Andric {"SLL", 0xFE00707F, 0x1033, DecodeRType<SLL>}, 449bdd1243dSDimitry Andric {"SLT", 0xFE00707F, 0x2033, DecodeRType<SLT>}, 450bdd1243dSDimitry Andric {"SLTU", 0xFE00707F, 0x3033, DecodeRType<SLTU>}, 451bdd1243dSDimitry Andric {"XOR", 0xFE00707F, 0x4033, DecodeRType<XOR>}, 452bdd1243dSDimitry Andric {"SRL", 0xFE00707F, 0x5033, DecodeRType<SRL>}, 453bdd1243dSDimitry Andric {"SRA", 0xFE00707F, 0x40005033, DecodeRType<SRA>}, 454bdd1243dSDimitry Andric {"OR", 0xFE00707F, 0x6033, DecodeRType<OR>}, 455bdd1243dSDimitry Andric {"AND", 0xFE00707F, 0x7033, DecodeRType<AND>}, 456bdd1243dSDimitry Andric {"LWU", 0x707F, 0x6003, DecodeIType<LWU>}, 457bdd1243dSDimitry Andric {"LD", 0x707F, 0x3003, DecodeIType<LD>}, 458bdd1243dSDimitry Andric {"SD", 0x707F, 0x3023, DecodeSType<SD>}, 459bdd1243dSDimitry Andric {"ADDIW", 0x707F, 0x1B, DecodeIType<ADDIW>}, 460bdd1243dSDimitry Andric {"SLLIW", 0xFE00707F, 0x101B, DecodeRShamtType<SLLIW>}, 461bdd1243dSDimitry Andric {"SRLIW", 0xFE00707F, 0x501B, DecodeRShamtType<SRLIW>}, 462bdd1243dSDimitry Andric {"SRAIW", 0xFE00707F, 0x4000501B, DecodeRShamtType<SRAIW>}, 463bdd1243dSDimitry Andric {"ADDW", 0xFE00707F, 0x3B, DecodeRType<ADDW>}, 464bdd1243dSDimitry Andric {"SUBW", 0xFE00707F, 0x4000003B, DecodeRType<SUBW>}, 465bdd1243dSDimitry Andric {"SLLW", 0xFE00707F, 0x103B, DecodeRType<SLLW>}, 466bdd1243dSDimitry Andric {"SRLW", 0xFE00707F, 0x503B, DecodeRType<SRLW>}, 467bdd1243dSDimitry Andric {"SRAW", 0xFE00707F, 0x4000503B, DecodeRType<SRAW>}, 468bdd1243dSDimitry Andric 469bdd1243dSDimitry Andric // RV32M & RV64M (The integer multiplication and division extension) // 470bdd1243dSDimitry Andric {"MUL", 0xFE00707F, 0x2000033, DecodeRType<MUL>}, 471bdd1243dSDimitry Andric {"MULH", 0xFE00707F, 0x2001033, DecodeRType<MULH>}, 472bdd1243dSDimitry Andric {"MULHSU", 0xFE00707F, 0x2002033, DecodeRType<MULHSU>}, 473bdd1243dSDimitry Andric {"MULHU", 0xFE00707F, 0x2003033, DecodeRType<MULHU>}, 474bdd1243dSDimitry Andric {"DIV", 0xFE00707F, 0x2004033, DecodeRType<DIV>}, 475bdd1243dSDimitry Andric {"DIVU", 0xFE00707F, 0x2005033, DecodeRType<DIVU>}, 476bdd1243dSDimitry Andric {"REM", 0xFE00707F, 0x2006033, DecodeRType<REM>}, 477bdd1243dSDimitry Andric {"REMU", 0xFE00707F, 0x2007033, DecodeRType<REMU>}, 478bdd1243dSDimitry Andric {"MULW", 0xFE00707F, 0x200003B, DecodeRType<MULW>}, 479bdd1243dSDimitry Andric {"DIVW", 0xFE00707F, 0x200403B, DecodeRType<DIVW>}, 480bdd1243dSDimitry Andric {"DIVUW", 0xFE00707F, 0x200503B, DecodeRType<DIVUW>}, 481bdd1243dSDimitry Andric {"REMW", 0xFE00707F, 0x200603B, DecodeRType<REMW>}, 482bdd1243dSDimitry Andric {"REMUW", 0xFE00707F, 0x200703B, DecodeRType<REMUW>}, 483bdd1243dSDimitry Andric 484bdd1243dSDimitry Andric // RV32A & RV64A (The standard atomic instruction extension) // 485bdd1243dSDimitry Andric {"LR_W", 0xF9F0707F, 0x1000202F, DecodeRRS1Type<LR_W>}, 486bdd1243dSDimitry Andric {"LR_D", 0xF9F0707F, 0x1000302F, DecodeRRS1Type<LR_D>}, 487bdd1243dSDimitry Andric {"SC_W", 0xF800707F, 0x1800202F, DecodeRType<SC_W>}, 488bdd1243dSDimitry Andric {"SC_D", 0xF800707F, 0x1800302F, DecodeRType<SC_D>}, 489bdd1243dSDimitry Andric {"AMOSWAP_W", 0xF800707F, 0x800202F, DecodeRType<AMOSWAP_W>}, 490bdd1243dSDimitry Andric {"AMOADD_W", 0xF800707F, 0x202F, DecodeRType<AMOADD_W>}, 491bdd1243dSDimitry Andric {"AMOXOR_W", 0xF800707F, 0x2000202F, DecodeRType<AMOXOR_W>}, 492bdd1243dSDimitry Andric {"AMOAND_W", 0xF800707F, 0x6000202F, DecodeRType<AMOAND_W>}, 493bdd1243dSDimitry Andric {"AMOOR_W", 0xF800707F, 0x4000202F, DecodeRType<AMOOR_W>}, 494bdd1243dSDimitry Andric {"AMOMIN_W", 0xF800707F, 0x8000202F, DecodeRType<AMOMIN_W>}, 495bdd1243dSDimitry Andric {"AMOMAX_W", 0xF800707F, 0xA000202F, DecodeRType<AMOMAX_W>}, 496bdd1243dSDimitry Andric {"AMOMINU_W", 0xF800707F, 0xC000202F, DecodeRType<AMOMINU_W>}, 497bdd1243dSDimitry Andric {"AMOMAXU_W", 0xF800707F, 0xE000202F, DecodeRType<AMOMAXU_W>}, 498bdd1243dSDimitry Andric {"AMOSWAP_D", 0xF800707F, 0x800302F, DecodeRType<AMOSWAP_D>}, 499bdd1243dSDimitry Andric {"AMOADD_D", 0xF800707F, 0x302F, DecodeRType<AMOADD_D>}, 500bdd1243dSDimitry Andric {"AMOXOR_D", 0xF800707F, 0x2000302F, DecodeRType<AMOXOR_D>}, 501bdd1243dSDimitry Andric {"AMOAND_D", 0xF800707F, 0x6000302F, DecodeRType<AMOAND_D>}, 502bdd1243dSDimitry Andric {"AMOOR_D", 0xF800707F, 0x4000302F, DecodeRType<AMOOR_D>}, 503bdd1243dSDimitry Andric {"AMOMIN_D", 0xF800707F, 0x8000302F, DecodeRType<AMOMIN_D>}, 504bdd1243dSDimitry Andric {"AMOMAX_D", 0xF800707F, 0xA000302F, DecodeRType<AMOMAX_D>}, 505bdd1243dSDimitry Andric {"AMOMINU_D", 0xF800707F, 0xC000302F, DecodeRType<AMOMINU_D>}, 506bdd1243dSDimitry Andric {"AMOMAXU_D", 0xF800707F, 0xE000302F, DecodeRType<AMOMAXU_D>}, 507bdd1243dSDimitry Andric 508bdd1243dSDimitry Andric // RVC (Compressed Instructions) // 509bdd1243dSDimitry Andric {"C_LWSP", 0xE003, 0x4002, DecodeC_LWSP}, 510bdd1243dSDimitry Andric {"C_LDSP", 0xE003, 0x6002, DecodeC_LDSP, RV64 | RV128}, 511bdd1243dSDimitry Andric {"C_SWSP", 0xE003, 0xC002, DecodeC_SWSP}, 512bdd1243dSDimitry Andric {"C_SDSP", 0xE003, 0xE002, DecodeC_SDSP, RV64 | RV128}, 513bdd1243dSDimitry Andric {"C_LW", 0xE003, 0x4000, DecodeC_LW}, 514bdd1243dSDimitry Andric {"C_LD", 0xE003, 0x6000, DecodeC_LD, RV64 | RV128}, 515bdd1243dSDimitry Andric {"C_SW", 0xE003, 0xC000, DecodeC_SW}, 516bdd1243dSDimitry Andric {"C_SD", 0xE003, 0xE000, DecodeC_SD, RV64 | RV128}, 517bdd1243dSDimitry Andric {"C_J", 0xE003, 0xA001, DecodeC_J}, 518bdd1243dSDimitry Andric {"C_JR", 0xF07F, 0x8002, DecodeC_JR}, 519bdd1243dSDimitry Andric {"C_JALR", 0xF07F, 0x9002, DecodeC_JALR}, 520bdd1243dSDimitry Andric {"C_BNEZ", 0xE003, 0xE001, DecodeC_BNEZ}, 521bdd1243dSDimitry Andric {"C_BEQZ", 0xE003, 0xC001, DecodeC_BEQZ}, 522bdd1243dSDimitry Andric {"C_LI", 0xE003, 0x4001, DecodeC_LI}, 523bdd1243dSDimitry Andric {"C_LUI_ADDI16SP", 0xE003, 0x6001, DecodeC_LUI_ADDI16SP}, 524bdd1243dSDimitry Andric {"C_ADDI", 0xE003, 0x1, DecodeC_ADDI}, 525bdd1243dSDimitry Andric {"C_ADDIW", 0xE003, 0x2001, DecodeC_ADDIW, RV64 | RV128}, 526bdd1243dSDimitry Andric {"C_ADDI4SPN", 0xE003, 0x0, DecodeC_ADDI4SPN}, 527bdd1243dSDimitry Andric {"C_SLLI", 0xE003, 0x2, DecodeC_SLLI, RV64 | RV128}, 528bdd1243dSDimitry Andric {"C_SRLI", 0xEC03, 0x8001, DecodeC_SRLI, RV64 | RV128}, 529bdd1243dSDimitry Andric {"C_SRAI", 0xEC03, 0x8401, DecodeC_SRAI, RV64 | RV128}, 530bdd1243dSDimitry Andric {"C_ANDI", 0xEC03, 0x8801, DecodeC_ANDI}, 531bdd1243dSDimitry Andric {"C_MV", 0xF003, 0x8002, DecodeC_MV}, 532bdd1243dSDimitry Andric {"C_ADD", 0xF003, 0x9002, DecodeC_ADD}, 533bdd1243dSDimitry Andric {"C_AND", 0xFC63, 0x8C61, DecodeC_AND}, 534bdd1243dSDimitry Andric {"C_OR", 0xFC63, 0x8C41, DecodeC_OR}, 535bdd1243dSDimitry Andric {"C_XOR", 0xFC63, 0x8C21, DecodeC_XOR}, 536bdd1243dSDimitry Andric {"C_SUB", 0xFC63, 0x8C01, DecodeC_SUB}, 537bdd1243dSDimitry Andric {"C_SUBW", 0xFC63, 0x9C01, DecodeC_SUBW, RV64 | RV128}, 538bdd1243dSDimitry Andric {"C_ADDW", 0xFC63, 0x9C21, DecodeC_ADDW, RV64 | RV128}, 539bdd1243dSDimitry Andric // RV32FC // 540bdd1243dSDimitry Andric {"FLW", 0xE003, 0x6000, DecodeC_FLW, RV32}, 541bdd1243dSDimitry Andric {"FSW", 0xE003, 0xE000, DecodeC_FSW, RV32}, 542bdd1243dSDimitry Andric {"FLWSP", 0xE003, 0x6002, DecodeC_FLWSP, RV32}, 543bdd1243dSDimitry Andric {"FSWSP", 0xE003, 0xE002, DecodeC_FSWSP, RV32}, 544bdd1243dSDimitry Andric // RVDC // 545bdd1243dSDimitry Andric {"FLDSP", 0xE003, 0x2002, DecodeC_FLDSP, RV32 | RV64}, 546bdd1243dSDimitry Andric {"FSDSP", 0xE003, 0xA002, DecodeC_FSDSP, RV32 | RV64}, 547bdd1243dSDimitry Andric {"FLD", 0xE003, 0x2000, DecodeC_FLD, RV32 | RV64}, 548bdd1243dSDimitry Andric {"FSD", 0xE003, 0xA000, DecodeC_FSD, RV32 | RV64}, 549bdd1243dSDimitry Andric 550bdd1243dSDimitry Andric // RV32F (Extension for Single-Precision Floating-Point) // 551bdd1243dSDimitry Andric {"FLW", 0x707F, 0x2007, DecodeIType<FLW>}, 552bdd1243dSDimitry Andric {"FSW", 0x707F, 0x2027, DecodeSType<FSW>}, 553bdd1243dSDimitry Andric {"FMADD_S", 0x600007F, 0x43, DecodeR4Type<FMADD_S>}, 554bdd1243dSDimitry Andric {"FMSUB_S", 0x600007F, 0x47, DecodeR4Type<FMSUB_S>}, 555bdd1243dSDimitry Andric {"FNMSUB_S", 0x600007F, 0x4B, DecodeR4Type<FNMSUB_S>}, 556bdd1243dSDimitry Andric {"FNMADD_S", 0x600007F, 0x4F, DecodeR4Type<FNMADD_S>}, 557bdd1243dSDimitry Andric {"FADD_S", 0xFE00007F, 0x53, DecodeRType<FADD_S>}, 558bdd1243dSDimitry Andric {"FSUB_S", 0xFE00007F, 0x8000053, DecodeRType<FSUB_S>}, 559bdd1243dSDimitry Andric {"FMUL_S", 0xFE00007F, 0x10000053, DecodeRType<FMUL_S>}, 560bdd1243dSDimitry Andric {"FDIV_S", 0xFE00007F, 0x18000053, DecodeRType<FDIV_S>}, 561bdd1243dSDimitry Andric {"FSQRT_S", 0xFFF0007F, 0x58000053, DecodeIType<FSQRT_S>}, 562bdd1243dSDimitry Andric {"FSGNJ_S", 0xFE00707F, 0x20000053, DecodeRType<FSGNJ_S>}, 563bdd1243dSDimitry Andric {"FSGNJN_S", 0xFE00707F, 0x20001053, DecodeRType<FSGNJN_S>}, 564bdd1243dSDimitry Andric {"FSGNJX_S", 0xFE00707F, 0x20002053, DecodeRType<FSGNJX_S>}, 565bdd1243dSDimitry Andric {"FMIN_S", 0xFE00707F, 0x28000053, DecodeRType<FMIN_S>}, 566bdd1243dSDimitry Andric {"FMAX_S", 0xFE00707F, 0x28001053, DecodeRType<FMAX_S>}, 567bdd1243dSDimitry Andric {"FCVT_W_S", 0xFFF0007F, 0xC0000053, DecodeIType<FCVT_W_S>}, 568bdd1243dSDimitry Andric {"FCVT_WU_S", 0xFFF0007F, 0xC0100053, DecodeIType<FCVT_WU_S>}, 569bdd1243dSDimitry Andric {"FMV_X_W", 0xFFF0707F, 0xE0000053, DecodeIType<FMV_X_W>}, 570bdd1243dSDimitry Andric {"FEQ_S", 0xFE00707F, 0xA0002053, DecodeRType<FEQ_S>}, 571bdd1243dSDimitry Andric {"FLT_S", 0xFE00707F, 0xA0001053, DecodeRType<FLT_S>}, 572bdd1243dSDimitry Andric {"FLE_S", 0xFE00707F, 0xA0000053, DecodeRType<FLE_S>}, 573bdd1243dSDimitry Andric {"FCLASS_S", 0xFFF0707F, 0xE0001053, DecodeIType<FCLASS_S>}, 574bdd1243dSDimitry Andric {"FCVT_S_W", 0xFFF0007F, 0xD0000053, DecodeIType<FCVT_S_W>}, 575bdd1243dSDimitry Andric {"FCVT_S_WU", 0xFFF0007F, 0xD0100053, DecodeIType<FCVT_S_WU>}, 576bdd1243dSDimitry Andric {"FMV_W_X", 0xFFF0707F, 0xF0000053, DecodeIType<FMV_W_X>}, 577bdd1243dSDimitry Andric 578bdd1243dSDimitry Andric // RV64F (Extension for Single-Precision Floating-Point) // 579bdd1243dSDimitry Andric {"FCVT_L_S", 0xFFF0007F, 0xC0200053, DecodeIType<FCVT_L_S>}, 580bdd1243dSDimitry Andric {"FCVT_LU_S", 0xFFF0007F, 0xC0300053, DecodeIType<FCVT_LU_S>}, 581bdd1243dSDimitry Andric {"FCVT_S_L", 0xFFF0007F, 0xD0200053, DecodeIType<FCVT_S_L>}, 582bdd1243dSDimitry Andric {"FCVT_S_LU", 0xFFF0007F, 0xD0300053, DecodeIType<FCVT_S_LU>}, 583bdd1243dSDimitry Andric 584bdd1243dSDimitry Andric // RV32D (Extension for Double-Precision Floating-Point) // 585bdd1243dSDimitry Andric {"FLD", 0x707F, 0x3007, DecodeIType<FLD>}, 586bdd1243dSDimitry Andric {"FSD", 0x707F, 0x3027, DecodeSType<FSD>}, 587bdd1243dSDimitry Andric {"FMADD_D", 0x600007F, 0x2000043, DecodeR4Type<FMADD_D>}, 588bdd1243dSDimitry Andric {"FMSUB_D", 0x600007F, 0x2000047, DecodeR4Type<FMSUB_D>}, 589bdd1243dSDimitry Andric {"FNMSUB_D", 0x600007F, 0x200004B, DecodeR4Type<FNMSUB_D>}, 590bdd1243dSDimitry Andric {"FNMADD_D", 0x600007F, 0x200004F, DecodeR4Type<FNMADD_D>}, 591bdd1243dSDimitry Andric {"FADD_D", 0xFE00007F, 0x2000053, DecodeRType<FADD_D>}, 592bdd1243dSDimitry Andric {"FSUB_D", 0xFE00007F, 0xA000053, DecodeRType<FSUB_D>}, 593bdd1243dSDimitry Andric {"FMUL_D", 0xFE00007F, 0x12000053, DecodeRType<FMUL_D>}, 594bdd1243dSDimitry Andric {"FDIV_D", 0xFE00007F, 0x1A000053, DecodeRType<FDIV_D>}, 595bdd1243dSDimitry Andric {"FSQRT_D", 0xFFF0007F, 0x5A000053, DecodeIType<FSQRT_D>}, 596bdd1243dSDimitry Andric {"FSGNJ_D", 0xFE00707F, 0x22000053, DecodeRType<FSGNJ_D>}, 597bdd1243dSDimitry Andric {"FSGNJN_D", 0xFE00707F, 0x22001053, DecodeRType<FSGNJN_D>}, 598bdd1243dSDimitry Andric {"FSGNJX_D", 0xFE00707F, 0x22002053, DecodeRType<FSGNJX_D>}, 599bdd1243dSDimitry Andric {"FMIN_D", 0xFE00707F, 0x2A000053, DecodeRType<FMIN_D>}, 600bdd1243dSDimitry Andric {"FMAX_D", 0xFE00707F, 0x2A001053, DecodeRType<FMAX_D>}, 601bdd1243dSDimitry Andric {"FCVT_S_D", 0xFFF0007F, 0x40100053, DecodeIType<FCVT_S_D>}, 602bdd1243dSDimitry Andric {"FCVT_D_S", 0xFFF0007F, 0x42000053, DecodeIType<FCVT_D_S>}, 603bdd1243dSDimitry Andric {"FEQ_D", 0xFE00707F, 0xA2002053, DecodeRType<FEQ_D>}, 604bdd1243dSDimitry Andric {"FLT_D", 0xFE00707F, 0xA2001053, DecodeRType<FLT_D>}, 605bdd1243dSDimitry Andric {"FLE_D", 0xFE00707F, 0xA2000053, DecodeRType<FLE_D>}, 606bdd1243dSDimitry Andric {"FCLASS_D", 0xFFF0707F, 0xE2001053, DecodeIType<FCLASS_D>}, 607bdd1243dSDimitry Andric {"FCVT_W_D", 0xFFF0007F, 0xC2000053, DecodeIType<FCVT_W_D>}, 608bdd1243dSDimitry Andric {"FCVT_WU_D", 0xFFF0007F, 0xC2100053, DecodeIType<FCVT_WU_D>}, 609bdd1243dSDimitry Andric {"FCVT_D_W", 0xFFF0007F, 0xD2000053, DecodeIType<FCVT_D_W>}, 610bdd1243dSDimitry Andric {"FCVT_D_WU", 0xFFF0007F, 0xD2100053, DecodeIType<FCVT_D_WU>}, 611bdd1243dSDimitry Andric 612bdd1243dSDimitry Andric // RV64D (Extension for Double-Precision Floating-Point) // 613bdd1243dSDimitry Andric {"FCVT_L_D", 0xFFF0007F, 0xC2200053, DecodeIType<FCVT_L_D>}, 614bdd1243dSDimitry Andric {"FCVT_LU_D", 0xFFF0007F, 0xC2300053, DecodeIType<FCVT_LU_D>}, 615bdd1243dSDimitry Andric {"FMV_X_D", 0xFFF0707F, 0xE2000053, DecodeIType<FMV_X_D>}, 616bdd1243dSDimitry Andric {"FCVT_D_L", 0xFFF0007F, 0xD2200053, DecodeIType<FCVT_D_L>}, 617bdd1243dSDimitry Andric {"FCVT_D_LU", 0xFFF0007F, 0xD2300053, DecodeIType<FCVT_D_LU>}, 618bdd1243dSDimitry Andric {"FMV_D_X", 0xFFF0707F, 0xF2000053, DecodeIType<FMV_D_X>}, 619bdd1243dSDimitry Andric }; 620bdd1243dSDimitry Andric 621bdd1243dSDimitry Andric std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) { 622bdd1243dSDimitry Andric Log *log = GetLog(LLDBLog::Unwind); 623bdd1243dSDimitry Andric 624bdd1243dSDimitry Andric uint16_t try_rvc = uint16_t(inst & 0x0000ffff); 625bdd1243dSDimitry Andric uint8_t inst_type = RV64; 626bdd1243dSDimitry Andric 627*0fca6ea1SDimitry Andric // Try to get size of RISCV instruction. 628*0fca6ea1SDimitry Andric // 1.2 Instruction Length Encoding 629*0fca6ea1SDimitry Andric bool is_16b = (inst & 0b11) != 0b11; 630*0fca6ea1SDimitry Andric bool is_32b = (inst & 0x1f) != 0x1f; 631*0fca6ea1SDimitry Andric bool is_48b = (inst & 0x3f) != 0x1f; 632*0fca6ea1SDimitry Andric bool is_64b = (inst & 0x7f) != 0x3f; 633*0fca6ea1SDimitry Andric if (is_16b) 634*0fca6ea1SDimitry Andric m_last_size = 2; 635*0fca6ea1SDimitry Andric else if (is_32b) 636*0fca6ea1SDimitry Andric m_last_size = 4; 637*0fca6ea1SDimitry Andric else if (is_48b) 638*0fca6ea1SDimitry Andric m_last_size = 6; 639*0fca6ea1SDimitry Andric else if (is_64b) 640*0fca6ea1SDimitry Andric m_last_size = 8; 641*0fca6ea1SDimitry Andric else 642*0fca6ea1SDimitry Andric // Not Valid 643*0fca6ea1SDimitry Andric m_last_size = std::nullopt; 644*0fca6ea1SDimitry Andric 645bdd1243dSDimitry Andric // if we have ArchSpec::eCore_riscv128 in the future, 646bdd1243dSDimitry Andric // we also need to check it here 647bdd1243dSDimitry Andric if (m_arch.GetCore() == ArchSpec::eCore_riscv32) 648bdd1243dSDimitry Andric inst_type = RV32; 649bdd1243dSDimitry Andric 650bdd1243dSDimitry Andric for (const InstrPattern &pat : PATTERNS) { 651bdd1243dSDimitry Andric if ((inst & pat.type_mask) == pat.eigen && 652bdd1243dSDimitry Andric (inst_type & pat.inst_type) != 0) { 653bdd1243dSDimitry Andric LLDB_LOGF( 65406c3fb27SDimitry Andric log, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64 ") was decoded to %s", 655bdd1243dSDimitry Andric __FUNCTION__, inst, m_addr, pat.name); 656*0fca6ea1SDimitry Andric auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst); 657*0fca6ea1SDimitry Andric return DecodeResult{decoded, inst, is_16b, pat}; 658bdd1243dSDimitry Andric } 659bdd1243dSDimitry Andric } 660bdd1243dSDimitry Andric LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported", 661bdd1243dSDimitry Andric __FUNCTION__, inst); 662bdd1243dSDimitry Andric return std::nullopt; 663bdd1243dSDimitry Andric } 664bdd1243dSDimitry Andric 665bdd1243dSDimitry Andric class Executor { 666bdd1243dSDimitry Andric EmulateInstructionRISCV &m_emu; 667bdd1243dSDimitry Andric bool m_ignore_cond; 668bdd1243dSDimitry Andric bool m_is_rvc; 669bdd1243dSDimitry Andric 670bdd1243dSDimitry Andric public: 671bdd1243dSDimitry Andric // also used in EvaluateInstruction() 672bdd1243dSDimitry Andric static uint64_t size(bool is_rvc) { return is_rvc ? 2 : 4; } 673bdd1243dSDimitry Andric 674bdd1243dSDimitry Andric private: 675bdd1243dSDimitry Andric uint64_t delta() { return size(m_is_rvc); } 676bdd1243dSDimitry Andric 677bdd1243dSDimitry Andric public: 678bdd1243dSDimitry Andric Executor(EmulateInstructionRISCV &emulator, bool ignoreCond, bool is_rvc) 679bdd1243dSDimitry Andric : m_emu(emulator), m_ignore_cond(ignoreCond), m_is_rvc(is_rvc) {} 680bdd1243dSDimitry Andric 681bdd1243dSDimitry Andric bool operator()(LUI inst) { return inst.rd.Write(m_emu, SignExt(inst.imm)); } 682bdd1243dSDimitry Andric bool operator()(AUIPC inst) { 683bdd1243dSDimitry Andric return transformOptional(m_emu.ReadPC(), 684bdd1243dSDimitry Andric [&](uint64_t pc) { 685bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 686bdd1243dSDimitry Andric SignExt(inst.imm) + pc); 687bdd1243dSDimitry Andric }) 688bdd1243dSDimitry Andric .value_or(false); 689bdd1243dSDimitry Andric } 690bdd1243dSDimitry Andric bool operator()(JAL inst) { 691bdd1243dSDimitry Andric return transformOptional(m_emu.ReadPC(), 692bdd1243dSDimitry Andric [&](uint64_t pc) { 693bdd1243dSDimitry Andric return inst.rd.Write(m_emu, pc + delta()) && 694bdd1243dSDimitry Andric m_emu.WritePC(SignExt(inst.imm) + pc); 695bdd1243dSDimitry Andric }) 696bdd1243dSDimitry Andric .value_or(false); 697bdd1243dSDimitry Andric } 698bdd1243dSDimitry Andric bool operator()(JALR inst) { 699bdd1243dSDimitry Andric return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu)), 700bdd1243dSDimitry Andric [&](auto &&tup) { 701bdd1243dSDimitry Andric auto [pc, rs1] = tup; 702bdd1243dSDimitry Andric return inst.rd.Write(m_emu, pc + delta()) && 703bdd1243dSDimitry Andric m_emu.WritePC((SignExt(inst.imm) + rs1) & 704bdd1243dSDimitry Andric ~1); 705bdd1243dSDimitry Andric }) 706bdd1243dSDimitry Andric .value_or(false); 707bdd1243dSDimitry Andric } 708bdd1243dSDimitry Andric bool operator()(B inst) { 709bdd1243dSDimitry Andric return transformOptional(zipOpt(m_emu.ReadPC(), inst.rs1.Read(m_emu), 710bdd1243dSDimitry Andric inst.rs2.Read(m_emu)), 711bdd1243dSDimitry Andric [&](auto &&tup) { 712bdd1243dSDimitry Andric auto [pc, rs1, rs2] = tup; 713bdd1243dSDimitry Andric if (m_ignore_cond || 714bdd1243dSDimitry Andric CompareB(rs1, rs2, inst.funct3)) 715bdd1243dSDimitry Andric return m_emu.WritePC(SignExt(inst.imm) + pc); 716bdd1243dSDimitry Andric return true; 717bdd1243dSDimitry Andric }) 718bdd1243dSDimitry Andric .value_or(false); 719bdd1243dSDimitry Andric } 720bdd1243dSDimitry Andric bool operator()(LB inst) { 721bdd1243dSDimitry Andric return Load<LB, uint8_t, int8_t>(m_emu, inst, SextW); 722bdd1243dSDimitry Andric } 723bdd1243dSDimitry Andric bool operator()(LH inst) { 724bdd1243dSDimitry Andric return Load<LH, uint16_t, int16_t>(m_emu, inst, SextW); 725bdd1243dSDimitry Andric } 726bdd1243dSDimitry Andric bool operator()(LW inst) { 727bdd1243dSDimitry Andric return Load<LW, uint32_t, int32_t>(m_emu, inst, SextW); 728bdd1243dSDimitry Andric } 729bdd1243dSDimitry Andric bool operator()(LBU inst) { 730bdd1243dSDimitry Andric return Load<LBU, uint8_t, uint8_t>(m_emu, inst, ZextD); 731bdd1243dSDimitry Andric } 732bdd1243dSDimitry Andric bool operator()(LHU inst) { 733bdd1243dSDimitry Andric return Load<LHU, uint16_t, uint16_t>(m_emu, inst, ZextD); 734bdd1243dSDimitry Andric } 735bdd1243dSDimitry Andric bool operator()(SB inst) { return Store<SB, uint8_t>(m_emu, inst); } 736bdd1243dSDimitry Andric bool operator()(SH inst) { return Store<SH, uint16_t>(m_emu, inst); } 737bdd1243dSDimitry Andric bool operator()(SW inst) { return Store<SW, uint32_t>(m_emu, inst); } 738bdd1243dSDimitry Andric bool operator()(ADDI inst) { 739bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadI64(m_emu), 740bdd1243dSDimitry Andric [&](int64_t rs1) { 741bdd1243dSDimitry Andric return inst.rd.Write( 742bdd1243dSDimitry Andric m_emu, rs1 + int64_t(SignExt(inst.imm))); 743bdd1243dSDimitry Andric }) 744bdd1243dSDimitry Andric .value_or(false); 745bdd1243dSDimitry Andric } 746bdd1243dSDimitry Andric bool operator()(SLTI inst) { 747bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadI64(m_emu), 748bdd1243dSDimitry Andric [&](int64_t rs1) { 749bdd1243dSDimitry Andric return inst.rd.Write( 750bdd1243dSDimitry Andric m_emu, rs1 < int64_t(SignExt(inst.imm))); 751bdd1243dSDimitry Andric }) 752bdd1243dSDimitry Andric .value_or(false); 753bdd1243dSDimitry Andric } 754bdd1243dSDimitry Andric bool operator()(SLTIU inst) { 755bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 756bdd1243dSDimitry Andric [&](uint64_t rs1) { 757bdd1243dSDimitry Andric return inst.rd.Write( 758bdd1243dSDimitry Andric m_emu, rs1 < uint64_t(SignExt(inst.imm))); 759bdd1243dSDimitry Andric }) 760bdd1243dSDimitry Andric .value_or(false); 761bdd1243dSDimitry Andric } 762bdd1243dSDimitry Andric bool operator()(XORI inst) { 763bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 764bdd1243dSDimitry Andric [&](uint64_t rs1) { 765bdd1243dSDimitry Andric return inst.rd.Write( 766bdd1243dSDimitry Andric m_emu, rs1 ^ uint64_t(SignExt(inst.imm))); 767bdd1243dSDimitry Andric }) 768bdd1243dSDimitry Andric .value_or(false); 769bdd1243dSDimitry Andric } 770bdd1243dSDimitry Andric bool operator()(ORI inst) { 771bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 772bdd1243dSDimitry Andric [&](uint64_t rs1) { 773bdd1243dSDimitry Andric return inst.rd.Write( 774bdd1243dSDimitry Andric m_emu, rs1 | uint64_t(SignExt(inst.imm))); 775bdd1243dSDimitry Andric }) 776bdd1243dSDimitry Andric .value_or(false); 777bdd1243dSDimitry Andric } 778bdd1243dSDimitry Andric bool operator()(ANDI inst) { 779bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 780bdd1243dSDimitry Andric [&](uint64_t rs1) { 781bdd1243dSDimitry Andric return inst.rd.Write( 782bdd1243dSDimitry Andric m_emu, rs1 & uint64_t(SignExt(inst.imm))); 783bdd1243dSDimitry Andric }) 784bdd1243dSDimitry Andric .value_or(false); 785bdd1243dSDimitry Andric } 786bdd1243dSDimitry Andric bool operator()(ADD inst) { 787bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 788bdd1243dSDimitry Andric [&](auto &&tup) { 789bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 790bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 + rs2); 791bdd1243dSDimitry Andric }) 792bdd1243dSDimitry Andric .value_or(false); 793bdd1243dSDimitry Andric } 794bdd1243dSDimitry Andric bool operator()(SUB inst) { 795bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 796bdd1243dSDimitry Andric [&](auto &&tup) { 797bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 798bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 - rs2); 799bdd1243dSDimitry Andric }) 800bdd1243dSDimitry Andric .value_or(false); 801bdd1243dSDimitry Andric } 802bdd1243dSDimitry Andric bool operator()(SLL inst) { 803bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 804bdd1243dSDimitry Andric [&](auto &&tup) { 805bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 806bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 807bdd1243dSDimitry Andric rs1 << (rs2 & 0b111111)); 808bdd1243dSDimitry Andric }) 809bdd1243dSDimitry Andric .value_or(false); 810bdd1243dSDimitry Andric } 811bdd1243dSDimitry Andric bool operator()(SLT inst) { 812bdd1243dSDimitry Andric return transformOptional( 813bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)), 814bdd1243dSDimitry Andric [&](auto &&tup) { 815bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 816bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 < rs2); 817bdd1243dSDimitry Andric }) 818bdd1243dSDimitry Andric .value_or(false); 819bdd1243dSDimitry Andric } 820bdd1243dSDimitry Andric bool operator()(SLTU inst) { 821bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 822bdd1243dSDimitry Andric [&](auto &&tup) { 823bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 824bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 < rs2); 825bdd1243dSDimitry Andric }) 826bdd1243dSDimitry Andric .value_or(false); 827bdd1243dSDimitry Andric } 828bdd1243dSDimitry Andric bool operator()(XOR inst) { 829bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 830bdd1243dSDimitry Andric [&](auto &&tup) { 831bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 832bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 ^ rs2); 833bdd1243dSDimitry Andric }) 834bdd1243dSDimitry Andric .value_or(false); 835bdd1243dSDimitry Andric } 836bdd1243dSDimitry Andric bool operator()(SRL inst) { 837bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 838bdd1243dSDimitry Andric [&](auto &&tup) { 839bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 840bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 841bdd1243dSDimitry Andric rs1 >> (rs2 & 0b111111)); 842bdd1243dSDimitry Andric }) 843bdd1243dSDimitry Andric .value_or(false); 844bdd1243dSDimitry Andric } 845bdd1243dSDimitry Andric bool operator()(SRA inst) { 846bdd1243dSDimitry Andric return transformOptional( 847bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.Read(m_emu)), 848bdd1243dSDimitry Andric [&](auto &&tup) { 849bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 850bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 >> (rs2 & 0b111111)); 851bdd1243dSDimitry Andric }) 852bdd1243dSDimitry Andric .value_or(false); 853bdd1243dSDimitry Andric } 854bdd1243dSDimitry Andric bool operator()(OR inst) { 855bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 856bdd1243dSDimitry Andric [&](auto &&tup) { 857bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 858bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 | rs2); 859bdd1243dSDimitry Andric }) 860bdd1243dSDimitry Andric .value_or(false); 861bdd1243dSDimitry Andric } 862bdd1243dSDimitry Andric bool operator()(AND inst) { 863bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 864bdd1243dSDimitry Andric [&](auto &&tup) { 865bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 866bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 & rs2); 867bdd1243dSDimitry Andric }) 868bdd1243dSDimitry Andric .value_or(false); 869bdd1243dSDimitry Andric } 870bdd1243dSDimitry Andric bool operator()(LWU inst) { 871bdd1243dSDimitry Andric return Load<LWU, uint32_t, uint32_t>(m_emu, inst, ZextD); 872bdd1243dSDimitry Andric } 873bdd1243dSDimitry Andric bool operator()(LD inst) { 874bdd1243dSDimitry Andric return Load<LD, uint64_t, uint64_t>(m_emu, inst, ZextD); 875bdd1243dSDimitry Andric } 876bdd1243dSDimitry Andric bool operator()(SD inst) { return Store<SD, uint64_t>(m_emu, inst); } 877bdd1243dSDimitry Andric bool operator()(SLLI inst) { 878bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 879bdd1243dSDimitry Andric [&](uint64_t rs1) { 880bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 << inst.shamt); 881bdd1243dSDimitry Andric }) 882bdd1243dSDimitry Andric .value_or(false); 883bdd1243dSDimitry Andric } 884bdd1243dSDimitry Andric bool operator()(SRLI inst) { 885bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 886bdd1243dSDimitry Andric [&](uint64_t rs1) { 887bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 >> inst.shamt); 888bdd1243dSDimitry Andric }) 889bdd1243dSDimitry Andric .value_or(false); 890bdd1243dSDimitry Andric } 891bdd1243dSDimitry Andric bool operator()(SRAI inst) { 892bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadI64(m_emu), 893bdd1243dSDimitry Andric [&](int64_t rs1) { 894bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 >> inst.shamt); 895bdd1243dSDimitry Andric }) 896bdd1243dSDimitry Andric .value_or(false); 897bdd1243dSDimitry Andric } 898bdd1243dSDimitry Andric bool operator()(ADDIW inst) { 899bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadI32(m_emu), 900bdd1243dSDimitry Andric [&](int32_t rs1) { 901bdd1243dSDimitry Andric return inst.rd.Write( 902bdd1243dSDimitry Andric m_emu, SextW(rs1 + SignExt(inst.imm))); 903bdd1243dSDimitry Andric }) 904bdd1243dSDimitry Andric .value_or(false); 905bdd1243dSDimitry Andric } 906bdd1243dSDimitry Andric bool operator()(SLLIW inst) { 907bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadU32(m_emu), 908bdd1243dSDimitry Andric [&](uint32_t rs1) { 909bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 910bdd1243dSDimitry Andric SextW(rs1 << inst.shamt)); 911bdd1243dSDimitry Andric }) 912bdd1243dSDimitry Andric .value_or(false); 913bdd1243dSDimitry Andric } 914bdd1243dSDimitry Andric bool operator()(SRLIW inst) { 915bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadU32(m_emu), 916bdd1243dSDimitry Andric [&](uint32_t rs1) { 917bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 918bdd1243dSDimitry Andric SextW(rs1 >> inst.shamt)); 919bdd1243dSDimitry Andric }) 920bdd1243dSDimitry Andric .value_or(false); 921bdd1243dSDimitry Andric } 922bdd1243dSDimitry Andric bool operator()(SRAIW inst) { 923bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadI32(m_emu), 924bdd1243dSDimitry Andric [&](int32_t rs1) { 925bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 926bdd1243dSDimitry Andric SextW(rs1 >> inst.shamt)); 927bdd1243dSDimitry Andric }) 928bdd1243dSDimitry Andric .value_or(false); 929bdd1243dSDimitry Andric } 930bdd1243dSDimitry Andric bool operator()(ADDW inst) { 931bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 932bdd1243dSDimitry Andric [&](auto &&tup) { 933bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 934bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 935bdd1243dSDimitry Andric SextW(uint32_t(rs1 + rs2))); 936bdd1243dSDimitry Andric }) 937bdd1243dSDimitry Andric .value_or(false); 938bdd1243dSDimitry Andric } 939bdd1243dSDimitry Andric bool operator()(SUBW inst) { 940bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 941bdd1243dSDimitry Andric [&](auto &&tup) { 942bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 943bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 944bdd1243dSDimitry Andric SextW(uint32_t(rs1 - rs2))); 945bdd1243dSDimitry Andric }) 946bdd1243dSDimitry Andric .value_or(false); 947bdd1243dSDimitry Andric } 948bdd1243dSDimitry Andric bool operator()(SLLW inst) { 949bdd1243dSDimitry Andric return transformOptional( 950bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)), 951bdd1243dSDimitry Andric [&](auto &&tup) { 952bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 953bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(rs1 << (rs2 & 0b11111))); 954bdd1243dSDimitry Andric }) 955bdd1243dSDimitry Andric .value_or(false); 956bdd1243dSDimitry Andric } 957bdd1243dSDimitry Andric bool operator()(SRLW inst) { 958bdd1243dSDimitry Andric return transformOptional( 959bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)), 960bdd1243dSDimitry Andric [&](auto &&tup) { 961bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 962bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111))); 963bdd1243dSDimitry Andric }) 964bdd1243dSDimitry Andric .value_or(false); 965bdd1243dSDimitry Andric } 966bdd1243dSDimitry Andric bool operator()(SRAW inst) { 967bdd1243dSDimitry Andric return transformOptional( 968bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.Read(m_emu)), 969bdd1243dSDimitry Andric [&](auto &&tup) { 970bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 971bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(rs1 >> (rs2 & 0b11111))); 972bdd1243dSDimitry Andric }) 973bdd1243dSDimitry Andric .value_or(false); 974bdd1243dSDimitry Andric } 975bdd1243dSDimitry Andric // RV32M & RV64M (Integer Multiplication and Division Extension) // 976bdd1243dSDimitry Andric bool operator()(MUL inst) { 977bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 978bdd1243dSDimitry Andric [&](auto &&tup) { 979bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 980bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1 * rs2); 981bdd1243dSDimitry Andric }) 982bdd1243dSDimitry Andric .value_or(false); 983bdd1243dSDimitry Andric } 984bdd1243dSDimitry Andric bool operator()(MULH inst) { 985bdd1243dSDimitry Andric return transformOptional( 986bdd1243dSDimitry Andric zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 987bdd1243dSDimitry Andric [&](auto &&tup) { 988bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 989bdd1243dSDimitry Andric // signed * signed 990bdd1243dSDimitry Andric auto mul = APInt(128, rs1, true) * APInt(128, rs2, true); 991bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 992bdd1243dSDimitry Andric mul.ashr(64).trunc(64).getZExtValue()); 993bdd1243dSDimitry Andric }) 994bdd1243dSDimitry Andric .value_or(false); 995bdd1243dSDimitry Andric } 996bdd1243dSDimitry Andric bool operator()(MULHSU inst) { 997bdd1243dSDimitry Andric return transformOptional( 998bdd1243dSDimitry Andric zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 999bdd1243dSDimitry Andric [&](auto &&tup) { 1000bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1001bdd1243dSDimitry Andric // signed * unsigned 1002bdd1243dSDimitry Andric auto mul = 1003bdd1243dSDimitry Andric APInt(128, rs1, true).zext(128) * APInt(128, rs2, false); 1004bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 1005bdd1243dSDimitry Andric mul.lshr(64).trunc(64).getZExtValue()); 1006bdd1243dSDimitry Andric }) 1007bdd1243dSDimitry Andric .value_or(false); 1008bdd1243dSDimitry Andric } 1009bdd1243dSDimitry Andric bool operator()(MULHU inst) { 1010bdd1243dSDimitry Andric return transformOptional( 1011bdd1243dSDimitry Andric zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 1012bdd1243dSDimitry Andric [&](auto &&tup) { 1013bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1014bdd1243dSDimitry Andric // unsigned * unsigned 1015bdd1243dSDimitry Andric auto mul = APInt(128, rs1, false) * APInt(128, rs2, false); 1016bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 1017bdd1243dSDimitry Andric mul.lshr(64).trunc(64).getZExtValue()); 1018bdd1243dSDimitry Andric }) 1019bdd1243dSDimitry Andric .value_or(false); 1020bdd1243dSDimitry Andric } 1021bdd1243dSDimitry Andric bool operator()(DIV inst) { 1022bdd1243dSDimitry Andric return transformOptional( 1023bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)), 1024bdd1243dSDimitry Andric [&](auto &&tup) { 1025bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1026bdd1243dSDimitry Andric 1027bdd1243dSDimitry Andric if (divisor == 0) 1028bdd1243dSDimitry Andric return inst.rd.Write(m_emu, UINT64_MAX); 1029bdd1243dSDimitry Andric 1030bdd1243dSDimitry Andric if (dividend == INT64_MIN && divisor == -1) 1031bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend); 1032bdd1243dSDimitry Andric 1033bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend / divisor); 1034bdd1243dSDimitry Andric }) 1035bdd1243dSDimitry Andric .value_or(false); 1036bdd1243dSDimitry Andric } 1037bdd1243dSDimitry Andric bool operator()(DIVU inst) { 1038bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 1039bdd1243dSDimitry Andric [&](auto &&tup) { 1040bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1041bdd1243dSDimitry Andric 1042bdd1243dSDimitry Andric if (divisor == 0) 1043bdd1243dSDimitry Andric return inst.rd.Write(m_emu, UINT64_MAX); 1044bdd1243dSDimitry Andric 1045bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend / divisor); 1046bdd1243dSDimitry Andric }) 1047bdd1243dSDimitry Andric .value_or(false); 1048bdd1243dSDimitry Andric } 1049bdd1243dSDimitry Andric bool operator()(REM inst) { 1050bdd1243dSDimitry Andric return transformOptional( 1051bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI64(m_emu), inst.rs2.ReadI64(m_emu)), 1052bdd1243dSDimitry Andric [&](auto &&tup) { 1053bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1054bdd1243dSDimitry Andric 1055bdd1243dSDimitry Andric if (divisor == 0) 1056bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend); 1057bdd1243dSDimitry Andric 1058bdd1243dSDimitry Andric if (dividend == INT64_MIN && divisor == -1) 1059bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 0); 1060bdd1243dSDimitry Andric 1061bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend % divisor); 1062bdd1243dSDimitry Andric }) 1063bdd1243dSDimitry Andric .value_or(false); 1064bdd1243dSDimitry Andric } 1065bdd1243dSDimitry Andric bool operator()(REMU inst) { 1066bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), inst.rs2.Read(m_emu)), 1067bdd1243dSDimitry Andric [&](auto &&tup) { 1068bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1069bdd1243dSDimitry Andric 1070bdd1243dSDimitry Andric if (divisor == 0) 1071bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend); 1072bdd1243dSDimitry Andric 1073bdd1243dSDimitry Andric return inst.rd.Write(m_emu, dividend % divisor); 1074bdd1243dSDimitry Andric }) 1075bdd1243dSDimitry Andric .value_or(false); 1076bdd1243dSDimitry Andric } 1077bdd1243dSDimitry Andric bool operator()(MULW inst) { 1078bdd1243dSDimitry Andric return transformOptional( 1079bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)), 1080bdd1243dSDimitry Andric [&](auto &&tup) { 1081bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1082bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(rs1 * rs2)); 1083bdd1243dSDimitry Andric }) 1084bdd1243dSDimitry Andric .value_or(false); 1085bdd1243dSDimitry Andric } 1086bdd1243dSDimitry Andric bool operator()(DIVW inst) { 1087bdd1243dSDimitry Andric return transformOptional( 1088bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)), 1089bdd1243dSDimitry Andric [&](auto &&tup) { 1090bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1091bdd1243dSDimitry Andric 1092bdd1243dSDimitry Andric if (divisor == 0) 1093bdd1243dSDimitry Andric return inst.rd.Write(m_emu, UINT64_MAX); 1094bdd1243dSDimitry Andric 1095bdd1243dSDimitry Andric if (dividend == INT32_MIN && divisor == -1) 1096bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend)); 1097bdd1243dSDimitry Andric 1098bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend / divisor)); 1099bdd1243dSDimitry Andric }) 1100bdd1243dSDimitry Andric .value_or(false); 1101bdd1243dSDimitry Andric } 1102bdd1243dSDimitry Andric bool operator()(DIVUW inst) { 1103bdd1243dSDimitry Andric return transformOptional( 1104bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)), 1105bdd1243dSDimitry Andric [&](auto &&tup) { 1106bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1107bdd1243dSDimitry Andric 1108bdd1243dSDimitry Andric if (divisor == 0) 1109bdd1243dSDimitry Andric return inst.rd.Write(m_emu, UINT64_MAX); 1110bdd1243dSDimitry Andric 1111bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend / divisor)); 1112bdd1243dSDimitry Andric }) 1113bdd1243dSDimitry Andric .value_or(false); 1114bdd1243dSDimitry Andric } 1115bdd1243dSDimitry Andric bool operator()(REMW inst) { 1116bdd1243dSDimitry Andric return transformOptional( 1117bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadI32(m_emu), inst.rs2.ReadI32(m_emu)), 1118bdd1243dSDimitry Andric [&](auto &&tup) { 1119bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1120bdd1243dSDimitry Andric 1121bdd1243dSDimitry Andric if (divisor == 0) 1122bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend)); 1123bdd1243dSDimitry Andric 1124bdd1243dSDimitry Andric if (dividend == INT32_MIN && divisor == -1) 1125bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 0); 1126bdd1243dSDimitry Andric 1127bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend % divisor)); 1128bdd1243dSDimitry Andric }) 1129bdd1243dSDimitry Andric .value_or(false); 1130bdd1243dSDimitry Andric } 1131bdd1243dSDimitry Andric bool operator()(REMUW inst) { 1132bdd1243dSDimitry Andric return transformOptional( 1133bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadU32(m_emu), inst.rs2.ReadU32(m_emu)), 1134bdd1243dSDimitry Andric [&](auto &&tup) { 1135bdd1243dSDimitry Andric auto [dividend, divisor] = tup; 1136bdd1243dSDimitry Andric 1137bdd1243dSDimitry Andric if (divisor == 0) 1138bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend)); 1139bdd1243dSDimitry Andric 1140bdd1243dSDimitry Andric return inst.rd.Write(m_emu, SextW(dividend % divisor)); 1141bdd1243dSDimitry Andric }) 1142bdd1243dSDimitry Andric .value_or(false); 1143bdd1243dSDimitry Andric } 1144bdd1243dSDimitry Andric // RV32A & RV64A (The standard atomic instruction extension) // 1145bdd1243dSDimitry Andric bool operator()(LR_W) { return AtomicSequence(m_emu); } 1146bdd1243dSDimitry Andric bool operator()(LR_D) { return AtomicSequence(m_emu); } 1147bdd1243dSDimitry Andric bool operator()(SC_W) { 1148bdd1243dSDimitry Andric llvm_unreachable("should be handled in AtomicSequence"); 1149bdd1243dSDimitry Andric } 1150bdd1243dSDimitry Andric bool operator()(SC_D) { 1151bdd1243dSDimitry Andric llvm_unreachable("should be handled in AtomicSequence"); 1152bdd1243dSDimitry Andric } 1153bdd1243dSDimitry Andric bool operator()(AMOSWAP_W inst) { 1154bdd1243dSDimitry Andric return AtomicSwap<AMOSWAP_W, uint32_t>(m_emu, inst, 4, SextW); 1155bdd1243dSDimitry Andric } 1156bdd1243dSDimitry Andric bool operator()(AMOADD_W inst) { 1157bdd1243dSDimitry Andric return AtomicADD<AMOADD_W, uint32_t>(m_emu, inst, 4, SextW); 1158bdd1243dSDimitry Andric } 1159bdd1243dSDimitry Andric bool operator()(AMOXOR_W inst) { 1160bdd1243dSDimitry Andric return AtomicBitOperate<AMOXOR_W, uint32_t>( 1161bdd1243dSDimitry Andric m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a ^ b; }); 1162bdd1243dSDimitry Andric } 1163bdd1243dSDimitry Andric bool operator()(AMOAND_W inst) { 1164bdd1243dSDimitry Andric return AtomicBitOperate<AMOAND_W, uint32_t>( 1165bdd1243dSDimitry Andric m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a & b; }); 1166bdd1243dSDimitry Andric } 1167bdd1243dSDimitry Andric bool operator()(AMOOR_W inst) { 1168bdd1243dSDimitry Andric return AtomicBitOperate<AMOOR_W, uint32_t>( 1169bdd1243dSDimitry Andric m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { return a | b; }); 1170bdd1243dSDimitry Andric } 1171bdd1243dSDimitry Andric bool operator()(AMOMIN_W inst) { 1172bdd1243dSDimitry Andric return AtomicCmp<AMOMIN_W, uint32_t>( 1173bdd1243dSDimitry Andric m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { 1174bdd1243dSDimitry Andric return uint32_t(std::min(int32_t(a), int32_t(b))); 1175bdd1243dSDimitry Andric }); 1176bdd1243dSDimitry Andric } 1177bdd1243dSDimitry Andric bool operator()(AMOMAX_W inst) { 1178bdd1243dSDimitry Andric return AtomicCmp<AMOMAX_W, uint32_t>( 1179bdd1243dSDimitry Andric m_emu, inst, 4, SextW, [](uint32_t a, uint32_t b) { 1180bdd1243dSDimitry Andric return uint32_t(std::max(int32_t(a), int32_t(b))); 1181bdd1243dSDimitry Andric }); 1182bdd1243dSDimitry Andric } 1183bdd1243dSDimitry Andric bool operator()(AMOMINU_W inst) { 1184bdd1243dSDimitry Andric return AtomicCmp<AMOMINU_W, uint32_t>( 1185bdd1243dSDimitry Andric m_emu, inst, 4, SextW, 1186bdd1243dSDimitry Andric [](uint32_t a, uint32_t b) { return std::min(a, b); }); 1187bdd1243dSDimitry Andric } 1188bdd1243dSDimitry Andric bool operator()(AMOMAXU_W inst) { 1189bdd1243dSDimitry Andric return AtomicCmp<AMOMAXU_W, uint32_t>( 1190bdd1243dSDimitry Andric m_emu, inst, 4, SextW, 1191bdd1243dSDimitry Andric [](uint32_t a, uint32_t b) { return std::max(a, b); }); 1192bdd1243dSDimitry Andric } 1193bdd1243dSDimitry Andric bool operator()(AMOSWAP_D inst) { 1194bdd1243dSDimitry Andric return AtomicSwap<AMOSWAP_D, uint64_t>(m_emu, inst, 8, ZextD); 1195bdd1243dSDimitry Andric } 1196bdd1243dSDimitry Andric bool operator()(AMOADD_D inst) { 1197bdd1243dSDimitry Andric return AtomicADD<AMOADD_D, uint64_t>(m_emu, inst, 8, ZextD); 1198bdd1243dSDimitry Andric } 1199bdd1243dSDimitry Andric bool operator()(AMOXOR_D inst) { 1200bdd1243dSDimitry Andric return AtomicBitOperate<AMOXOR_D, uint64_t>( 1201bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a ^ b; }); 1202bdd1243dSDimitry Andric } 1203bdd1243dSDimitry Andric bool operator()(AMOAND_D inst) { 1204bdd1243dSDimitry Andric return AtomicBitOperate<AMOAND_D, uint64_t>( 1205bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a & b; }); 1206bdd1243dSDimitry Andric } 1207bdd1243dSDimitry Andric bool operator()(AMOOR_D inst) { 1208bdd1243dSDimitry Andric return AtomicBitOperate<AMOOR_D, uint64_t>( 1209bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { return a | b; }); 1210bdd1243dSDimitry Andric } 1211bdd1243dSDimitry Andric bool operator()(AMOMIN_D inst) { 1212bdd1243dSDimitry Andric return AtomicCmp<AMOMIN_D, uint64_t>( 1213bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { 1214bdd1243dSDimitry Andric return uint64_t(std::min(int64_t(a), int64_t(b))); 1215bdd1243dSDimitry Andric }); 1216bdd1243dSDimitry Andric } 1217bdd1243dSDimitry Andric bool operator()(AMOMAX_D inst) { 1218bdd1243dSDimitry Andric return AtomicCmp<AMOMAX_D, uint64_t>( 1219bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, [](uint64_t a, uint64_t b) { 1220bdd1243dSDimitry Andric return uint64_t(std::max(int64_t(a), int64_t(b))); 1221bdd1243dSDimitry Andric }); 1222bdd1243dSDimitry Andric } 1223bdd1243dSDimitry Andric bool operator()(AMOMINU_D inst) { 1224bdd1243dSDimitry Andric return AtomicCmp<AMOMINU_D, uint64_t>( 1225bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, 1226bdd1243dSDimitry Andric [](uint64_t a, uint64_t b) { return std::min(a, b); }); 1227bdd1243dSDimitry Andric } 1228bdd1243dSDimitry Andric bool operator()(AMOMAXU_D inst) { 1229bdd1243dSDimitry Andric return AtomicCmp<AMOMAXU_D, uint64_t>( 1230bdd1243dSDimitry Andric m_emu, inst, 8, ZextD, 1231bdd1243dSDimitry Andric [](uint64_t a, uint64_t b) { return std::max(a, b); }); 1232bdd1243dSDimitry Andric } 1233bdd1243dSDimitry Andric template <typename T> 1234bdd1243dSDimitry Andric bool F_Load(T inst, const fltSemantics &(*semantics)(), 1235bdd1243dSDimitry Andric unsigned int numBits) { 1236bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 1237bdd1243dSDimitry Andric [&](auto &&rs1) { 1238bdd1243dSDimitry Andric uint64_t addr = rs1 + uint64_t(inst.imm); 1239bdd1243dSDimitry Andric uint64_t bits = *m_emu.ReadMem<uint64_t>(addr); 1240bdd1243dSDimitry Andric APFloat f(semantics(), APInt(numBits, bits)); 1241bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, f); 1242bdd1243dSDimitry Andric }) 1243bdd1243dSDimitry Andric .value_or(false); 1244bdd1243dSDimitry Andric } 1245bdd1243dSDimitry Andric bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); } 1246bdd1243dSDimitry Andric template <typename T> bool F_Store(T inst, bool isDouble) { 1247bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.Read(m_emu), 1248bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble)), 1249bdd1243dSDimitry Andric [&](auto &&tup) { 1250bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1251bdd1243dSDimitry Andric uint64_t addr = rs1 + uint64_t(inst.imm); 1252bdd1243dSDimitry Andric uint64_t bits = 1253bdd1243dSDimitry Andric rs2.bitcastToAPInt().getZExtValue(); 1254bdd1243dSDimitry Andric return m_emu.WriteMem<uint64_t>(addr, bits); 1255bdd1243dSDimitry Andric }) 1256bdd1243dSDimitry Andric .value_or(false); 1257bdd1243dSDimitry Andric } 1258bdd1243dSDimitry Andric bool operator()(FSW inst) { return F_Store(inst, false); } 1259bdd1243dSDimitry Andric std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2, 1260bdd1243dSDimitry Andric APFloat rs3) { 1261bdd1243dSDimitry Andric auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode()); 1262bdd1243dSDimitry Andric auto res = m_emu.SetAccruedExceptions(opStatus); 1263bdd1243dSDimitry Andric return {res, rs1}; 1264bdd1243dSDimitry Andric } 1265bdd1243dSDimitry Andric template <typename T> 1266bdd1243dSDimitry Andric bool FMA(T inst, bool isDouble, float rs2_sign, float rs3_sign) { 1267bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble), 1268bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble), 1269bdd1243dSDimitry Andric inst.rs3.ReadAPFloat(m_emu, isDouble)), 1270bdd1243dSDimitry Andric [&](auto &&tup) { 1271bdd1243dSDimitry Andric auto [rs1, rs2, rs3] = tup; 1272bdd1243dSDimitry Andric rs2.copySign(APFloat(rs2_sign)); 1273bdd1243dSDimitry Andric rs3.copySign(APFloat(rs3_sign)); 1274bdd1243dSDimitry Andric auto [res, f] = FusedMultiplyAdd(rs1, rs2, rs3); 1275bdd1243dSDimitry Andric return res && inst.rd.WriteAPFloat(m_emu, f); 1276bdd1243dSDimitry Andric }) 1277bdd1243dSDimitry Andric .value_or(false); 1278bdd1243dSDimitry Andric } 1279bdd1243dSDimitry Andric bool operator()(FMADD_S inst) { return FMA(inst, false, 1.0f, 1.0f); } 1280bdd1243dSDimitry Andric bool operator()(FMSUB_S inst) { return FMA(inst, false, 1.0f, -1.0f); } 1281bdd1243dSDimitry Andric bool operator()(FNMSUB_S inst) { return FMA(inst, false, -1.0f, 1.0f); } 1282bdd1243dSDimitry Andric bool operator()(FNMADD_S inst) { return FMA(inst, false, -1.0f, -1.0f); } 1283bdd1243dSDimitry Andric template <typename T> 1284bdd1243dSDimitry Andric bool F_Op(T inst, bool isDouble, 1285bdd1243dSDimitry Andric APFloat::opStatus (APFloat::*f)(const APFloat &RHS, 1286bdd1243dSDimitry Andric APFloat::roundingMode RM)) { 1287bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble), 1288bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble)), 1289bdd1243dSDimitry Andric [&](auto &&tup) { 1290bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1291bdd1243dSDimitry Andric auto res = 1292bdd1243dSDimitry Andric ((&rs1)->*f)(rs2, m_emu.GetRoundingMode()); 1293bdd1243dSDimitry Andric inst.rd.WriteAPFloat(m_emu, rs1); 1294bdd1243dSDimitry Andric return m_emu.SetAccruedExceptions(res); 1295bdd1243dSDimitry Andric }) 1296bdd1243dSDimitry Andric .value_or(false); 1297bdd1243dSDimitry Andric } 1298bdd1243dSDimitry Andric bool operator()(FADD_S inst) { return F_Op(inst, false, &APFloat::add); } 1299bdd1243dSDimitry Andric bool operator()(FSUB_S inst) { return F_Op(inst, false, &APFloat::subtract); } 1300bdd1243dSDimitry Andric bool operator()(FMUL_S inst) { return F_Op(inst, false, &APFloat::multiply); } 1301bdd1243dSDimitry Andric bool operator()(FDIV_S inst) { return F_Op(inst, false, &APFloat::divide); } 1302bdd1243dSDimitry Andric bool operator()(FSQRT_S inst) { 1303bdd1243dSDimitry Andric // TODO: APFloat doesn't have a sqrt function. 1304bdd1243dSDimitry Andric return false; 1305bdd1243dSDimitry Andric } 1306bdd1243dSDimitry Andric template <typename T> bool F_SignInj(T inst, bool isDouble, bool isNegate) { 1307bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble), 1308bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble)), 1309bdd1243dSDimitry Andric [&](auto &&tup) { 1310bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1311bdd1243dSDimitry Andric if (isNegate) 1312bdd1243dSDimitry Andric rs2.changeSign(); 1313bdd1243dSDimitry Andric rs1.copySign(rs2); 1314bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, rs1); 1315bdd1243dSDimitry Andric }) 1316bdd1243dSDimitry Andric .value_or(false); 1317bdd1243dSDimitry Andric } 1318bdd1243dSDimitry Andric bool operator()(FSGNJ_S inst) { return F_SignInj(inst, false, false); } 1319bdd1243dSDimitry Andric bool operator()(FSGNJN_S inst) { return F_SignInj(inst, false, true); } 1320bdd1243dSDimitry Andric template <typename T> bool F_SignInjXor(T inst, bool isDouble) { 1321bdd1243dSDimitry Andric return transformOptional(zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble), 1322bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble)), 1323bdd1243dSDimitry Andric [&](auto &&tup) { 1324bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1325bdd1243dSDimitry Andric // spec: the sign bit is the XOR of the sign bits 1326bdd1243dSDimitry Andric // of rs1 and rs2. if rs1 and rs2 have the same 1327bdd1243dSDimitry Andric // signs set rs1 to positive else set rs1 to 1328bdd1243dSDimitry Andric // negative 1329bdd1243dSDimitry Andric if (rs1.isNegative() == rs2.isNegative()) { 1330bdd1243dSDimitry Andric rs1.clearSign(); 1331bdd1243dSDimitry Andric } else { 1332bdd1243dSDimitry Andric rs1.clearSign(); 1333bdd1243dSDimitry Andric rs1.changeSign(); 1334bdd1243dSDimitry Andric } 1335bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, rs1); 1336bdd1243dSDimitry Andric }) 1337bdd1243dSDimitry Andric .value_or(false); 1338bdd1243dSDimitry Andric } 1339bdd1243dSDimitry Andric bool operator()(FSGNJX_S inst) { return F_SignInjXor(inst, false); } 1340bdd1243dSDimitry Andric template <typename T> 1341bdd1243dSDimitry Andric bool F_MAX_MIN(T inst, bool isDouble, 1342bdd1243dSDimitry Andric APFloat (*f)(const APFloat &A, const APFloat &B)) { 1343bdd1243dSDimitry Andric return transformOptional( 1344bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble), 1345bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble)), 1346bdd1243dSDimitry Andric [&](auto &&tup) { 1347bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1348bdd1243dSDimitry Andric // If both inputs are NaNs, the result is the canonical NaN. 1349bdd1243dSDimitry Andric // If only one operand is a NaN, the result is the non-NaN 1350bdd1243dSDimitry Andric // operand. Signaling NaN inputs set the invalid operation 1351bdd1243dSDimitry Andric // exception flag, even when the result is not NaN. 1352bdd1243dSDimitry Andric if (rs1.isNaN() || rs2.isNaN()) 1353bdd1243dSDimitry Andric m_emu.SetAccruedExceptions(APFloat::opInvalidOp); 1354bdd1243dSDimitry Andric if (rs1.isNaN() && rs2.isNaN()) { 1355bdd1243dSDimitry Andric auto canonicalNaN = APFloat::getQNaN(rs1.getSemantics()); 1356bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, canonicalNaN); 1357bdd1243dSDimitry Andric } 1358bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, f(rs1, rs2)); 1359bdd1243dSDimitry Andric }) 1360bdd1243dSDimitry Andric .value_or(false); 1361bdd1243dSDimitry Andric } 1362bdd1243dSDimitry Andric bool operator()(FMIN_S inst) { return F_MAX_MIN(inst, false, minnum); } 1363bdd1243dSDimitry Andric bool operator()(FMAX_S inst) { return F_MAX_MIN(inst, false, maxnum); } 1364bdd1243dSDimitry Andric bool operator()(FCVT_W_S inst) { 1365bdd1243dSDimitry Andric return FCVT_i2f<FCVT_W_S, int32_t, float>(inst, false, 1366bdd1243dSDimitry Andric &APFloat::convertToFloat); 1367bdd1243dSDimitry Andric } 1368bdd1243dSDimitry Andric bool operator()(FCVT_WU_S inst) { 1369bdd1243dSDimitry Andric return FCVT_i2f<FCVT_WU_S, uint32_t, float>(inst, false, 1370bdd1243dSDimitry Andric &APFloat::convertToFloat); 1371bdd1243dSDimitry Andric } 1372bdd1243dSDimitry Andric template <typename T> bool FMV_f2i(T inst, bool isDouble) { 1373bdd1243dSDimitry Andric return transformOptional( 1374bdd1243dSDimitry Andric inst.rs1.ReadAPFloat(m_emu, isDouble), 1375bdd1243dSDimitry Andric [&](auto &&rs1) { 1376bdd1243dSDimitry Andric if (rs1.isNaN()) { 1377bdd1243dSDimitry Andric if (isDouble) 1378bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 0x7ff8'0000'0000'0000); 1379bdd1243dSDimitry Andric else 1380bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 0x7fc0'0000); 1381bdd1243dSDimitry Andric } 1382bdd1243dSDimitry Andric auto bits = rs1.bitcastToAPInt().getZExtValue(); 1383bdd1243dSDimitry Andric if (isDouble) 1384bdd1243dSDimitry Andric return inst.rd.Write(m_emu, bits); 1385bdd1243dSDimitry Andric else 1386bdd1243dSDimitry Andric return inst.rd.Write(m_emu, uint64_t(bits & 0xffff'ffff)); 1387bdd1243dSDimitry Andric }) 1388bdd1243dSDimitry Andric .value_or(false); 1389bdd1243dSDimitry Andric } 1390bdd1243dSDimitry Andric bool operator()(FMV_X_W inst) { return FMV_f2i(inst, false); } 1391bdd1243dSDimitry Andric enum F_CMP { 1392bdd1243dSDimitry Andric FEQ, 1393bdd1243dSDimitry Andric FLT, 1394bdd1243dSDimitry Andric FLE, 1395bdd1243dSDimitry Andric }; 1396bdd1243dSDimitry Andric template <typename T> bool F_Compare(T inst, bool isDouble, F_CMP cmp) { 1397bdd1243dSDimitry Andric return transformOptional( 1398bdd1243dSDimitry Andric zipOpt(inst.rs1.ReadAPFloat(m_emu, isDouble), 1399bdd1243dSDimitry Andric inst.rs2.ReadAPFloat(m_emu, isDouble)), 1400bdd1243dSDimitry Andric [&](auto &&tup) { 1401bdd1243dSDimitry Andric auto [rs1, rs2] = tup; 1402bdd1243dSDimitry Andric if (rs1.isNaN() || rs2.isNaN()) { 1403bdd1243dSDimitry Andric if (cmp == FEQ) { 1404bdd1243dSDimitry Andric if (rs1.isSignaling() || rs2.isSignaling()) { 1405bdd1243dSDimitry Andric auto res = 1406bdd1243dSDimitry Andric m_emu.SetAccruedExceptions(APFloat::opInvalidOp); 1407bdd1243dSDimitry Andric return res && inst.rd.Write(m_emu, 0); 1408bdd1243dSDimitry Andric } 1409bdd1243dSDimitry Andric } 1410bdd1243dSDimitry Andric auto res = m_emu.SetAccruedExceptions(APFloat::opInvalidOp); 1411bdd1243dSDimitry Andric return res && inst.rd.Write(m_emu, 0); 1412bdd1243dSDimitry Andric } 1413bdd1243dSDimitry Andric switch (cmp) { 1414bdd1243dSDimitry Andric case FEQ: 1415bdd1243dSDimitry Andric return inst.rd.Write(m_emu, 1416bdd1243dSDimitry Andric rs1.compare(rs2) == APFloat::cmpEqual); 1417bdd1243dSDimitry Andric case FLT: 1418bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1.compare(rs2) == 1419bdd1243dSDimitry Andric APFloat::cmpLessThan); 1420bdd1243dSDimitry Andric case FLE: 1421bdd1243dSDimitry Andric return inst.rd.Write(m_emu, rs1.compare(rs2) != 1422bdd1243dSDimitry Andric APFloat::cmpGreaterThan); 1423bdd1243dSDimitry Andric } 1424bdd1243dSDimitry Andric llvm_unreachable("unsupported F_CMP"); 1425bdd1243dSDimitry Andric }) 1426bdd1243dSDimitry Andric .value_or(false); 1427bdd1243dSDimitry Andric } 1428bdd1243dSDimitry Andric 1429bdd1243dSDimitry Andric bool operator()(FEQ_S inst) { return F_Compare(inst, false, FEQ); } 1430bdd1243dSDimitry Andric bool operator()(FLT_S inst) { return F_Compare(inst, false, FLT); } 1431bdd1243dSDimitry Andric bool operator()(FLE_S inst) { return F_Compare(inst, false, FLE); } 1432bdd1243dSDimitry Andric template <typename T> bool FCLASS(T inst, bool isDouble) { 1433bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble), 1434bdd1243dSDimitry Andric [&](auto &&rs1) { 1435bdd1243dSDimitry Andric uint64_t result = 0; 1436bdd1243dSDimitry Andric if (rs1.isInfinity() && rs1.isNegative()) 1437bdd1243dSDimitry Andric result |= 1 << 0; 1438bdd1243dSDimitry Andric // neg normal 1439bdd1243dSDimitry Andric if (rs1.isNormal() && rs1.isNegative()) 1440bdd1243dSDimitry Andric result |= 1 << 1; 1441bdd1243dSDimitry Andric // neg subnormal 1442bdd1243dSDimitry Andric if (rs1.isDenormal() && rs1.isNegative()) 1443bdd1243dSDimitry Andric result |= 1 << 2; 1444bdd1243dSDimitry Andric if (rs1.isNegZero()) 1445bdd1243dSDimitry Andric result |= 1 << 3; 1446bdd1243dSDimitry Andric if (rs1.isPosZero()) 1447bdd1243dSDimitry Andric result |= 1 << 4; 1448bdd1243dSDimitry Andric // pos normal 1449bdd1243dSDimitry Andric if (rs1.isNormal() && !rs1.isNegative()) 1450bdd1243dSDimitry Andric result |= 1 << 5; 1451bdd1243dSDimitry Andric // pos subnormal 1452bdd1243dSDimitry Andric if (rs1.isDenormal() && !rs1.isNegative()) 1453bdd1243dSDimitry Andric result |= 1 << 6; 1454bdd1243dSDimitry Andric if (rs1.isInfinity() && !rs1.isNegative()) 1455bdd1243dSDimitry Andric result |= 1 << 7; 1456bdd1243dSDimitry Andric if (rs1.isNaN()) { 1457bdd1243dSDimitry Andric if (rs1.isSignaling()) 1458bdd1243dSDimitry Andric result |= 1 << 8; 1459bdd1243dSDimitry Andric else 1460bdd1243dSDimitry Andric result |= 1 << 9; 1461bdd1243dSDimitry Andric } 1462bdd1243dSDimitry Andric return inst.rd.Write(m_emu, result); 1463bdd1243dSDimitry Andric }) 1464bdd1243dSDimitry Andric .value_or(false); 1465bdd1243dSDimitry Andric } 1466bdd1243dSDimitry Andric bool operator()(FCLASS_S inst) { return FCLASS(inst, false); } 1467bdd1243dSDimitry Andric template <typename T, typename E> 1468bdd1243dSDimitry Andric bool FCVT_f2i(T inst, std::optional<E> (Rs::*f)(EmulateInstructionRISCV &emu), 1469bdd1243dSDimitry Andric const fltSemantics &semantics) { 1470bdd1243dSDimitry Andric return transformOptional(((&inst.rs1)->*f)(m_emu), 1471bdd1243dSDimitry Andric [&](auto &&rs1) { 1472bdd1243dSDimitry Andric APFloat apf(semantics, rs1); 1473bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, apf); 1474bdd1243dSDimitry Andric }) 1475bdd1243dSDimitry Andric .value_or(false); 1476bdd1243dSDimitry Andric } 1477bdd1243dSDimitry Andric bool operator()(FCVT_S_W inst) { 1478bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEsingle()); 1479bdd1243dSDimitry Andric } 1480bdd1243dSDimitry Andric bool operator()(FCVT_S_WU inst) { 1481bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEsingle()); 1482bdd1243dSDimitry Andric } 1483bdd1243dSDimitry Andric template <typename T, typename E> 1484bdd1243dSDimitry Andric bool FMV_i2f(T inst, unsigned int numBits, E (APInt::*f)() const) { 1485bdd1243dSDimitry Andric return transformOptional(inst.rs1.Read(m_emu), 1486bdd1243dSDimitry Andric [&](auto &&rs1) { 1487bdd1243dSDimitry Andric APInt apInt(numBits, rs1); 1488bdd1243dSDimitry Andric if (numBits == 32) // a.k.a. float 1489bdd1243dSDimitry Andric apInt = APInt(numBits, NanUnBoxing(rs1)); 1490bdd1243dSDimitry Andric APFloat apf((&apInt->*f)()); 1491bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, apf); 1492bdd1243dSDimitry Andric }) 1493bdd1243dSDimitry Andric .value_or(false); 1494bdd1243dSDimitry Andric } 1495bdd1243dSDimitry Andric bool operator()(FMV_W_X inst) { 1496bdd1243dSDimitry Andric return FMV_i2f(inst, 32, &APInt::bitsToFloat); 1497bdd1243dSDimitry Andric } 1498bdd1243dSDimitry Andric template <typename I, typename E, typename T> 1499bdd1243dSDimitry Andric bool FCVT_i2f(I inst, bool isDouble, T (APFloat::*f)() const) { 1500bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadAPFloat(m_emu, isDouble), 1501bdd1243dSDimitry Andric [&](auto &&rs1) { 1502bdd1243dSDimitry Andric E res = E((&rs1->*f)()); 1503bdd1243dSDimitry Andric return inst.rd.Write(m_emu, uint64_t(res)); 1504bdd1243dSDimitry Andric }) 1505bdd1243dSDimitry Andric .value_or(false); 1506bdd1243dSDimitry Andric } 1507bdd1243dSDimitry Andric bool operator()(FCVT_L_S inst) { 1508bdd1243dSDimitry Andric return FCVT_i2f<FCVT_L_S, int64_t, float>(inst, false, 1509bdd1243dSDimitry Andric &APFloat::convertToFloat); 1510bdd1243dSDimitry Andric } 1511bdd1243dSDimitry Andric bool operator()(FCVT_LU_S inst) { 1512bdd1243dSDimitry Andric return FCVT_i2f<FCVT_LU_S, uint64_t, float>(inst, false, 1513bdd1243dSDimitry Andric &APFloat::convertToFloat); 1514bdd1243dSDimitry Andric } 1515bdd1243dSDimitry Andric bool operator()(FCVT_S_L inst) { 1516bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEsingle()); 1517bdd1243dSDimitry Andric } 1518bdd1243dSDimitry Andric bool operator()(FCVT_S_LU inst) { 1519bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle()); 1520bdd1243dSDimitry Andric } 1521bdd1243dSDimitry Andric bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); } 1522bdd1243dSDimitry Andric bool operator()(FSD inst) { return F_Store(inst, true); } 1523bdd1243dSDimitry Andric bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); } 1524bdd1243dSDimitry Andric bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); } 1525bdd1243dSDimitry Andric bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); } 1526bdd1243dSDimitry Andric bool operator()(FNMADD_D inst) { return FMA(inst, true, -1.0f, -1.0f); } 1527bdd1243dSDimitry Andric bool operator()(FADD_D inst) { return F_Op(inst, true, &APFloat::add); } 1528bdd1243dSDimitry Andric bool operator()(FSUB_D inst) { return F_Op(inst, true, &APFloat::subtract); } 1529bdd1243dSDimitry Andric bool operator()(FMUL_D inst) { return F_Op(inst, true, &APFloat::multiply); } 1530bdd1243dSDimitry Andric bool operator()(FDIV_D inst) { return F_Op(inst, true, &APFloat::divide); } 1531bdd1243dSDimitry Andric bool operator()(FSQRT_D inst) { 1532bdd1243dSDimitry Andric // TODO: APFloat doesn't have a sqrt function. 1533bdd1243dSDimitry Andric return false; 1534bdd1243dSDimitry Andric } 1535bdd1243dSDimitry Andric bool operator()(FSGNJ_D inst) { return F_SignInj(inst, true, false); } 1536bdd1243dSDimitry Andric bool operator()(FSGNJN_D inst) { return F_SignInj(inst, true, true); } 1537bdd1243dSDimitry Andric bool operator()(FSGNJX_D inst) { return F_SignInjXor(inst, true); } 1538bdd1243dSDimitry Andric bool operator()(FMIN_D inst) { return F_MAX_MIN(inst, true, minnum); } 1539bdd1243dSDimitry Andric bool operator()(FMAX_D inst) { return F_MAX_MIN(inst, true, maxnum); } 1540bdd1243dSDimitry Andric bool operator()(FCVT_S_D inst) { 1541bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadAPFloat(m_emu, true), 1542bdd1243dSDimitry Andric [&](auto &&rs1) { 1543bdd1243dSDimitry Andric double d = rs1.convertToDouble(); 1544bdd1243dSDimitry Andric APFloat apf((float(d))); 1545bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, apf); 1546bdd1243dSDimitry Andric }) 1547bdd1243dSDimitry Andric .value_or(false); 1548bdd1243dSDimitry Andric } 1549bdd1243dSDimitry Andric bool operator()(FCVT_D_S inst) { 1550bdd1243dSDimitry Andric return transformOptional(inst.rs1.ReadAPFloat(m_emu, false), 1551bdd1243dSDimitry Andric [&](auto &&rs1) { 1552bdd1243dSDimitry Andric float f = rs1.convertToFloat(); 1553bdd1243dSDimitry Andric APFloat apf((double(f))); 1554bdd1243dSDimitry Andric return inst.rd.WriteAPFloat(m_emu, apf); 1555bdd1243dSDimitry Andric }) 1556bdd1243dSDimitry Andric .value_or(false); 1557bdd1243dSDimitry Andric } 1558bdd1243dSDimitry Andric bool operator()(FEQ_D inst) { return F_Compare(inst, true, FEQ); } 1559bdd1243dSDimitry Andric bool operator()(FLT_D inst) { return F_Compare(inst, true, FLT); } 1560bdd1243dSDimitry Andric bool operator()(FLE_D inst) { return F_Compare(inst, true, FLE); } 1561bdd1243dSDimitry Andric bool operator()(FCLASS_D inst) { return FCLASS(inst, true); } 1562bdd1243dSDimitry Andric bool operator()(FCVT_W_D inst) { 1563bdd1243dSDimitry Andric return FCVT_i2f<FCVT_W_D, int32_t, double>(inst, true, 1564bdd1243dSDimitry Andric &APFloat::convertToDouble); 1565bdd1243dSDimitry Andric } 1566bdd1243dSDimitry Andric bool operator()(FCVT_WU_D inst) { 1567bdd1243dSDimitry Andric return FCVT_i2f<FCVT_WU_D, uint32_t, double>(inst, true, 1568bdd1243dSDimitry Andric &APFloat::convertToDouble); 1569bdd1243dSDimitry Andric } 1570bdd1243dSDimitry Andric bool operator()(FCVT_D_W inst) { 1571bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::ReadI32, APFloat::IEEEdouble()); 1572bdd1243dSDimitry Andric } 1573bdd1243dSDimitry Andric bool operator()(FCVT_D_WU inst) { 1574bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::ReadU32, APFloat::IEEEdouble()); 1575bdd1243dSDimitry Andric } 1576bdd1243dSDimitry Andric bool operator()(FCVT_L_D inst) { 1577bdd1243dSDimitry Andric return FCVT_i2f<FCVT_L_D, int64_t, double>(inst, true, 1578bdd1243dSDimitry Andric &APFloat::convertToDouble); 1579bdd1243dSDimitry Andric } 1580bdd1243dSDimitry Andric bool operator()(FCVT_LU_D inst) { 1581bdd1243dSDimitry Andric return FCVT_i2f<FCVT_LU_D, uint64_t, double>(inst, true, 1582bdd1243dSDimitry Andric &APFloat::convertToDouble); 1583bdd1243dSDimitry Andric } 1584bdd1243dSDimitry Andric bool operator()(FMV_X_D inst) { return FMV_f2i(inst, true); } 1585bdd1243dSDimitry Andric bool operator()(FCVT_D_L inst) { 1586bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::ReadI64, APFloat::IEEEdouble()); 1587bdd1243dSDimitry Andric } 1588bdd1243dSDimitry Andric bool operator()(FCVT_D_LU inst) { 1589bdd1243dSDimitry Andric return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEdouble()); 1590bdd1243dSDimitry Andric } 1591bdd1243dSDimitry Andric bool operator()(FMV_D_X inst) { 1592bdd1243dSDimitry Andric return FMV_i2f(inst, 64, &APInt::bitsToDouble); 1593bdd1243dSDimitry Andric } 1594bdd1243dSDimitry Andric bool operator()(INVALID inst) { return false; } 1595bdd1243dSDimitry Andric bool operator()(RESERVED inst) { return false; } 1596bdd1243dSDimitry Andric bool operator()(EBREAK inst) { return false; } 1597bdd1243dSDimitry Andric bool operator()(HINT inst) { return true; } 1598bdd1243dSDimitry Andric bool operator()(NOP inst) { return true; } 1599bdd1243dSDimitry Andric }; 1600bdd1243dSDimitry Andric 1601bdd1243dSDimitry Andric bool EmulateInstructionRISCV::Execute(DecodeResult inst, bool ignore_cond) { 1602bdd1243dSDimitry Andric return std::visit(Executor(*this, ignore_cond, inst.is_rvc), inst.decoded); 1603bdd1243dSDimitry Andric } 1604bdd1243dSDimitry Andric 1605bdd1243dSDimitry Andric bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) { 1606bdd1243dSDimitry Andric bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC; 1607bdd1243dSDimitry Andric bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions; 1608bdd1243dSDimitry Andric 1609bdd1243dSDimitry Andric if (!increase_pc) 1610bdd1243dSDimitry Andric return Execute(m_decoded, ignore_cond); 1611bdd1243dSDimitry Andric 1612bdd1243dSDimitry Andric auto old_pc = ReadPC(); 1613bdd1243dSDimitry Andric if (!old_pc) 1614bdd1243dSDimitry Andric return false; 1615bdd1243dSDimitry Andric 1616bdd1243dSDimitry Andric bool success = Execute(m_decoded, ignore_cond); 1617bdd1243dSDimitry Andric if (!success) 1618bdd1243dSDimitry Andric return false; 1619bdd1243dSDimitry Andric 1620bdd1243dSDimitry Andric auto new_pc = ReadPC(); 1621bdd1243dSDimitry Andric if (!new_pc) 1622bdd1243dSDimitry Andric return false; 1623bdd1243dSDimitry Andric 1624bdd1243dSDimitry Andric // If the pc is not updated during execution, we do it here. 1625bdd1243dSDimitry Andric return new_pc != old_pc || 1626bdd1243dSDimitry Andric WritePC(*old_pc + Executor::size(m_decoded.is_rvc)); 1627bdd1243dSDimitry Andric } 1628bdd1243dSDimitry Andric 1629bdd1243dSDimitry Andric std::optional<DecodeResult> 1630bdd1243dSDimitry Andric EmulateInstructionRISCV::ReadInstructionAt(addr_t addr) { 1631bdd1243dSDimitry Andric return transformOptional(ReadMem<uint32_t>(addr), 1632bdd1243dSDimitry Andric [&](uint32_t inst) { return Decode(inst); }) 1633bdd1243dSDimitry Andric .value_or(std::nullopt); 1634bdd1243dSDimitry Andric } 1635bdd1243dSDimitry Andric 1636bdd1243dSDimitry Andric bool EmulateInstructionRISCV::ReadInstruction() { 1637bdd1243dSDimitry Andric auto addr = ReadPC(); 1638bdd1243dSDimitry Andric m_addr = addr.value_or(LLDB_INVALID_ADDRESS); 1639bdd1243dSDimitry Andric if (!addr) 1640bdd1243dSDimitry Andric return false; 1641bdd1243dSDimitry Andric auto inst = ReadInstructionAt(*addr); 1642bdd1243dSDimitry Andric if (!inst) 1643bdd1243dSDimitry Andric return false; 1644bdd1243dSDimitry Andric m_decoded = *inst; 1645bdd1243dSDimitry Andric if (inst->is_rvc) 1646bdd1243dSDimitry Andric m_opcode.SetOpcode16(inst->inst, GetByteOrder()); 1647bdd1243dSDimitry Andric else 1648bdd1243dSDimitry Andric m_opcode.SetOpcode32(inst->inst, GetByteOrder()); 1649bdd1243dSDimitry Andric return true; 1650bdd1243dSDimitry Andric } 1651bdd1243dSDimitry Andric 1652bdd1243dSDimitry Andric std::optional<addr_t> EmulateInstructionRISCV::ReadPC() { 1653bdd1243dSDimitry Andric bool success = false; 1654bdd1243dSDimitry Andric auto addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 1655bdd1243dSDimitry Andric LLDB_INVALID_ADDRESS, &success); 1656bdd1243dSDimitry Andric return success ? std::optional<addr_t>(addr) : std::nullopt; 1657bdd1243dSDimitry Andric } 1658bdd1243dSDimitry Andric 1659bdd1243dSDimitry Andric bool EmulateInstructionRISCV::WritePC(addr_t pc) { 1660bdd1243dSDimitry Andric EmulateInstruction::Context ctx; 1661bdd1243dSDimitry Andric ctx.type = eContextAdvancePC; 1662bdd1243dSDimitry Andric ctx.SetNoArgs(); 1663bdd1243dSDimitry Andric return WriteRegisterUnsigned(ctx, eRegisterKindGeneric, 1664bdd1243dSDimitry Andric LLDB_REGNUM_GENERIC_PC, pc); 1665bdd1243dSDimitry Andric } 1666bdd1243dSDimitry Andric 1667bdd1243dSDimitry Andric RoundingMode EmulateInstructionRISCV::GetRoundingMode() { 1668bdd1243dSDimitry Andric bool success = false; 1669bdd1243dSDimitry Andric auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv, 1670bdd1243dSDimitry Andric LLDB_INVALID_ADDRESS, &success); 1671bdd1243dSDimitry Andric if (!success) 1672bdd1243dSDimitry Andric return RoundingMode::Invalid; 1673bdd1243dSDimitry Andric auto frm = (fcsr >> 5) & 0x7; 1674bdd1243dSDimitry Andric switch (frm) { 1675bdd1243dSDimitry Andric case 0b000: 1676bdd1243dSDimitry Andric return RoundingMode::NearestTiesToEven; 1677bdd1243dSDimitry Andric case 0b001: 1678bdd1243dSDimitry Andric return RoundingMode::TowardZero; 1679bdd1243dSDimitry Andric case 0b010: 1680bdd1243dSDimitry Andric return RoundingMode::TowardNegative; 1681bdd1243dSDimitry Andric case 0b011: 1682bdd1243dSDimitry Andric return RoundingMode::TowardPositive; 1683bdd1243dSDimitry Andric case 0b111: 1684bdd1243dSDimitry Andric return RoundingMode::Dynamic; 1685bdd1243dSDimitry Andric default: 1686bdd1243dSDimitry Andric // Reserved for future use. 1687bdd1243dSDimitry Andric return RoundingMode::Invalid; 1688bdd1243dSDimitry Andric } 1689bdd1243dSDimitry Andric } 1690bdd1243dSDimitry Andric 1691bdd1243dSDimitry Andric bool EmulateInstructionRISCV::SetAccruedExceptions( 1692bdd1243dSDimitry Andric APFloatBase::opStatus opStatus) { 1693bdd1243dSDimitry Andric bool success = false; 1694bdd1243dSDimitry Andric auto fcsr = ReadRegisterUnsigned(eRegisterKindLLDB, fpr_fcsr_riscv, 1695bdd1243dSDimitry Andric LLDB_INVALID_ADDRESS, &success); 1696bdd1243dSDimitry Andric if (!success) 1697bdd1243dSDimitry Andric return false; 1698bdd1243dSDimitry Andric switch (opStatus) { 1699bdd1243dSDimitry Andric case APFloatBase::opInvalidOp: 1700bdd1243dSDimitry Andric fcsr |= 1 << 4; 1701bdd1243dSDimitry Andric break; 1702bdd1243dSDimitry Andric case APFloatBase::opDivByZero: 1703bdd1243dSDimitry Andric fcsr |= 1 << 3; 1704bdd1243dSDimitry Andric break; 1705bdd1243dSDimitry Andric case APFloatBase::opOverflow: 1706bdd1243dSDimitry Andric fcsr |= 1 << 2; 1707bdd1243dSDimitry Andric break; 1708bdd1243dSDimitry Andric case APFloatBase::opUnderflow: 1709bdd1243dSDimitry Andric fcsr |= 1 << 1; 1710bdd1243dSDimitry Andric break; 1711bdd1243dSDimitry Andric case APFloatBase::opInexact: 1712bdd1243dSDimitry Andric fcsr |= 1 << 0; 1713bdd1243dSDimitry Andric break; 1714bdd1243dSDimitry Andric case APFloatBase::opOK: 1715bdd1243dSDimitry Andric break; 1716bdd1243dSDimitry Andric } 1717bdd1243dSDimitry Andric EmulateInstruction::Context ctx; 1718bdd1243dSDimitry Andric ctx.type = eContextRegisterStore; 1719bdd1243dSDimitry Andric ctx.SetNoArgs(); 1720bdd1243dSDimitry Andric return WriteRegisterUnsigned(ctx, eRegisterKindLLDB, fpr_fcsr_riscv, fcsr); 1721bdd1243dSDimitry Andric } 1722bdd1243dSDimitry Andric 1723bdd1243dSDimitry Andric std::optional<RegisterInfo> 1724bdd1243dSDimitry Andric EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind, 1725bdd1243dSDimitry Andric uint32_t reg_index) { 1726bdd1243dSDimitry Andric if (reg_kind == eRegisterKindGeneric) { 1727bdd1243dSDimitry Andric switch (reg_index) { 1728bdd1243dSDimitry Andric case LLDB_REGNUM_GENERIC_PC: 1729bdd1243dSDimitry Andric reg_kind = eRegisterKindLLDB; 1730bdd1243dSDimitry Andric reg_index = gpr_pc_riscv; 1731bdd1243dSDimitry Andric break; 1732bdd1243dSDimitry Andric case LLDB_REGNUM_GENERIC_SP: 1733bdd1243dSDimitry Andric reg_kind = eRegisterKindLLDB; 1734bdd1243dSDimitry Andric reg_index = gpr_sp_riscv; 1735bdd1243dSDimitry Andric break; 1736bdd1243dSDimitry Andric case LLDB_REGNUM_GENERIC_FP: 1737bdd1243dSDimitry Andric reg_kind = eRegisterKindLLDB; 1738bdd1243dSDimitry Andric reg_index = gpr_fp_riscv; 1739bdd1243dSDimitry Andric break; 1740bdd1243dSDimitry Andric case LLDB_REGNUM_GENERIC_RA: 1741bdd1243dSDimitry Andric reg_kind = eRegisterKindLLDB; 1742bdd1243dSDimitry Andric reg_index = gpr_ra_riscv; 1743bdd1243dSDimitry Andric break; 1744bdd1243dSDimitry Andric // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are 1745bdd1243dSDimitry Andric // supported. 1746bdd1243dSDimitry Andric default: 1747bdd1243dSDimitry Andric llvm_unreachable("unsupported register"); 1748bdd1243dSDimitry Andric } 1749bdd1243dSDimitry Andric } 1750bdd1243dSDimitry Andric 1751bdd1243dSDimitry Andric const RegisterInfo *array = 1752bdd1243dSDimitry Andric RegisterInfoPOSIX_riscv64::GetRegisterInfoPtr(m_arch); 1753bdd1243dSDimitry Andric const uint32_t length = 1754bdd1243dSDimitry Andric RegisterInfoPOSIX_riscv64::GetRegisterInfoCount(m_arch); 1755bdd1243dSDimitry Andric 1756bdd1243dSDimitry Andric if (reg_index >= length || reg_kind != eRegisterKindLLDB) 1757bdd1243dSDimitry Andric return {}; 1758bdd1243dSDimitry Andric 1759bdd1243dSDimitry Andric return array[reg_index]; 1760bdd1243dSDimitry Andric } 1761bdd1243dSDimitry Andric 1762bdd1243dSDimitry Andric bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) { 1763bdd1243dSDimitry Andric return SupportsThisArch(arch); 1764bdd1243dSDimitry Andric } 1765bdd1243dSDimitry Andric 176606c3fb27SDimitry Andric bool EmulateInstructionRISCV::TestEmulation(Stream &out_stream, ArchSpec &arch, 1767bdd1243dSDimitry Andric OptionValueDictionary *test_data) { 1768bdd1243dSDimitry Andric return false; 1769bdd1243dSDimitry Andric } 1770bdd1243dSDimitry Andric 1771bdd1243dSDimitry Andric void EmulateInstructionRISCV::Initialize() { 1772bdd1243dSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 1773bdd1243dSDimitry Andric GetPluginDescriptionStatic(), CreateInstance); 1774bdd1243dSDimitry Andric } 1775bdd1243dSDimitry Andric 1776bdd1243dSDimitry Andric void EmulateInstructionRISCV::Terminate() { 1777bdd1243dSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 1778bdd1243dSDimitry Andric } 1779bdd1243dSDimitry Andric 1780bdd1243dSDimitry Andric lldb_private::EmulateInstruction * 1781bdd1243dSDimitry Andric EmulateInstructionRISCV::CreateInstance(const ArchSpec &arch, 1782bdd1243dSDimitry Andric InstructionType inst_type) { 1783bdd1243dSDimitry Andric if (EmulateInstructionRISCV::SupportsThisInstructionType(inst_type) && 1784bdd1243dSDimitry Andric SupportsThisArch(arch)) { 1785bdd1243dSDimitry Andric return new EmulateInstructionRISCV(arch); 1786bdd1243dSDimitry Andric } 1787bdd1243dSDimitry Andric 1788bdd1243dSDimitry Andric return nullptr; 1789bdd1243dSDimitry Andric } 1790bdd1243dSDimitry Andric 1791bdd1243dSDimitry Andric bool EmulateInstructionRISCV::SupportsThisArch(const ArchSpec &arch) { 1792bdd1243dSDimitry Andric return arch.GetTriple().isRISCV(); 1793bdd1243dSDimitry Andric } 1794bdd1243dSDimitry Andric 1795bdd1243dSDimitry Andric } // namespace lldb_private 1796