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