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