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