[Lldb-commits] [lldb] ff7b876 - [LLDB][RISCV] Add more instruction decode and execute for EmulateInstructionRISCV
via lldb-commits
lldb-commits at lists.llvm.org
Thu Sep 1 19:17:23 PDT 2022
Author: Emmmer
Date: 2022-09-02T10:17:09+08:00
New Revision: ff7b876aa75d1d4df581ada78befb707dfdbb129
URL: https://github.com/llvm/llvm-project/commit/ff7b876aa75d1d4df581ada78befb707dfdbb129
DIFF: https://github.com/llvm/llvm-project/commit/ff7b876aa75d1d4df581ada78befb707dfdbb129.diff
LOG: [LLDB][RISCV] Add more instruction decode and execute for EmulateInstructionRISCV
Add:
- most of instructions from RVI base instructions set.
- some instruction decode tests from objdump.
Further work:
- implement riscv imac extension.
Reviewed By: DavidSpickett
Differential Revision: https://reviews.llvm.org/D132789
Added:
Modified:
lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
index 10aefc6d9dc08..4ca017dd98bbe 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -32,12 +32,6 @@ LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV)
namespace lldb_private {
-// Masks for detecting instructions types. According to riscv-spec Chap 26.
-constexpr uint32_t I_MASK = 0b111000001111111;
-constexpr uint32_t J_MASK = 0b000000001111111;
-// no funct3 in the b-mask because the logic executing B<CMP> is quite similar.
-constexpr uint32_t B_MASK = 0b000000001111111;
-
// The funct3 is the type of compare in B<CMP> instructions.
// funct3 means "3-bits function selector", which RISC-V ISA uses as minor
// opcode. It reuses the major opcode encoding space.
@@ -48,13 +42,26 @@ constexpr uint32_t BGE = 0b101;
constexpr uint32_t BLTU = 0b110;
constexpr uint32_t BGEU = 0b111;
-constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; }
-constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; }
-constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; }
+constexpr uint32_t DecodeSHAMT5(uint32_t inst) { return DecodeRS2(inst); }
+constexpr uint32_t DecodeSHAMT7(uint32_t inst) {
+ return (inst & 0x7F00000) >> 20;
+}
constexpr uint32_t DecodeFunct3(uint32_t inst) { return (inst & 0x7000) >> 12; }
+// used in decoder
constexpr int32_t SignExt(uint32_t imm) { return int32_t(imm); }
+// used in executor
+template <typename T>
+constexpr std::enable_if_t<sizeof(T) <= 4, uint64_t> SextW(T value) {
+ return uint64_t(int64_t(int32_t(value)));
+}
+
+// used in executor
+template <typename T> constexpr uint64_t ZextD(T value) {
+ return uint64_t(value);
+}
+
constexpr uint32_t DecodeJImm(uint32_t inst) {
return (uint64_t(int64_t(int32_t(inst & 0x80000000)) >> 11)) // imm[20]
| (inst & 0xff000) // imm[19:12]
@@ -73,6 +80,15 @@ constexpr uint32_t DecodeBImm(uint32_t inst) {
| ((inst >> 7) & 0x1e); // imm[4:1]
}
+constexpr uint32_t DecodeSImm(uint32_t inst) {
+ return (uint64_t(int64_t(int32_t(inst & 0xFE00000)) >> 20)) // imm[11:5]
+ | ((inst & 0xF80) >> 7); // imm[4:0]
+}
+
+constexpr uint32_t DecodeUImm(uint32_t inst) {
+ return SextW(inst & 0xFFFFF000); // imm[31:12]
+}
+
static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {
if (reg_encode == 0)
return gpr_x0_riscv;
@@ -81,43 +97,43 @@ static uint32_t GPREncodingToLLDB(uint32_t reg_encode) {
return LLDB_INVALID_REGNUM;
}
-static bool ReadRegister(EmulateInstructionRISCV *emulator, uint32_t reg_encode,
+static bool ReadRegister(EmulateInstructionRISCV &emulator, uint32_t reg_encode,
RegisterValue &value) {
uint32_t lldb_reg = GPREncodingToLLDB(reg_encode);
- return emulator->ReadRegister(eRegisterKindLLDB, lldb_reg, value);
+ return emulator.ReadRegister(eRegisterKindLLDB, lldb_reg, value);
}
-static bool WriteRegister(EmulateInstructionRISCV *emulator,
+static bool WriteRegister(EmulateInstructionRISCV &emulator,
uint32_t reg_encode, const RegisterValue &value) {
uint32_t lldb_reg = GPREncodingToLLDB(reg_encode);
EmulateInstruction::Context ctx;
ctx.type = EmulateInstruction::eContextRegisterStore;
ctx.SetNoArgs();
- return emulator->WriteRegister(ctx, eRegisterKindLLDB, lldb_reg, value);
+ return emulator.WriteRegister(ctx, eRegisterKindLLDB, lldb_reg, value);
}
-static bool ExecJAL(EmulateInstructionRISCV *emulator, uint32_t inst, bool) {
+static bool ExecJAL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
bool success = false;
int64_t offset = SignExt(DecodeJImm(inst));
- int64_t pc = emulator->ReadPC(&success);
- return success && emulator->WritePC(pc + offset) &&
+ int64_t pc = emulator.ReadPC(&success);
+ return success && emulator.WritePC(pc + offset) &&
WriteRegister(emulator, DecodeRD(inst),
RegisterValue(uint64_t(pc + 4)));
}
-static bool ExecJALR(EmulateInstructionRISCV *emulator, uint32_t inst, bool) {
+static bool ExecJALR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
int64_t offset = SignExt(DecodeIImm(inst));
RegisterValue value;
if (!ReadRegister(emulator, DecodeRS1(inst), value))
return false;
bool success = false;
- int64_t pc = emulator->ReadPC(&success);
+ int64_t pc = emulator.ReadPC(&success);
int64_t rs1 = int64_t(value.GetAsUInt64());
// JALR clears the bottom bit. According to riscv-spec:
// "The JALR instruction now clears the lowest bit of the calculated target
// address, to simplify hardware and to allow auxiliary information to be
// stored in function pointers."
- return emulator->WritePC((rs1 + offset) & ~1) &&
+ return emulator.WritePC((rs1 + offset) & ~1) &&
WriteRegister(emulator, DecodeRD(inst),
RegisterValue(uint64_t(pc + 4)));
}
@@ -141,17 +157,17 @@ static bool CompareB(uint64_t rs1, uint64_t rs2, uint32_t funct3) {
}
}
-static bool ExecB(EmulateInstructionRISCV *emulator, uint32_t inst,
+static bool ExecB(EmulateInstructionRISCV &emulator, uint32_t inst,
bool ignore_cond) {
bool success = false;
- uint64_t pc = emulator->ReadPC(&success);
+ uint64_t pc = emulator.ReadPC(&success);
if (!success)
return false;
uint64_t offset = SignExt(DecodeBImm(inst));
uint64_t target = pc + offset;
if (ignore_cond)
- return emulator->WritePC(target);
+ return emulator.WritePC(target);
RegisterValue value1;
RegisterValue value2;
@@ -161,43 +177,563 @@ static bool ExecB(EmulateInstructionRISCV *emulator, uint32_t inst,
uint32_t funct3 = DecodeFunct3(inst);
if (CompareB(value1.GetAsUInt64(), value2.GetAsUInt64(), funct3))
- return emulator->WritePC(target);
+ return emulator.WritePC(target);
return true;
}
-struct InstrPattern {
- const char *name;
- /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.)
- uint32_t type_mask;
- /// Characteristic value after bitwise-and with type_mask.
- uint32_t eigen;
- bool (*exec)(EmulateInstructionRISCV *emulator, uint32_t inst,
- bool ignore_cond);
-};
+static bool ExecLUI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ uint32_t imm = DecodeUImm(inst);
+ RegisterValue value;
+ value.SetUInt64(SignExt(imm));
+ return WriteRegister(emulator, DecodeRD(inst), value);
+}
+
+static bool ExecAUIPC(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ uint32_t imm = DecodeUImm(inst);
+ RegisterValue value;
+ bool success = false;
+ value.SetUInt64(SignExt(imm) + emulator.ReadPC(&success));
+ return success && WriteRegister(emulator, DecodeRD(inst), value);
+}
+
+template <typename T>
+static std::enable_if_t<std::is_integral_v<T>, T>
+ReadMem(EmulateInstructionRISCV &emulator, uint64_t addr, bool *success) {
+
+ EmulateInstructionRISCV::Context ctx;
+ ctx.type = EmulateInstruction::eContextRegisterLoad;
+ ctx.SetNoArgs();
+ return T(emulator.ReadMemoryUnsigned(ctx, addr, sizeof(T), T(), success));
+}
+
+template <typename T>
+static bool WriteMem(EmulateInstructionRISCV &emulator, uint64_t addr,
+ RegisterValue value) {
+ EmulateInstructionRISCV::Context ctx;
+ ctx.type = EmulateInstruction::eContextRegisterStore;
+ ctx.SetNoArgs();
+ return emulator.WriteMemoryUnsigned(ctx, addr, value.GetAsUInt64(),
+ sizeof(T));
+}
+
+static uint64_t LoadStoreAddr(EmulateInstructionRISCV &emulator,
+ uint32_t inst) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeSImm(inst));
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return LLDB_INVALID_ADDRESS;
+ uint64_t addr = value.GetAsUInt64() + uint64_t(imm);
+ return addr;
+}
+
+// Read T from memory, then load its sign-extended value E to register.
+template <typename T, typename E>
+static bool Load(EmulateInstructionRISCV &emulator, uint32_t inst,
+ uint64_t (*extend)(E)) {
+ uint64_t addr = LoadStoreAddr(emulator, inst);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+ bool success = false;
+ E value = E(ReadMem<T>(emulator, addr, &success));
+ if (!success)
+ return false;
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(extend(value)));
+}
+
+template <typename T>
+static bool Store(EmulateInstructionRISCV &emulator, uint32_t inst) {
+ uint64_t addr = LoadStoreAddr(emulator, inst);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+ RegisterValue value;
+ if (!ReadRegister(emulator, DecodeRS2(inst), value))
+ return false;
+ return WriteMem<T>(emulator, addr, value);
+}
+
+static bool ExecLB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint8_t, int8_t>(emulator, inst, SextW);
+}
+
+static bool ExecLH(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint16_t, int16_t>(emulator, inst, SextW);
+}
+
+static bool ExecLW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint32_t, int32_t>(emulator, inst, SextW);
+}
+
+static bool ExecLD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint64_t, uint64_t>(emulator, inst, ZextD);
+}
+
+static bool ExecLBU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint8_t, uint8_t>(emulator, inst, ZextD);
+}
+
+static bool ExecLHU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint16_t, uint16_t>(emulator, inst, ZextD);
+}
+
+static bool ExecLWU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Load<uint32_t, uint32_t>(emulator, inst, ZextD);
+}
+
+static bool ExecSB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Store<uint8_t>(emulator, inst);
+}
+
+static bool ExecSH(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Store<uint16_t>(emulator, inst);
+}
+
+static bool ExecSW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Store<uint32_t>(emulator, inst);
+}
+
+static bool ExecSD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ return Store<uint64_t>(emulator, inst);
+}
+
+static bool ExecADDI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = int64_t(value.GetAsUInt64()) + int64_t(imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLTI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = int64_t(value.GetAsUInt64()) < int64_t(imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLTIU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = value.GetAsUInt64() < uint64_t(imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecXORI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = value.GetAsUInt64() ^ uint64_t(imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecORI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = value.GetAsUInt64() | uint64_t(imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecANDI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = value.GetAsUInt64() & uint64_t(imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLLI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto shamt = DecodeSHAMT7(inst);
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = value.GetAsUInt64() << shamt;
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRLI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto shamt = DecodeSHAMT7(inst);
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = value.GetAsUInt64() >> shamt;
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRAI(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto shamt = DecodeSHAMT7(inst);
+
+ RegisterValue value;
+ if (!ReadRegister(emulator, rs1, value))
+ return false;
+
+ uint64_t result = int64_t(value.GetAsUInt64()) >> shamt;
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecADD(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
-static InstrPattern PATTERNS[] = {
- {"JAL", J_MASK, 0b1101111, ExecJAL},
- {"JALR", I_MASK, 0b000000001100111, ExecJALR},
- {"B<CMP>", B_MASK, 0b1100011, ExecB},
- // TODO: {LR/SC}.{W/D} and ECALL
+ uint64_t result = value1.GetAsUInt64() + value2.GetAsUInt64();
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSUB(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() - value2.GetAsUInt64();
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() << (value2.GetAsUInt64() & 0b111111);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLT(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = int64_t(value1.GetAsUInt64()) < int64_t(value2.GetAsUInt64());
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLTU(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() < value2.GetAsUInt64();
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecXOR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() ^ value2.GetAsUInt64();
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRL(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() >> (value2.GetAsUInt64() & 0b111111);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRA(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result =
+ int64_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecOR(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() | value2.GetAsUInt64();
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecAND(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = value1.GetAsUInt64() & value2.GetAsUInt64();
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecADDIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ int32_t imm = SignExt(DecodeIImm(inst));
+
+ RegisterValue value1;
+ if (!ReadRegister(emulator, rs1, value1))
+ return false;
+
+ uint64_t result = SextW(int32_t(value1.GetAsUInt64()) + imm);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLLIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto shamt = DecodeSHAMT5(inst);
+
+ RegisterValue value1;
+ if (!ReadRegister(emulator, rs1, value1))
+ return false;
+
+ uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) << shamt);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRLIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto shamt = DecodeSHAMT5(inst);
+
+ RegisterValue value1;
+ if (!ReadRegister(emulator, rs1, value1))
+ return false;
+
+ uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >> shamt);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRAIW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto shamt = DecodeSHAMT5(inst);
+
+ RegisterValue value1;
+ if (!ReadRegister(emulator, rs1, value1))
+ return false;
+
+ uint64_t result = SextW(int32_t(value1.GetAsUInt64()) >> shamt);
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecADDW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = SextW(value1.GetAsUInt32() + value2.GetAsUInt32());
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSUBW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = SextW(value1.GetAsUInt32() - value2.GetAsUInt32());
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSLLW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = SextW(uint32_t(value1.GetAsUInt64())
+ << (value2.GetAsUInt64() & 0b111111));
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRLW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result = SextW(uint32_t(value1.GetAsUInt64()) >>
+ (value2.GetAsUInt64() & 0b111111));
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static bool ExecSRAW(EmulateInstructionRISCV &emulator, uint32_t inst, bool) {
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = DecodeRS2(inst);
+
+ RegisterValue value1;
+ RegisterValue value2;
+ if (!ReadRegister(emulator, rs1, value1) ||
+ !ReadRegister(emulator, rs2, value2))
+ return false;
+
+ uint64_t result =
+ SextW(int32_t(value1.GetAsUInt64()) >> (value2.GetAsUInt64() & 0b111111));
+ return WriteRegister(emulator, DecodeRD(inst), RegisterValue(result));
+}
+
+static const InstrPattern PATTERNS[] = {
+ {"LUI", 0x7F, 0x37, ExecLUI},
+ {"AUIPC", 0x7F, 0x17, ExecAUIPC},
+ {"JAL", 0x7F, 0x6F, ExecJAL},
+ {"JALR", 0x707F, 0x67, ExecJALR},
+ {"B<CMP>", 0x7F, 0x63, ExecB},
+ {"LB", 0x707F, 0x3, ExecLB},
+ {"LH", 0x707F, 0x1003, ExecLH},
+ {"LW", 0x707F, 0x2003, ExecLW},
+ {"LBU", 0x707F, 0x4003, ExecLBU},
+ {"LHU", 0x707F, 0x5003, ExecLHU},
+ {"SB", 0x707F, 0x23, ExecSB},
+ {"SH", 0x707F, 0x1023, ExecSH},
+ {"SW", 0x707F, 0x2023, ExecSW},
+ {"ADDI", 0x707F, 0x13, ExecADDI},
+ {"SLTI", 0x707F, 0x2013, ExecSLTI},
+ {"SLTIU", 0x707F, 0x3013, ExecSLTIU},
+ {"XORI", 0x707F, 0x4013, ExecXORI},
+ {"ORI", 0x707F, 0x6013, ExecORI},
+ {"ANDI", 0x707F, 0x7013, ExecANDI},
+ {"SLLI", 0xF800707F, 0x1013, ExecSLLI},
+ {"SRLI", 0xF800707F, 0x5013, ExecSRLI},
+ {"SRAI", 0xF800707F, 0x40005013, ExecSRAI},
+ {"ADD", 0xFE00707F, 0x33, ExecADD},
+ {"SUB", 0xFE00707F, 0x40000033, ExecSUB},
+ {"SLL", 0xFE00707F, 0x1033, ExecSLL},
+ {"SLT", 0xFE00707F, 0x2033, ExecSLT},
+ {"SLTU", 0xFE00707F, 0x3033, ExecSLTU},
+ {"XOR", 0xFE00707F, 0x4033, ExecXOR},
+ {"SRL", 0xFE00707F, 0x5033, ExecSRL},
+ {"SRA", 0xFE00707F, 0x40005033, ExecSRA},
+ {"OR", 0xFE00707F, 0x6033, ExecOR},
+ {"AND", 0xFE00707F, 0x7033, ExecAND},
+ {"LWU", 0x707F, 0x6003, ExecLWU},
+ {"LD", 0x707F, 0x3003, ExecLD},
+ {"SD", 0x707F, 0x3023, ExecSD},
+ {"ADDIW", 0x707F, 0x1B, ExecADDIW},
+ {"SLLIW", 0xFE00707F, 0x101B, ExecSLLIW},
+ {"SRLIW", 0xFE00707F, 0x501B, ExecSRLIW},
+ {"SRAIW", 0xFE00707F, 0x4000501B, ExecSRAIW},
+ {"ADDW", 0xFE00707F, 0x3B, ExecADDW},
+ {"SUBW", 0xFE00707F, 0x4000003B, ExecSUBW},
+ {"SLLW", 0xFE00707F, 0x103B, ExecSLLW},
+ {"SRLW", 0xFE00707F, 0x503B, ExecSRLW},
+ {"SRAW", 0xFE00707F, 0x4000503B, ExecSRAW},
};
-/// This function only determines the next instruction address for software
-/// sigle stepping by emulating branching instructions including:
-/// - from Base Instruction Set : JAL, JALR, B<CMP>, ECALL
-/// - from Atomic Instruction Set: LR -> BNE -> SC -> BNE
-/// We will get rid of this tedious code when the riscv debug spec is ratified.
-bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst,
- bool ignore_cond) {
- Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
+const InstrPattern *EmulateInstructionRISCV::Decode(uint32_t inst) {
for (const InstrPattern &pat : PATTERNS) {
if ((inst & pat.type_mask) == pat.eigen) {
- LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s",
- __FUNCTION__, inst, pat.name);
- return pat.exec(this, inst, ignore_cond);
+ return &pat;
}
}
+ return nullptr;
+}
+
+/// This function only determines the next instruction address for software
+/// sigle stepping by emulating instructions
+bool EmulateInstructionRISCV::DecodeAndExecute(uint32_t inst,
+ bool ignore_cond) {
+ Log *log = GetLog(LLDBLog::Unwind);
+ const InstrPattern *pattern = this->Decode(inst);
+ if (pattern) {
+ LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(%x) was decoded to %s",
+ __FUNCTION__, inst, pattern->name);
+ return pattern->exec(*this, inst, ignore_cond);
+ }
LLDB_LOGF(log,
"EmulateInstructionRISCV::%s: inst(0x%x) does not branch: "
@@ -213,7 +749,7 @@ bool EmulateInstructionRISCV::EvaluateInstruction(uint32_t options) {
bool ignore_cond = options & eEmulateInstructionOptionIgnoreConditions;
bool success = false;
- lldb::addr_t old_pc = 0;
+ lldb::addr_t old_pc = LLDB_INVALID_ADDRESS;
if (increase_pc) {
old_pc = ReadPC(&success);
if (!success)
@@ -253,15 +789,14 @@ bool EmulateInstructionRISCV::ReadInstruction() {
Context ctx;
ctx.type = eContextReadOpcode;
ctx.SetNoArgs();
- uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success);
- uint16_t try_rvc = (uint16_t)(inst & 0x0000ffff);
+ uint32_t inst = uint32_t(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success));
+ uint16_t try_rvc = uint16_t(inst & 0x0000ffff);
// check whether the compressed encode could be valid
uint16_t mask = try_rvc & 0b11;
- if (try_rvc != 0 && mask != 3) {
+ if (try_rvc != 0 && mask != 3)
m_opcode.SetOpcode16(try_rvc, GetByteOrder());
- } else {
+ else
m_opcode.SetOpcode32(inst, GetByteOrder());
- }
return true;
}
diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
index 65fba83eb14f7..2ed049ffac990 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h
@@ -16,6 +16,22 @@
namespace lldb_private {
+constexpr uint32_t DecodeRD(uint32_t inst) { return (inst & 0xF80) >> 7; }
+constexpr uint32_t DecodeRS1(uint32_t inst) { return (inst & 0xF8000) >> 15; }
+constexpr uint32_t DecodeRS2(uint32_t inst) { return (inst & 0x1F00000) >> 20; }
+
+class EmulateInstructionRISCV;
+
+struct InstrPattern {
+ const char *name;
+ /// Bit mask to check the type of a instruction (B-Type, I-Type, J-Type, etc.)
+ uint32_t type_mask;
+ /// Characteristic value after bitwise-and with type_mask.
+ uint32_t eigen;
+ bool (*exec)(EmulateInstructionRISCV &emulator, uint32_t inst,
+ bool ignore_cond);
+};
+
class EmulateInstructionRISCV : public EmulateInstruction {
public:
static llvm::StringRef GetPluginNameStatic() { return "riscv"; }
@@ -32,6 +48,8 @@ class EmulateInstructionRISCV : public EmulateInstruction {
case eInstructionTypePrologueEpilogue:
case eInstructionTypeAll:
return false;
+ default:
+ llvm_unreachable("Unhandled instruction type");
}
llvm_unreachable("Fully covered switch above!");
}
@@ -64,6 +82,8 @@ class EmulateInstructionRISCV : public EmulateInstruction {
lldb::addr_t ReadPC(bool *success);
bool WritePC(lldb::addr_t pc);
+
+ const InstrPattern *Decode(uint32_t inst);
bool DecodeAndExecute(uint32_t inst, bool ignore_cond);
};
diff --git a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
index c49f33ddd0d7e..2ae8b4eb7149c 100644
--- a/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
+++ b/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp
@@ -157,6 +157,37 @@ void testBranch(RISCVEmulatorTester *tester, EncoderB encoder, bool branched,
testBranch(this, name, false, rs1, rs2_continued); \
}
+void CheckRD(RISCVEmulatorTester *tester, uint64_t rd, uint64_t value) {
+ ASSERT_EQ(tester->gpr.gpr[rd], value);
+}
+
+using RS1 = uint64_t;
+using RS2 = uint64_t;
+using PC = uint64_t;
+using RDComputer = std::function<uint64_t(RS1, RS2, PC)>;
+
+void TestInst(RISCVEmulatorTester *tester, uint64_t inst, bool has_rs2,
+ RDComputer rd_val) {
+
+ lldb::addr_t old_pc = 0x114514;
+ tester->WritePC(old_pc);
+ auto rd = DecodeRD(inst);
+ auto rs1 = DecodeRS1(inst);
+ auto rs2 = 0;
+ if (rs1)
+ tester->gpr.gpr[rs1] = 0x1919;
+
+ if (has_rs2) {
+ rs2 = DecodeRS2(inst);
+ if (rs2)
+ tester->gpr.gpr[rs2] = 0x8181;
+ }
+
+ ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
+ CheckRD(tester, rd,
+ rd_val(tester->gpr.gpr[rs1], rs2 ? tester->gpr.gpr[rs2] : 0, old_pc));
+}
+
// GEN_BRANCH_TEST(opcode, imm1, imm2, imm3):
// It should branch for instruction `opcode imm1, imm2`
// It should do nothing for instruction `opcode imm1, imm3`
@@ -167,30 +198,34 @@ GEN_BRANCH_TEST(BGE, -2, -3, 1)
GEN_BRANCH_TEST(BLTU, -2, -1, 1)
GEN_BRANCH_TEST(BGEU, -2, 1, -1)
-void testNothing(RISCVEmulatorTester *tester, uint32_t inst) {
- lldb::addr_t old_pc = 0x114514;
- tester->WritePC(old_pc);
- tester->SetInstruction(Opcode(inst, tester->GetByteOrder()),
- LLDB_INVALID_ADDRESS, nullptr);
- ASSERT_TRUE(tester->EvaluateInstruction(0));
- bool success = false;
- auto pc = tester->ReadPC(&success);
- ASSERT_TRUE(success);
- ASSERT_EQ(pc, old_pc);
- ASSERT_TRUE(
- tester->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC));
- pc = tester->ReadPC(&success);
- ASSERT_TRUE(success);
- ASSERT_EQ(pc, old_pc + 4);
-}
-
-#define GEN_NOTHING_TEST(name, inst) \
- TEST_F(RISCVEmulatorTester, testDoNothing_##name) { testNothing(this, inst); }
+struct TestData {
+ uint32_t inst;
+ std::string name;
+ bool has_rs2;
+ RDComputer rd_val;
+};
-// GEN_NOTHING_TEST(name, inst):
-// It should do nothing (except increasing pc) for instruction `inst`
-GEN_NOTHING_TEST(mv, 0x01813083) // mv a0, a5
-GEN_NOTHING_TEST(li, 0x00078513) // li a5, 0
-GEN_NOTHING_TEST(sd, 0x02010413) // sd s0, sp(16)
-GEN_NOTHING_TEST(lw, 0x0007879b) // lw a5, s0(-20)
-GEN_NOTHING_TEST(addi, 0x00113423) // addi sp, sp, -16
+TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
+
+ std::vector<TestData> tests = {
+ {0x00010113, "ADDI", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
+ {0x00023517, "AUIPC", false, [](RS1, RS2, PC pc) { return pc + 143360; }},
+ {0x0006079b, "ADDIW", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
+ {0x00110837, "LUI", false, [](RS1, RS2, PC pc) { return 1114112; }},
+ {0x00147513, "ANDI", false, [](RS1 rs1, RS2, PC) { return rs1 & 1; }},
+ {0x00153513, "SLTIU", false, [](RS1 rs1, RS2, PC) { return rs1 != 0; }},
+ {0x00256513, "ORI", false, [](RS1 rs1, RS2, PC) { return rs1 | 1; }},
+ {0x00451a13, "SLLI", false, [](RS1 rs1, RS2, PC) { return rs1 << 4; }},
+ {0x00455693, "SRLI", false, [](RS1 rs1, RS2, PC) { return rs1 >> 4; }},
+ {0x00a035b3, "SLTU", true, [](RS1 rs1, RS2 rs2, PC) { return rs2 != 0; }},
+ {0x00b50633, "ADD", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 + rs2; }},
+ {0x40d507b3, "SUB", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 - rs2; }},
+ };
+ for (auto i : tests) {
+ const InstrPattern *pattern = this->Decode(i.inst);
+ ASSERT_TRUE(pattern != nullptr);
+ std::string name = pattern->name;
+ ASSERT_EQ(name, i.name);
+ TestInst(this, i.inst, i.has_rs2, i.rd_val);
+ }
+}
More information about the lldb-commits
mailing list