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

source code of lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp