1//===-- TestRISCVEmulator.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 "gtest/gtest.h"
10
11#include "lldb/Core/Address.h"
12#include "lldb/Core/Disassembler.h"
13#include "lldb/Core/PluginManager.h"
14#include "lldb/Target/ExecutionContext.h"
15#include "lldb/Utility/ArchSpec.h"
16#include "lldb/Utility/RegisterValue.h"
17
18#include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h"
19#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"
20#include "Plugins/Process/Utility/lldb-riscv-register-enums.h"
21
22using namespace llvm;
23using namespace lldb;
24using namespace lldb_private;
25
26struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
27 RegisterInfoPOSIX_riscv64::GPR gpr;
28 RegisterInfoPOSIX_riscv64::FPR fpr;
29 uint8_t memory[1024] = {0};
30
31 RISCVEmulatorTester(std::string triple = "riscv64-unknown-linux-gnu")
32 : EmulateInstructionRISCV(ArchSpec(triple)) {
33 EmulateInstruction::SetReadRegCallback(ReadRegisterCallback);
34 EmulateInstruction::SetWriteRegCallback(WriteRegisterCallback);
35 EmulateInstruction::SetReadMemCallback(ReadMemoryCallback);
36 EmulateInstruction::SetWriteMemCallback(WriteMemoryCallback);
37 ClearAll();
38 }
39
40 static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
41 const RegisterInfo *reg_info,
42 RegisterValue &reg_value) {
43 RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
44 uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
45 if (reg == gpr_x0_riscv)
46 reg_value.SetUInt(uint: 0, byte_size: reg_info->byte_size);
47 if (reg >= gpr_pc_riscv && reg <= gpr_x31_riscv)
48 reg_value.SetUInt(uint: tester->gpr.gpr[reg], byte_size: reg_info->byte_size);
49 if (reg >= fpr_f0_riscv && reg <= fpr_f31_riscv)
50 reg_value.SetUInt(uint: tester->fpr.fpr[reg - fpr_f0_riscv],
51 byte_size: reg_info->byte_size);
52 if (reg == fpr_fcsr_riscv)
53 reg_value.SetUInt(uint: tester->fpr.fcsr, byte_size: reg_info->byte_size);
54 return true;
55 }
56
57 static bool WriteRegisterCallback(EmulateInstruction *instruction,
58 void *baton, const Context &context,
59 const RegisterInfo *reg_info,
60 const RegisterValue &reg_value) {
61 RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
62 uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
63 if (reg >= gpr_pc_riscv && reg <= gpr_x31_riscv)
64 tester->gpr.gpr[reg] = reg_value.GetAsUInt64();
65 if (reg >= fpr_f0_riscv && reg <= fpr_f31_riscv)
66 tester->fpr.fpr[reg - fpr_f0_riscv] = reg_value.GetAsUInt64();
67 if (reg == fpr_fcsr_riscv)
68 tester->fpr.fcsr = reg_value.GetAsUInt32();
69 return true;
70 }
71
72 static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
73 const Context &context, addr_t addr,
74 void *dst, size_t length) {
75 RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
76 assert(addr + length < sizeof(tester->memory));
77 memcpy(dest: dst, src: tester->memory + addr, n: length);
78 return length;
79 };
80
81 static size_t WriteMemoryCallback(EmulateInstruction *instruction,
82 void *baton, const Context &context,
83 addr_t addr, const void *dst,
84 size_t length) {
85 RISCVEmulatorTester *tester = (RISCVEmulatorTester *)instruction;
86 assert(addr + length < sizeof(tester->memory));
87 memcpy(dest: tester->memory + addr, src: dst, n: length);
88 return length;
89 };
90
91 bool DecodeAndExecute(uint32_t inst, bool ignore_cond) {
92 return llvm::transformOptional(
93 O: Decode(inst),
94 F: [&](DecodeResult res) { return Execute(inst: res, ignore_cond); })
95 .value_or(u: false);
96 }
97
98 void ClearAll() {
99 memset(s: &gpr, c: 0, n: sizeof(gpr));
100 memset(s: &fpr, c: 0, n: sizeof(fpr));
101 memset(s: memory, c: 0, n: sizeof(memory));
102 }
103};
104
105TEST_F(RISCVEmulatorTester, testJAL) {
106 addr_t old_pc = 0x114514;
107 WritePC(pc: old_pc);
108 // jal x1, -6*4
109 uint32_t inst = 0b11111110100111111111000011101111;
110 ASSERT_TRUE(DecodeAndExecute(inst, false));
111 auto x1 = gpr.gpr[1];
112 auto pc = ReadPC();
113 ASSERT_TRUE(pc.has_value());
114 ASSERT_EQ(x1, old_pc + 4);
115 ASSERT_EQ(*pc, old_pc + (-6 * 4));
116}
117
118constexpr uint32_t EncodeIType(uint32_t opcode, uint32_t funct3, uint32_t rd,
119 uint32_t rs1, uint32_t imm) {
120 return imm << 20 | rs1 << 15 | funct3 << 12 | rd << 7 | opcode;
121}
122
123constexpr uint32_t EncodeJALR(uint32_t rd, uint32_t rs1, int32_t offset) {
124 return EncodeIType(opcode: 0b1100111, funct3: 0, rd, rs1, imm: uint32_t(offset));
125}
126
127TEST_F(RISCVEmulatorTester, testJALR) {
128 addr_t old_pc = 0x114514;
129 addr_t old_x2 = 0x1024;
130 WritePC(pc: old_pc);
131 gpr.gpr[2] = old_x2;
132 // jalr x1, x2(-255)
133 uint32_t inst = EncodeJALR(rd: 1, rs1: 2, offset: -255);
134 ASSERT_TRUE(DecodeAndExecute(inst, false));
135 auto x1 = gpr.gpr[1];
136 auto pc = ReadPC();
137 ASSERT_TRUE(pc.has_value());
138 ASSERT_EQ(x1, old_pc + 4);
139 // JALR always zeros the bottom bit of the target address.
140 ASSERT_EQ(*pc, (old_x2 + (-255)) & (~1));
141}
142
143constexpr uint32_t EncodeBType(uint32_t opcode, uint32_t funct3, uint32_t rs1,
144 uint32_t rs2, uint32_t imm) {
145 uint32_t bimm = (imm & (0b1 << 11)) >> 4 | (imm & (0b11110)) << 7 |
146 (imm & (0b111111 << 5)) << 20 | (imm & (0b1 << 12)) << 19;
147
148 return rs2 << 20 | rs1 << 15 | funct3 << 12 | opcode | bimm;
149}
150
151constexpr uint32_t BEQ(uint32_t rs1, uint32_t rs2, int32_t offset) {
152 return EncodeBType(opcode: 0b1100011, funct3: 0b000, rs1, rs2, imm: uint32_t(offset));
153}
154
155constexpr uint32_t BNE(uint32_t rs1, uint32_t rs2, int32_t offset) {
156 return EncodeBType(opcode: 0b1100011, funct3: 0b001, rs1, rs2, imm: uint32_t(offset));
157}
158
159constexpr uint32_t BLT(uint32_t rs1, uint32_t rs2, int32_t offset) {
160 return EncodeBType(opcode: 0b1100011, funct3: 0b100, rs1, rs2, imm: uint32_t(offset));
161}
162
163constexpr uint32_t BGE(uint32_t rs1, uint32_t rs2, int32_t offset) {
164 return EncodeBType(opcode: 0b1100011, funct3: 0b101, rs1, rs2, imm: uint32_t(offset));
165}
166
167constexpr uint32_t BLTU(uint32_t rs1, uint32_t rs2, int32_t offset) {
168 return EncodeBType(opcode: 0b1100011, funct3: 0b110, rs1, rs2, imm: uint32_t(offset));
169}
170
171constexpr uint32_t BGEU(uint32_t rs1, uint32_t rs2, int32_t offset) {
172 return EncodeBType(opcode: 0b1100011, funct3: 0b111, rs1, rs2, imm: uint32_t(offset));
173}
174
175using EncoderB = uint32_t (*)(uint32_t rs1, uint32_t rs2, int32_t offset);
176
177static void testBranch(RISCVEmulatorTester *tester, EncoderB encoder,
178 bool branched, uint64_t rs1, uint64_t rs2) {
179 // prepare test registers
180 addr_t old_pc = 0x114514;
181 tester->WritePC(pc: old_pc);
182 tester->gpr.gpr[1] = rs1;
183 tester->gpr.gpr[2] = rs2;
184 // b<cmp> x1, x2, (-256)
185 uint32_t inst = encoder(1, 2, -256);
186 ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
187 auto pc = tester->ReadPC();
188 ASSERT_TRUE(pc.has_value());
189 ASSERT_EQ(*pc, old_pc + (branched ? (-256) : 0));
190}
191
192#define GEN_BRANCH_TEST(name, rs1, rs2_branched, rs2_continued) \
193 TEST_F(RISCVEmulatorTester, test##name##Branched) { \
194 testBranch(this, name, true, rs1, rs2_branched); \
195 } \
196 TEST_F(RISCVEmulatorTester, test##name##Continued) { \
197 testBranch(this, name, false, rs1, rs2_continued); \
198 }
199
200static void CheckRD(RISCVEmulatorTester *tester, uint64_t rd, uint64_t value) {
201 ASSERT_EQ(tester->gpr.gpr[rd], value);
202}
203
204template <typename T>
205static void CheckMem(RISCVEmulatorTester *tester, uint64_t addr,
206 uint64_t value) {
207 auto mem = tester->ReadMem<T>(addr);
208 ASSERT_TRUE(mem.has_value());
209 ASSERT_EQ(*mem, value);
210}
211
212using RS1 = uint64_t;
213using RS2 = uint64_t;
214using PC = uint64_t;
215using RDComputer = std::function<uint64_t(RS1, RS2, PC)>;
216
217static void TestInst(RISCVEmulatorTester *tester, DecodeResult inst,
218 bool has_rs2, RDComputer rd_val) {
219
220 addr_t old_pc = 0x114514;
221 tester->WritePC(pc: old_pc);
222 uint32_t rd = DecodeRD(inst: inst.inst);
223 uint32_t rs1 = DecodeRS1(inst: inst.inst);
224 uint32_t rs2 = 0;
225
226 uint64_t rs1_val = 0x19;
227 uint64_t rs2_val = 0x81;
228
229 if (rs1)
230 tester->gpr.gpr[rs1] = rs1_val;
231
232 if (has_rs2) {
233 rs2 = DecodeRS2(inst: inst.inst);
234 if (rs2) {
235 if (rs1 == rs2)
236 rs2_val = rs1_val;
237 tester->gpr.gpr[rs2] = rs2_val;
238 }
239 }
240
241 ASSERT_TRUE(tester->Execute(inst, false));
242 CheckRD(tester, rd, value: rd_val(rs1_val, rs2 ? rs2_val : 0, old_pc));
243}
244
245template <typename T>
246static void TestAtomic(RISCVEmulatorTester *tester, uint64_t inst, T rs1_val,
247 T rs2_val, T rd_expected, T mem_expected) {
248 // Atomic inst must have rs1 and rs2
249
250 uint32_t rd = DecodeRD(inst);
251 uint32_t rs1 = DecodeRS1(inst);
252 uint32_t rs2 = DecodeRS2(inst);
253
254 // addr was stored in rs1
255 uint64_t atomic_addr = 0x100;
256
257 tester->gpr.gpr[rs1] = atomic_addr;
258 tester->gpr.gpr[rs2] = rs2_val;
259
260 // Write and check rs1_val in atomic_addr
261 ASSERT_TRUE(tester->WriteMem<T>(atomic_addr, rs1_val));
262 CheckMem<T>(tester, atomic_addr, rs1_val);
263
264 ASSERT_TRUE(tester->DecodeAndExecute(inst, false));
265 CheckRD(tester, rd, rd_expected);
266 CheckMem<T>(tester, atomic_addr, mem_expected);
267}
268
269TEST_F(RISCVEmulatorTester, TestAtomicSequence) {
270 this->WritePC(pc: 0x0);
271 *(uint32_t *)this->memory = 0x100427af; // lr.w a5,(s0)
272 *(uint32_t *)(this->memory + 4) = 0x00079663; // bnez a5,12
273 *(uint32_t *)(this->memory + 8) = 0x1ce426af; // sc.w.aq a3,a4,(s0)
274 *(uint32_t *)(this->memory + 12) = 0xfe069ae3; // bnez a3,-12
275 ASSERT_TRUE(this->DecodeAndExecute(*(uint32_t *)this->memory, false));
276 ASSERT_EQ(this->gpr.gpr[0], uint64_t(16));
277}
278
279struct TestDecode {
280 uint32_t inst;
281 RISCVInst inst_type;
282};
283
284TEST_F(RISCVEmulatorTester, TestCDecode) {
285 std::vector<TestDecode> tests = {
286 {.inst: 0x0000, .inst_type: INVALID{.inst: 0x0000}},
287 {.inst: 0x0010, .inst_type: RESERVED{.inst: 0x0010}},
288 // ADDI4SPN here, decode as ADDI
289 {.inst: 0x0024, .inst_type: ADDI{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 2}, .imm: 8}},
290 {.inst: 0x2084, .inst_type: FLD{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .imm: 0}},
291 {.inst: 0x4488, .inst_type: LW{.rd: Rd{.rd: 10}, .rs1: Rs{.rs: 9}, .imm: 8}},
292 {.inst: 0x6488, .inst_type: LD{.rd: Rd{.rd: 10}, .rs1: Rs{.rs: 9}, .imm: 8}},
293 {.inst: 0xA084, .inst_type: FSD{.rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}, .imm: 0}},
294 {.inst: 0xC488, .inst_type: SW{.rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 10}, .imm: 8}},
295 {.inst: 0xE488, .inst_type: SD{.rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 10}, .imm: 8}},
296 {.inst: 0x1001, .inst_type: NOP{.inst: 0x1001}},
297 {.inst: 0x1085, .inst_type: ADDI{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 1}, .imm: uint32_t(-31)}},
298 {.inst: 0x2081, .inst_type: ADDIW{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 1}, .imm: 0}},
299 // ADDI16SP here, decode as ADDI
300 {.inst: 0x7101, .inst_type: ADDI{.rd: Rd{.rd: 2}, .rs1: Rs{.rs: 2}, .imm: uint32_t(-512)}},
301 {.inst: 0x4081, .inst_type: ADDI{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 0}, .imm: 0}},
302 {.inst: 0x7081, .inst_type: LUI{.rd: Rd{.rd: 1}, .imm: uint32_t(-131072)}},
303 {.inst: 0x8085, .inst_type: SRLI{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .shamt: 1}},
304 {.inst: 0x8485, .inst_type: SRAI{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .shamt: 1}},
305 {.inst: 0x8881, .inst_type: ANDI{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .imm: 0}},
306 {.inst: 0x8C85, .inst_type: SUB{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}}},
307 {.inst: 0x8CA5, .inst_type: XOR{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}}},
308 {.inst: 0x8CC5, .inst_type: OR{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}}},
309 {.inst: 0x8CE5, .inst_type: AND{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}}},
310 {.inst: 0x9C85, .inst_type: SUBW{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}}},
311 {.inst: 0x9CA5, .inst_type: ADDW{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}}},
312 // C.J here, decoded as JAL
313 {.inst: 0xA001, .inst_type: JAL{.rd: Rd{.rd: 0}, .imm: 0}},
314 {.inst: 0xC081, .inst_type: B{.rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 0}, .imm: 0, .funct3: 0b000}},
315 {.inst: 0xE081, .inst_type: B{.rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 0}, .imm: 0, .funct3: 0b001}},
316 {.inst: 0x1082, .inst_type: SLLI{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 1}, .shamt: 32}},
317 {.inst: 0x1002, .inst_type: HINT{.inst: 0x1002}},
318 // SLLI64 here, decoded as HINT if not in RV128
319 {.inst: 0x0082, .inst_type: HINT{.inst: 0x0082}},
320 // FLDSP here, decoded as FLD
321 {.inst: 0x2082, .inst_type: FLD{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 2}, .imm: 0}},
322 // LWSP here, decoded as LW
323 {.inst: 0x4082, .inst_type: LW{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 2}, .imm: 0}},
324 // LDSP here, decoded as LD
325 {.inst: 0x6082, .inst_type: LD{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 2}, .imm: 0}},
326 // C.JR here, decoded as JALR
327 {.inst: 0x8082, .inst_type: JALR{.rd: Rd{.rd: 0}, .rs1: Rs{.rs: 1}, .imm: 0}},
328 // C.MV here, decoded as ADD
329 {.inst: 0x8086, .inst_type: ADD{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 0}, .rs2: Rs{.rs: 1}}},
330 {.inst: 0x9002, .inst_type: EBREAK{.inst: 0x9002}},
331 {.inst: 0x9082, .inst_type: JALR{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 1}, .imm: 0}},
332 {.inst: 0x9086, .inst_type: ADD{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 1}, .rs2: Rs{.rs: 1}}},
333 // C.FSDSP here, decoded as FSD
334 {.inst: 0xA006, .inst_type: FSD{.rs1: Rs{.rs: 2}, .rs2: Rs{.rs: 1}, .imm: 0}},
335 // C.SWSP here, decoded as SW
336 {.inst: 0xC006, .inst_type: SW{.rs1: Rs{.rs: 2}, .rs2: Rs{.rs: 1}, .imm: 0}},
337 // C.SDSP here, decoded as SD
338 {.inst: 0xE006, .inst_type: SD{.rs1: Rs{.rs: 2}, .rs2: Rs{.rs: 1}, .imm: 0}},
339 };
340
341 for (auto i : tests) {
342 auto decode = this->Decode(inst: i.inst);
343 ASSERT_TRUE(decode.has_value());
344 ASSERT_EQ(decode->decoded, i.inst_type);
345 }
346}
347
348class RISCVEmulatorTester32 : public RISCVEmulatorTester {
349public:
350 RISCVEmulatorTester32() : RISCVEmulatorTester("riscv32-unknown-linux-gnu") {}
351};
352
353TEST_F(RISCVEmulatorTester32, TestCDecodeRV32) {
354 std::vector<TestDecode> tests = {
355 {.inst: 0x6002, .inst_type: FLW{.rd: Rd{.rd: 0}, .rs1: Rs{.rs: 2}, .imm: 0}},
356 {.inst: 0xE006, .inst_type: FSW{.rs1: Rs{.rs: 2}, .rs2: Rs{.rs: 1}, .imm: 0}},
357 {.inst: 0x6000, .inst_type: FLW{.rd: Rd{.rd: 8}, .rs1: Rs{.rs: 8}, .imm: 0}},
358 {.inst: 0xE000, .inst_type: FSW{.rs1: Rs{.rs: 8}, .rs2: Rs{.rs: 8}, .imm: 0}},
359
360 {.inst: 0x2084, .inst_type: FLD{.rd: Rd{.rd: 9}, .rs1: Rs{.rs: 9}, .imm: 0}},
361 {.inst: 0xA084, .inst_type: FSD{.rs1: Rs{.rs: 9}, .rs2: Rs{.rs: 9}, .imm: 0}},
362 {.inst: 0x2082, .inst_type: FLD{.rd: Rd{.rd: 1}, .rs1: Rs{.rs: 2}, .imm: 0}},
363 {.inst: 0xA006, .inst_type: FSD{.rs1: Rs{.rs: 2}, .rs2: Rs{.rs: 1}, .imm: 0}},
364 };
365
366 for (auto i : tests) {
367 auto decode = this->Decode(inst: i.inst);
368 ASSERT_TRUE(decode.has_value());
369 ASSERT_EQ(decode->decoded, i.inst_type);
370 }
371}
372
373// GEN_BRANCH_TEST(opcode, imm1, imm2, imm3):
374// It should branch for instruction `opcode imm1, imm2`
375// It should do nothing for instruction `opcode imm1, imm3`
376GEN_BRANCH_TEST(BEQ, 1, 1, 0)
377GEN_BRANCH_TEST(BNE, 1, 0, 1)
378GEN_BRANCH_TEST(BLT, -2, 1, -3)
379GEN_BRANCH_TEST(BGE, -2, -3, 1)
380GEN_BRANCH_TEST(BLTU, -2, -1, 1)
381GEN_BRANCH_TEST(BGEU, -2, 1, -1)
382
383struct TestData {
384 uint32_t inst;
385 std::string name;
386 bool has_rs2;
387 RDComputer rd_val;
388};
389
390TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
391 std::vector<TestData> tests = {
392 // RV32I & RV64I Tests
393 {.inst: 0x00010113, .name: "ADDI", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
394 {.inst: 0x00023517, .name: "AUIPC", .has_rs2: false, .rd_val: [](RS1, RS2, PC pc) { return pc + 143360; }},
395 {.inst: 0x0006079b, .name: "ADDIW", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
396 {.inst: 0x00110837, .name: "LUI", .has_rs2: false, .rd_val: [](RS1, RS2, PC pc) { return 1114112; }},
397 {.inst: 0x00147513, .name: "ANDI", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return rs1 & 1; }},
398 {.inst: 0x00153513, .name: "SLTIU", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return 0; }},
399 {.inst: 0x00256513, .name: "ORI", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return rs1 | 2; }},
400 {.inst: 0x00451a13, .name: "SLLI", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return rs1 << 4; }},
401 {.inst: 0x00455693, .name: "SRLI", .has_rs2: false, .rd_val: [](RS1 rs1, RS2, PC) { return rs1 >> 4; }},
402 {.inst: 0x00a035b3, .name: "SLTU", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs2 != 0; }},
403 {.inst: 0x00b50633, .name: "ADD", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 + rs2; }},
404 {.inst: 0x40d507b3, .name: "SUB", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 - rs2; }},
405
406 // RV32M & RV64M Tests
407 {.inst: 0x02f787b3, .name: "MUL", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 * rs2; }},
408 {.inst: 0x2F797B3, .name: "MULH", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return 0; }},
409 {.inst: 0x2F7A7B3, .name: "MULHSU", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return 0; }},
410 {.inst: 0x2F7B7B3, .name: "MULHU", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return 0; }},
411 {.inst: 0x02f747b3, .name: "DIV", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
412 {.inst: 0x02f757b3, .name: "DIVU", .has_rs2: true,
413 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
414 {.inst: 0x02f767b3, .name: "REM", .has_rs2: true, .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
415 {.inst: 0x02f777b3, .name: "REMU", .has_rs2: true,
416 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
417 {.inst: 0x02f787bb, .name: "MULW", .has_rs2: true,
418 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 * rs2; }},
419 {.inst: 0x02f747bb, .name: "DIVW", .has_rs2: true,
420 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
421 {.inst: 0x02f757bb, .name: "DIVUW", .has_rs2: true,
422 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
423 {.inst: 0x02f767bb, .name: "REMW", .has_rs2: true,
424 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
425 {.inst: 0x02f777bb, .name: "REMUW", .has_rs2: true,
426 .rd_val: [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
427 };
428 for (auto i : tests) {
429 auto decode = this->Decode(inst: i.inst);
430 ASSERT_TRUE(decode.has_value());
431 std::string name = decode->pattern.name;
432 ASSERT_EQ(name, i.name);
433 TestInst(tester: this, inst: *decode, has_rs2: i.has_rs2, rd_val: i.rd_val);
434 }
435}
436
437TEST_F(RISCVEmulatorTester, TestAMOSWAP) {
438 TestAtomic<uint32_t>(tester: this, inst: 0x8F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x2);
439 TestAtomic<uint64_t>(tester: this, inst: 0x8F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x2);
440}
441
442TEST_F(RISCVEmulatorTester, TestAMOADD) {
443 TestAtomic<uint32_t>(tester: this, inst: 0xF7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x3);
444 TestAtomic<uint64_t>(tester: this, inst: 0xF7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x3);
445}
446
447TEST_F(RISCVEmulatorTester, TestAMOXOR) {
448 TestAtomic<uint32_t>(tester: this, inst: 0x20F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x3);
449 TestAtomic<uint32_t>(tester: this, inst: 0x20F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x3);
450}
451
452TEST_F(RISCVEmulatorTester, TestAMOAND) {
453 TestAtomic<uint32_t>(tester: this, inst: 0x60F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x0);
454 TestAtomic<uint64_t>(tester: this, inst: 0x60F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x0);
455}
456
457TEST_F(RISCVEmulatorTester, TestAMOOR) {
458 TestAtomic<uint32_t>(tester: this, inst: 0x40F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x3);
459 TestAtomic<uint32_t>(tester: this, inst: 0x40F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x3);
460}
461
462TEST_F(RISCVEmulatorTester, TestAMOMIN) {
463 TestAtomic<uint32_t>(tester: this, inst: 0x80F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x1);
464 TestAtomic<uint64_t>(tester: this, inst: 0x80F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x1);
465}
466
467TEST_F(RISCVEmulatorTester, TestAMOMAX) {
468 TestAtomic<uint32_t>(tester: this, inst: 0xA0F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x2);
469 TestAtomic<uint64_t>(tester: this, inst: 0xA0F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x2);
470}
471
472TEST_F(RISCVEmulatorTester, TestAMOMINU) {
473 TestAtomic<uint32_t>(tester: this, inst: 0xC0F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x1);
474 TestAtomic<uint64_t>(tester: this, inst: 0xC0F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x1);
475}
476
477TEST_F(RISCVEmulatorTester, TestAMOMAXU) {
478 TestAtomic<uint32_t>(tester: this, inst: 0xE0F7282F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x2);
479 TestAtomic<uint64_t>(tester: this, inst: 0xE0F7382F, rs1_val: 0x1, rs2_val: 0x2, rd_expected: 0x1, mem_expected: 0x2);
480}
481
482template <typename T> struct F_D_CalInst {
483 uint32_t inst;
484 std::string name;
485 T rs1_val;
486 T rs2_val;
487 T rd_val;
488};
489
490using FloatCalInst = F_D_CalInst<float>;
491using DoubleCalInst = F_D_CalInst<double>;
492
493template <typename T>
494static void TestF_D_CalInst(RISCVEmulatorTester *tester, DecodeResult inst,
495 T rs1_val, T rs2_val, T rd_exp) {
496 std::vector<std::string> CMPs = {"FEQ_S", "FLT_S", "FLE_S",
497 "FEQ_D", "FLT_D", "FLE_D"};
498 std::vector<std::string> FMAs = {"FMADD_S", "FMSUB_S", "FNMSUB_S",
499 "FNMADD_S", "FMADD_D", "FMSUB_D",
500 "FNMSUB_D", "FNMADD_D"};
501
502 uint32_t rd = DecodeRD(inst: inst.inst);
503 uint32_t rs1 = DecodeRS1(inst: inst.inst);
504 uint32_t rs2 = DecodeRS2(inst: inst.inst);
505
506 APFloat ap_rs1_val(rs1_val);
507 APFloat ap_rs2_val(rs2_val);
508 APFloat ap_rs3_val(0.0f);
509 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
510 "T should be float or double");
511 if constexpr (std::is_same_v<T, float>)
512 ap_rs3_val = APFloat(0.5f);
513 if constexpr (std::is_same_v<T, double>)
514 ap_rs3_val = APFloat(0.5);
515
516 if (rs1)
517 tester->fpr.fpr[rs1] = ap_rs1_val.bitcastToAPInt().getZExtValue();
518 if (rs2)
519 tester->fpr.fpr[rs2] = ap_rs2_val.bitcastToAPInt().getZExtValue();
520 for (auto i : FMAs) {
521 if (inst.pattern.name == i) {
522 uint32_t rs3 = DecodeRS3(inst: inst.inst);
523 tester->fpr.fpr[rs3] = ap_rs3_val.bitcastToAPInt().getZExtValue();
524 }
525 }
526 ASSERT_TRUE(tester->Execute(inst, false));
527 for (auto i : CMPs) {
528 if (inst.pattern.name == i) {
529 ASSERT_EQ(tester->gpr.gpr[rd], rd_exp);
530 return;
531 }
532 }
533
534 if constexpr (std::is_same_v<T, float>) {
535 APInt apInt(32, tester->fpr.fpr[rd]);
536 APFloat rd_val(apInt.bitsToFloat());
537 ASSERT_EQ(rd_val.convertToFloat(), rd_exp);
538 }
539 if constexpr (std::is_same_v<T, double>) {
540 APInt apInt(64, tester->fpr.fpr[rd]);
541 APFloat rd_val(apInt.bitsToDouble());
542 ASSERT_EQ(rd_val.convertToDouble(), rd_exp);
543 }
544}
545
546TEST_F(RISCVEmulatorTester, TestFloatInst) {
547 std::vector<FloatCalInst> tests = {
548 {.inst: 0x21F253, .name: "FADD_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 1.0f},
549 {.inst: 0x821F253, .name: "FSUB_S", .rs1_val: 1.0f, .rs2_val: 0.5f, .rd_val: 0.5f},
550 {.inst: 0x1021F253, .name: "FMUL_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 0.25f},
551 {.inst: 0x1821F253, .name: "FDIV_S", .rs1_val: 0.1f, .rs2_val: 0.1f, .rd_val: 1.0f},
552 {.inst: 0x20218253, .name: "FSGNJ_S", .rs1_val: 0.5f, .rs2_val: 0.2f, .rd_val: 0.5f},
553 {.inst: 0x20219253, .name: "FSGNJN_S", .rs1_val: 0.5f, .rs2_val: -1.0f, .rd_val: 0.5f},
554 {.inst: 0x2021A253, .name: "FSGNJX_S", .rs1_val: -0.5f, .rs2_val: -0.5f, .rd_val: 0.5f},
555 {.inst: 0x2021A253, .name: "FSGNJX_S", .rs1_val: -0.5f, .rs2_val: 0.5f, .rd_val: -0.5f},
556 {.inst: 0x28218253, .name: "FMIN_S", .rs1_val: -0.5f, .rs2_val: 0.5f, .rd_val: -0.5f},
557 {.inst: 0x28218253, .name: "FMIN_S", .rs1_val: -0.5f, .rs2_val: -0.6f, .rd_val: -0.6f},
558 {.inst: 0x28218253, .name: "FMIN_S", .rs1_val: 0.5f, .rs2_val: 0.6f, .rd_val: 0.5f},
559 {.inst: 0x28219253, .name: "FMAX_S", .rs1_val: -0.5f, .rs2_val: -0.6f, .rd_val: -0.5f},
560 {.inst: 0x28219253, .name: "FMAX_S", .rs1_val: 0.5f, .rs2_val: 0.6f, .rd_val: 0.6f},
561 {.inst: 0x28219253, .name: "FMAX_S", .rs1_val: 0.5f, .rs2_val: -0.6f, .rd_val: 0.5f},
562 {.inst: 0xA021A253, .name: "FEQ_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 1},
563 {.inst: 0xA021A253, .name: "FEQ_S", .rs1_val: 0.5f, .rs2_val: -0.5f, .rd_val: 0},
564 {.inst: 0xA021A253, .name: "FEQ_S", .rs1_val: -0.5f, .rs2_val: 0.5f, .rd_val: 0},
565 {.inst: 0xA021A253, .name: "FEQ_S", .rs1_val: 0.4f, .rs2_val: 0.5f, .rd_val: 0},
566 {.inst: 0xA0219253, .name: "FLT_S", .rs1_val: 0.4f, .rs2_val: 0.5f, .rd_val: 1},
567 {.inst: 0xA0219253, .name: "FLT_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 0},
568 {.inst: 0xA0218253, .name: "FLE_S", .rs1_val: 0.4f, .rs2_val: 0.5f, .rd_val: 1},
569 {.inst: 0xA0218253, .name: "FLE_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 1},
570 {.inst: 0x4021F243, .name: "FMADD_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 0.75f},
571 {.inst: 0x4021F247, .name: "FMSUB_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: -0.25f},
572 {.inst: 0x4021F24B, .name: "FNMSUB_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: 0.25f},
573 {.inst: 0x4021F24F, .name: "FNMADD_S", .rs1_val: 0.5f, .rs2_val: 0.5f, .rd_val: -0.75f},
574 };
575 for (auto i : tests) {
576 auto decode = this->Decode(inst: i.inst);
577 ASSERT_TRUE(decode.has_value());
578 std::string name = decode->pattern.name;
579 ASSERT_EQ(name, i.name);
580 TestF_D_CalInst(tester: this, inst: *decode, rs1_val: i.rs1_val, rs2_val: i.rs2_val, rd_exp: i.rd_val);
581 }
582}
583
584TEST_F(RISCVEmulatorTester, TestDoubleInst) {
585 std::vector<DoubleCalInst> tests = {
586 {.inst: 0x221F253, .name: "FADD_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 1.0},
587 {.inst: 0xA21F253, .name: "FSUB_D", .rs1_val: 1.0, .rs2_val: 0.5, .rd_val: 0.5},
588 {.inst: 0x1221F253, .name: "FMUL_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 0.25},
589 {.inst: 0x1A21F253, .name: "FDIV_D", .rs1_val: 0.1, .rs2_val: 0.1, .rd_val: 1.0},
590 {.inst: 0x22218253, .name: "FSGNJ_D", .rs1_val: 0.5, .rs2_val: 0.2, .rd_val: 0.5},
591 {.inst: 0x22219253, .name: "FSGNJN_D", .rs1_val: 0.5, .rs2_val: -1.0, .rd_val: 0.5},
592 {.inst: 0x2221A253, .name: "FSGNJX_D", .rs1_val: -0.5, .rs2_val: -0.5, .rd_val: 0.5},
593 {.inst: 0x2221A253, .name: "FSGNJX_D", .rs1_val: -0.5, .rs2_val: 0.5, .rd_val: -0.5},
594 {.inst: 0x2A218253, .name: "FMIN_D", .rs1_val: -0.5, .rs2_val: 0.5, .rd_val: -0.5},
595 {.inst: 0x2A218253, .name: "FMIN_D", .rs1_val: -0.5, .rs2_val: -0.6, .rd_val: -0.6},
596 {.inst: 0x2A218253, .name: "FMIN_D", .rs1_val: 0.5, .rs2_val: 0.6, .rd_val: 0.5},
597 {.inst: 0x2A219253, .name: "FMAX_D", .rs1_val: -0.5, .rs2_val: -0.6, .rd_val: -0.5},
598 {.inst: 0x2A219253, .name: "FMAX_D", .rs1_val: 0.5, .rs2_val: 0.6, .rd_val: 0.6},
599 {.inst: 0x2A219253, .name: "FMAX_D", .rs1_val: 0.5, .rs2_val: -0.6, .rd_val: 0.5},
600 {.inst: 0xA221A253, .name: "FEQ_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 1},
601 {.inst: 0xA221A253, .name: "FEQ_D", .rs1_val: 0.5, .rs2_val: -0.5, .rd_val: 0},
602 {.inst: 0xA221A253, .name: "FEQ_D", .rs1_val: -0.5, .rs2_val: 0.5, .rd_val: 0},
603 {.inst: 0xA221A253, .name: "FEQ_D", .rs1_val: 0.4, .rs2_val: 0.5, .rd_val: 0},
604 {.inst: 0xA2219253, .name: "FLT_D", .rs1_val: 0.4, .rs2_val: 0.5, .rd_val: 1},
605 {.inst: 0xA2219253, .name: "FLT_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 0},
606 {.inst: 0xA2218253, .name: "FLE_D", .rs1_val: 0.4, .rs2_val: 0.5, .rd_val: 1},
607 {.inst: 0xA2218253, .name: "FLE_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 1},
608 {.inst: 0x4221F243, .name: "FMADD_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 0.75},
609 {.inst: 0x4221F247, .name: "FMSUB_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: -0.25},
610 {.inst: 0x4221F24B, .name: "FNMSUB_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: 0.25},
611 {.inst: 0x4221F24F, .name: "FNMADD_D", .rs1_val: 0.5, .rs2_val: 0.5, .rd_val: -0.75},
612 };
613 for (auto i : tests) {
614 auto decode = this->Decode(inst: i.inst);
615 ASSERT_TRUE(decode.has_value());
616 std::string name = decode->pattern.name;
617 ASSERT_EQ(name, i.name);
618 TestF_D_CalInst(tester: this, inst: *decode, rs1_val: i.rs1_val, rs2_val: i.rs2_val, rd_exp: i.rd_val);
619 }
620}
621
622template <typename T>
623static void TestInverse(RISCVEmulatorTester *tester, uint32_t f_reg,
624 uint32_t x_reg, DecodeResult f2i, DecodeResult i2f,
625 APFloat apf_val) {
626 uint64_t exp_x;
627 if constexpr (std::is_same_v<T, float>)
628 exp_x = uint64_t(apf_val.convertToFloat());
629 if constexpr (std::is_same_v<T, double>)
630 exp_x = uint64_t(apf_val.convertToDouble());
631 T exp_f = T(exp_x);
632
633 // convert float/double to int.
634 tester->fpr.fpr[f_reg] = apf_val.bitcastToAPInt().getZExtValue();
635 ASSERT_TRUE(tester->Execute(f2i, false));
636 ASSERT_EQ(tester->gpr.gpr[x_reg], exp_x);
637
638 // then convert int to float/double back.
639 ASSERT_TRUE(tester->Execute(i2f, false));
640 ASSERT_EQ(tester->fpr.fpr[f_reg],
641 APFloat(exp_f).bitcastToAPInt().getZExtValue());
642}
643
644struct FCVTInst {
645 uint32_t f2i;
646 uint32_t i2f;
647 APFloat data;
648 bool isDouble;
649};
650
651TEST_F(RISCVEmulatorTester, TestFCVT) {
652 std::vector<FCVTInst> tests{
653 // FCVT_W_S and FCVT_S_W
654 {.f2i: 0xC000F0D3, .i2f: 0xD000F0D3, .data: APFloat(12.0f), .isDouble: false},
655 // FCVT_WU_S and FCVT_S_WU
656 {.f2i: 0xC010F0D3, .i2f: 0xD010F0D3, .data: APFloat(12.0f), .isDouble: false},
657 // FCVT_L_S and FCVT_S_L
658 {.f2i: 0xC020F0D3, .i2f: 0xD020F0D3, .data: APFloat(12.0f), .isDouble: false},
659 // FCVT_LU_S and FCVT_S_LU
660 {.f2i: 0xC030F0D3, .i2f: 0xD030F0D3, .data: APFloat(12.0f), .isDouble: false},
661 // FCVT_W_D and FCVT_D_W
662 {.f2i: 0xC200F0D3, .i2f: 0xD200F0D3, .data: APFloat(12.0), .isDouble: true},
663 // FCVT_WU_D and FCVT_D_WU
664 {.f2i: 0xC210F0D3, .i2f: 0xD210F0D3, .data: APFloat(12.0), .isDouble: true},
665 // FCVT_L_D and FCVT_D_L
666 {.f2i: 0xC220F0D3, .i2f: 0xD220F0D3, .data: APFloat(12.0), .isDouble: true},
667 // FCVT_LU_D and FCVT_D_LU
668 {.f2i: 0xC230F0D3, .i2f: 0xD230F0D3, .data: APFloat(12.0), .isDouble: true},
669 };
670 for (auto i : tests) {
671 auto f2i = this->Decode(inst: i.f2i);
672 auto i2f = this->Decode(inst: i.i2f);
673 ASSERT_TRUE(f2i.has_value());
674 ASSERT_TRUE(i2f.has_value());
675 uint32_t f_reg = DecodeRS1(inst: (*f2i).inst);
676 uint32_t x_reg = DecodeRS1(inst: (*i2f).inst);
677 if (i.isDouble)
678 TestInverse<double>(tester: this, f_reg, x_reg, f2i: *f2i, i2f: *i2f, apf_val: i.data);
679 else
680 TestInverse<float>(tester: this, f_reg, x_reg, f2i: *f2i, i2f: *i2f, apf_val: i.data);
681 }
682}
683
684TEST_F(RISCVEmulatorTester, TestFDInverse) {
685 // FCVT_S_D
686 auto d2f = this->Decode(inst: 0x4010F0D3);
687 // FCVT_S_D
688 auto f2d = this->Decode(inst: 0x4200F0D3);
689 ASSERT_TRUE(d2f.has_value());
690 ASSERT_TRUE(f2d.has_value());
691 auto data = APFloat(12.0);
692 uint32_t reg = DecodeRS1(inst: (*d2f).inst);
693 float exp_f = 12.0f;
694 double exp_d = 12.0;
695
696 // double to float
697 this->fpr.fpr[reg] = data.bitcastToAPInt().getZExtValue();
698 ASSERT_TRUE(this->Execute(*d2f, false));
699 ASSERT_EQ(this->fpr.fpr[reg], APFloat(exp_f).bitcastToAPInt().getZExtValue());
700
701 // float to double
702 ASSERT_TRUE(this->Execute(*f2d, false));
703 ASSERT_EQ(this->fpr.fpr[reg], APFloat(exp_d).bitcastToAPInt().getZExtValue());
704}
705
706TEST_F(RISCVEmulatorTester, TestFloatLSInst) {
707 uint32_t FLWInst = 0x1A207; // imm = 0
708 uint32_t FSWInst = 0x21A827; // imm = 16
709
710 APFloat apf(12.0f);
711 uint64_t bits = apf.bitcastToAPInt().getZExtValue();
712
713 *(uint64_t *)this->memory = bits;
714 auto decode = this->Decode(inst: FLWInst);
715 ASSERT_TRUE(decode.has_value());
716 std::string name = decode->pattern.name;
717 ASSERT_EQ(name, "FLW");
718 ASSERT_TRUE(this->Execute(*decode, false));
719 ASSERT_EQ(this->fpr.fpr[DecodeRD(FLWInst)], bits);
720
721 this->fpr.fpr[DecodeRS2(inst: FSWInst)] = bits;
722 decode = this->Decode(inst: FSWInst);
723 ASSERT_TRUE(decode.has_value());
724 name = decode->pattern.name;
725 ASSERT_EQ(name, "FSW");
726 ASSERT_TRUE(this->Execute(*decode, false));
727 ASSERT_EQ(*(uint32_t *)(this->memory + 16), bits);
728}
729
730TEST_F(RISCVEmulatorTester, TestDoubleLSInst) {
731 uint32_t FLDInst = 0x1B207; // imm = 0
732 uint32_t FSDInst = 0x21B827; // imm = 16
733
734 APFloat apf(12.0);
735 uint64_t bits = apf.bitcastToAPInt().getZExtValue();
736
737 *(uint64_t *)this->memory = bits;
738 auto decode = this->Decode(inst: FLDInst);
739 ASSERT_TRUE(decode.has_value());
740 std::string name = decode->pattern.name;
741 ASSERT_EQ(name, "FLD");
742 ASSERT_TRUE(this->Execute(*decode, false));
743 ASSERT_EQ(this->fpr.fpr[DecodeRD(FLDInst)], bits);
744
745 this->fpr.fpr[DecodeRS2(inst: FSDInst)] = bits;
746 decode = this->Decode(inst: FSDInst);
747 ASSERT_TRUE(decode.has_value());
748 name = decode->pattern.name;
749 ASSERT_EQ(name, "FSD");
750 ASSERT_TRUE(this->Execute(*decode, false));
751 ASSERT_EQ(*(uint64_t *)(this->memory + 16), bits);
752}
753
754TEST_F(RISCVEmulatorTester, TestFMV_X_WInst) {
755 auto FMV_X_WInst = 0xE0018253;
756
757 APFloat apf(12.0f);
758 auto exp_bits = apf.bitcastToAPInt().getZExtValue();
759 this->fpr.fpr[DecodeRS1(inst: FMV_X_WInst)] = NanBoxing(val: exp_bits);
760 auto decode = this->Decode(inst: FMV_X_WInst);
761 ASSERT_TRUE(decode.has_value());
762 std::string name = decode->pattern.name;
763 ASSERT_EQ(name, "FMV_X_W");
764 ASSERT_TRUE(this->Execute(*decode, false));
765 ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_WInst)], exp_bits);
766}
767
768TEST_F(RISCVEmulatorTester, TestFMV_X_DInst) {
769 auto FMV_X_DInst = 0xE2018253;
770
771 APFloat apf(12.0);
772 auto exp_bits = apf.bitcastToAPInt().getZExtValue();
773 this->fpr.fpr[DecodeRS1(inst: FMV_X_DInst)] = exp_bits;
774 auto decode = this->Decode(inst: FMV_X_DInst);
775 ASSERT_TRUE(decode.has_value());
776 std::string name = decode->pattern.name;
777 ASSERT_EQ(name, "FMV_X_D");
778 ASSERT_TRUE(this->Execute(*decode, false));
779 ASSERT_EQ(this->gpr.gpr[DecodeRD(FMV_X_DInst)], exp_bits);
780}
781
782TEST_F(RISCVEmulatorTester, TestFMV_W_XInst) {
783 auto FMV_W_XInst = 0xF0018253;
784
785 APFloat apf(12.0f);
786 uint64_t exp_bits = NanUnBoxing(val: apf.bitcastToAPInt().getZExtValue());
787 this->gpr.gpr[DecodeRS1(inst: FMV_W_XInst)] = exp_bits;
788 auto decode = this->Decode(inst: FMV_W_XInst);
789 ASSERT_TRUE(decode.has_value());
790 std::string name = decode->pattern.name;
791 ASSERT_EQ(name, "FMV_W_X");
792 ASSERT_TRUE(this->Execute(*decode, false));
793 ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_W_XInst)], exp_bits);
794}
795
796TEST_F(RISCVEmulatorTester, TestFMV_D_XInst) {
797 auto FMV_D_XInst = 0xF2018253;
798
799 APFloat apf(12.0);
800 uint64_t bits = apf.bitcastToAPInt().getZExtValue();
801 this->gpr.gpr[DecodeRS1(inst: FMV_D_XInst)] = bits;
802 auto decode = this->Decode(inst: FMV_D_XInst);
803 ASSERT_TRUE(decode.has_value());
804 std::string name = decode->pattern.name;
805 ASSERT_EQ(name, "FMV_D_X");
806 ASSERT_TRUE(this->Execute(*decode, false));
807 ASSERT_EQ(this->fpr.fpr[DecodeRD(FMV_D_XInst)], bits);
808}
809

source code of lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp