xref: /llvm-project/lldb/unittests/Instruction/RISCV/TestRISCVEmulator.cpp (revision 0ef58c66c6e4652ff3582bf0972673708afb912e)
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 
22 using namespace llvm;
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 struct RISCVEmulatorTester : public EmulateInstructionRISCV, testing::Test {
27   RegisterInfoPOSIX_riscv64::GPR gpr;
28   RegisterInfoPOSIX_riscv64::FPR fpr;
29   uint8_t memory[1024] = {0};
30 
RISCVEmulatorTesterRISCVEmulatorTester31   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 
ReadRegisterCallbackRISCVEmulatorTester40   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(0, reg_info->byte_size);
47     if (reg >= gpr_pc_riscv && reg <= gpr_x31_riscv)
48       reg_value.SetUInt(tester->gpr.gpr[reg], reg_info->byte_size);
49     if (reg >= fpr_f0_riscv && reg <= fpr_f31_riscv)
50       reg_value.SetUInt(tester->fpr.fpr[reg - fpr_f0_riscv],
51                         reg_info->byte_size);
52     if (reg == fpr_fcsr_riscv)
53       reg_value.SetUInt(tester->fpr.fcsr, reg_info->byte_size);
54     return true;
55   }
56 
WriteRegisterCallbackRISCVEmulatorTester57   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 
ReadMemoryCallbackRISCVEmulatorTester72   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(dst, tester->memory + addr, length);
78     return length;
79   };
80 
WriteMemoryCallbackRISCVEmulatorTester81   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(tester->memory + addr, dst, length);
88     return length;
89   };
90 
DecodeAndExecuteRISCVEmulatorTester91   bool DecodeAndExecute(uint32_t inst, bool ignore_cond) {
92     return llvm::transformOptional(
93                Decode(inst),
94                [&](DecodeResult res) { return Execute(res, ignore_cond); })
95         .value_or(false);
96   }
97 
ClearAllRISCVEmulatorTester98   void ClearAll() {
99     memset(&gpr, 0, sizeof(gpr));
100     memset(&fpr, 0, sizeof(fpr));
101     memset(memory, 0, sizeof(memory));
102   }
103 };
104 
TEST_F(RISCVEmulatorTester,testJAL)105 TEST_F(RISCVEmulatorTester, testJAL) {
106   addr_t old_pc = 0x114514;
107   WritePC(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 
EncodeIType(uint32_t opcode,uint32_t funct3,uint32_t rd,uint32_t rs1,uint32_t imm)118 constexpr 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 
EncodeJALR(uint32_t rd,uint32_t rs1,int32_t offset)123 constexpr uint32_t EncodeJALR(uint32_t rd, uint32_t rs1, int32_t offset) {
124   return EncodeIType(0b1100111, 0, rd, rs1, uint32_t(offset));
125 }
126 
TEST_F(RISCVEmulatorTester,testJALR)127 TEST_F(RISCVEmulatorTester, testJALR) {
128   addr_t old_pc = 0x114514;
129   addr_t old_x2 = 0x1024;
130   WritePC(old_pc);
131   gpr.gpr[2] = old_x2;
132   // jalr x1, x2(-255)
133   uint32_t inst = EncodeJALR(1, 2, -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 
EncodeBType(uint32_t opcode,uint32_t funct3,uint32_t rs1,uint32_t rs2,uint32_t imm)143 constexpr 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 
BEQ(uint32_t rs1,uint32_t rs2,int32_t offset)151 constexpr uint32_t BEQ(uint32_t rs1, uint32_t rs2, int32_t offset) {
152   return EncodeBType(0b1100011, 0b000, rs1, rs2, uint32_t(offset));
153 }
154 
BNE(uint32_t rs1,uint32_t rs2,int32_t offset)155 constexpr uint32_t BNE(uint32_t rs1, uint32_t rs2, int32_t offset) {
156   return EncodeBType(0b1100011, 0b001, rs1, rs2, uint32_t(offset));
157 }
158 
BLT(uint32_t rs1,uint32_t rs2,int32_t offset)159 constexpr uint32_t BLT(uint32_t rs1, uint32_t rs2, int32_t offset) {
160   return EncodeBType(0b1100011, 0b100, rs1, rs2, uint32_t(offset));
161 }
162 
BGE(uint32_t rs1,uint32_t rs2,int32_t offset)163 constexpr uint32_t BGE(uint32_t rs1, uint32_t rs2, int32_t offset) {
164   return EncodeBType(0b1100011, 0b101, rs1, rs2, uint32_t(offset));
165 }
166 
BLTU(uint32_t rs1,uint32_t rs2,int32_t offset)167 constexpr uint32_t BLTU(uint32_t rs1, uint32_t rs2, int32_t offset) {
168   return EncodeBType(0b1100011, 0b110, rs1, rs2, uint32_t(offset));
169 }
170 
BGEU(uint32_t rs1,uint32_t rs2,int32_t offset)171 constexpr uint32_t BGEU(uint32_t rs1, uint32_t rs2, int32_t offset) {
172   return EncodeBType(0b1100011, 0b111, rs1, rs2, uint32_t(offset));
173 }
174 
175 using EncoderB = uint32_t (*)(uint32_t rs1, uint32_t rs2, int32_t offset);
176 
testBranch(RISCVEmulatorTester * tester,EncoderB encoder,bool branched,uint64_t rs1,uint64_t rs2)177 static 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(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 
CheckRD(RISCVEmulatorTester * tester,uint64_t rd,uint64_t value)200 static void CheckRD(RISCVEmulatorTester *tester, uint64_t rd, uint64_t value) {
201   ASSERT_EQ(tester->gpr.gpr[rd], value);
202 }
203 
204 template <typename T>
CheckMem(RISCVEmulatorTester * tester,uint64_t addr,uint64_t value)205 static 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 
212 using RS1 = uint64_t;
213 using RS2 = uint64_t;
214 using PC = uint64_t;
215 using RDComputer = std::function<uint64_t(RS1, RS2, PC)>;
216 
TestInst(RISCVEmulatorTester * tester,DecodeResult inst,bool has_rs2,RDComputer rd_val)217 static void TestInst(RISCVEmulatorTester *tester, DecodeResult inst,
218                      bool has_rs2, RDComputer rd_val) {
219 
220   addr_t old_pc = 0x114514;
221   tester->WritePC(old_pc);
222   uint32_t rd = DecodeRD(inst.inst);
223   uint32_t rs1 = DecodeRS1(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);
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, rd_val(rs1_val, rs2 ? rs2_val : 0, old_pc));
243 }
244 
245 template <typename T>
TestAtomic(RISCVEmulatorTester * tester,uint64_t inst,T rs1_val,T rs2_val,T rd_expected,T mem_expected)246 static 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 
TEST_F(RISCVEmulatorTester,TestAtomicSequence)269 TEST_F(RISCVEmulatorTester, TestAtomicSequence) {
270   this->WritePC(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 
279 struct TestDecode {
280   uint32_t inst;
281   RISCVInst inst_type;
282 };
283 
TEST_F(RISCVEmulatorTester,TestCDecode)284 TEST_F(RISCVEmulatorTester, TestCDecode) {
285   std::vector<TestDecode> tests = {
286       {0x0000, INVALID{0x0000}},
287       {0x0010, RESERVED{0x0010}},
288       // ADDI4SPN here, decode as ADDI
289       {0x0024, ADDI{Rd{9}, Rs{2}, 8}},
290       {0x2084, FLD{Rd{9}, Rs{9}, 0}},
291       {0x4488, LW{Rd{10}, Rs{9}, 8}},
292       {0x6488, LD{Rd{10}, Rs{9}, 8}},
293       {0xA084, FSD{Rs{9}, Rs{9}, 0}},
294       {0xC488, SW{Rs{9}, Rs{10}, 8}},
295       {0xE488, SD{Rs{9}, Rs{10}, 8}},
296       {0x1001, NOP{0x1001}},
297       {0x1085, ADDI{Rd{1}, Rs{1}, uint32_t(-31)}},
298       {0x2081, ADDIW{Rd{1}, Rs{1}, 0}},
299       // ADDI16SP here, decode as ADDI
300       {0x7101, ADDI{Rd{2}, Rs{2}, uint32_t(-512)}},
301       {0x4081, ADDI{Rd{1}, Rs{0}, 0}},
302       {0x7081, LUI{Rd{1}, uint32_t(-131072)}},
303       {0x8085, SRLI{Rd{9}, Rs{9}, 1}},
304       {0x8485, SRAI{Rd{9}, Rs{9}, 1}},
305       {0x8881, ANDI{Rd{9}, Rs{9}, 0}},
306       {0x8C85, SUB{Rd{9}, Rs{9}, Rs{9}}},
307       {0x8CA5, XOR{Rd{9}, Rs{9}, Rs{9}}},
308       {0x8CC5, OR{Rd{9}, Rs{9}, Rs{9}}},
309       {0x8CE5, AND{Rd{9}, Rs{9}, Rs{9}}},
310       {0x9C85, SUBW{Rd{9}, Rs{9}, Rs{9}}},
311       {0x9CA5, ADDW{Rd{9}, Rs{9}, Rs{9}}},
312       // C.J here, decoded as JAL
313       {0xA001, JAL{Rd{0}, 0}},
314       {0xC081, B{Rs{9}, Rs{0}, 0, 0b000}},
315       {0xE081, B{Rs{9}, Rs{0}, 0, 0b001}},
316       {0x1082, SLLI{Rd{1}, Rs{1}, 32}},
317       {0x1002, HINT{0x1002}},
318       // SLLI64 here, decoded as HINT if not in RV128
319       {0x0082, HINT{0x0082}},
320       // FLDSP here, decoded as FLD
321       {0x2082, FLD{Rd{1}, Rs{2}, 0}},
322       // LWSP here, decoded as LW
323       {0x4082, LW{Rd{1}, Rs{2}, 0}},
324       // LDSP here, decoded as LD
325       {0x6082, LD{Rd{1}, Rs{2}, 0}},
326       // C.JR here, decoded as JALR
327       {0x8082, JALR{Rd{0}, Rs{1}, 0}},
328       // C.MV here, decoded as ADD
329       {0x8086, ADD{Rd{1}, Rs{0}, Rs{1}}},
330       {0x9002, EBREAK{0x9002}},
331       {0x9082, JALR{Rd{1}, Rs{1}, 0}},
332       {0x9086, ADD{Rd{1}, Rs{1}, Rs{1}}},
333       // C.FSDSP here, decoded as FSD
334       {0xA006, FSD{Rs{2}, Rs{1}, 0}},
335       // C.SWSP here, decoded as SW
336       {0xC006, SW{Rs{2}, Rs{1}, 0}},
337       // C.SDSP here, decoded as SD
338       {0xE006, SD{Rs{2}, Rs{1}, 0}},
339   };
340 
341   for (auto i : tests) {
342     auto decode = this->Decode(i.inst);
343     ASSERT_TRUE(decode.has_value());
344     ASSERT_EQ(decode->decoded, i.inst_type);
345   }
346 }
347 
348 class RISCVEmulatorTester32 : public RISCVEmulatorTester {
349 public:
RISCVEmulatorTester32()350   RISCVEmulatorTester32() : RISCVEmulatorTester("riscv32-unknown-linux-gnu") {}
351 };
352 
TEST_F(RISCVEmulatorTester32,TestCDecodeRV32)353 TEST_F(RISCVEmulatorTester32, TestCDecodeRV32) {
354   std::vector<TestDecode> tests = {
355       {0x6002, FLW{Rd{0}, Rs{2}, 0}},
356       {0xE006, FSW{Rs{2}, Rs{1}, 0}},
357       {0x6000, FLW{Rd{8}, Rs{8}, 0}},
358       {0xE000, FSW{Rs{8}, Rs{8}, 0}},
359 
360       {0x2084, FLD{Rd{9}, Rs{9}, 0}},
361       {0xA084, FSD{Rs{9}, Rs{9}, 0}},
362       {0x2082, FLD{Rd{1}, Rs{2}, 0}},
363       {0xA006, FSD{Rs{2}, Rs{1}, 0}},
364   };
365 
366   for (auto i : tests) {
367     auto decode = this->Decode(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`
376 GEN_BRANCH_TEST(BEQ, 1, 1, 0)
377 GEN_BRANCH_TEST(BNE, 1, 0, 1)
378 GEN_BRANCH_TEST(BLT, -2, 1, -3)
379 GEN_BRANCH_TEST(BGE, -2, -3, 1)
380 GEN_BRANCH_TEST(BLTU, -2, -1, 1)
381 GEN_BRANCH_TEST(BGEU, -2, 1, -1)
382 
383 struct TestData {
384   uint32_t inst;
385   std::string name;
386   bool has_rs2;
387   RDComputer rd_val;
388 };
389 
TEST_F(RISCVEmulatorTester,TestDecodeAndExcute)390 TEST_F(RISCVEmulatorTester, TestDecodeAndExcute) {
391   std::vector<TestData> tests = {
392       // RV32I & RV64I Tests
393       {0x00010113, "ADDI", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
394       {0x00023517, "AUIPC", false, [](RS1, RS2, PC pc) { return pc + 143360; }},
395       {0x0006079b, "ADDIW", false, [](RS1 rs1, RS2, PC) { return rs1 + 0; }},
396       {0x00110837, "LUI", false, [](RS1, RS2, PC pc) { return 1114112; }},
397       {0x00147513, "ANDI", false, [](RS1 rs1, RS2, PC) { return rs1 & 1; }},
398       {0x00153513, "SLTIU", false, [](RS1 rs1, RS2, PC) { return 0; }},
399       {0x00256513, "ORI", false, [](RS1 rs1, RS2, PC) { return rs1 | 2; }},
400       {0x00451a13, "SLLI", false, [](RS1 rs1, RS2, PC) { return rs1 << 4; }},
401       {0x00455693, "SRLI", false, [](RS1 rs1, RS2, PC) { return rs1 >> 4; }},
402       {0x00a035b3, "SLTU", true, [](RS1 rs1, RS2 rs2, PC) { return rs2 != 0; }},
403       {0x00b50633, "ADD", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 + rs2; }},
404       {0x40d507b3, "SUB", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 - rs2; }},
405 
406       // RV32M & RV64M Tests
407       {0x02f787b3, "MUL", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 * rs2; }},
408       {0x2F797B3, "MULH", true, [](RS1 rs1, RS2 rs2, PC) { return 0; }},
409       {0x2F7A7B3, "MULHSU", true, [](RS1 rs1, RS2 rs2, PC) { return 0; }},
410       {0x2F7B7B3, "MULHU", true, [](RS1 rs1, RS2 rs2, PC) { return 0; }},
411       {0x02f747b3, "DIV", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
412       {0x02f757b3, "DIVU", true,
413        [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
414       {0x02f767b3, "REM", true, [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
415       {0x02f777b3, "REMU", true,
416        [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
417       {0x02f787bb, "MULW", true,
418        [](RS1 rs1, RS2 rs2, PC) { return rs1 * rs2; }},
419       {0x02f747bb, "DIVW", true,
420        [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
421       {0x02f757bb, "DIVUW", true,
422        [](RS1 rs1, RS2 rs2, PC) { return rs1 / rs2; }},
423       {0x02f767bb, "REMW", true,
424        [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
425       {0x02f777bb, "REMUW", true,
426        [](RS1 rs1, RS2 rs2, PC) { return rs1 % rs2; }},
427   };
428   for (auto i : tests) {
429     auto decode = this->Decode(i.inst);
430     ASSERT_TRUE(decode.has_value());
431     std::string name = decode->pattern.name;
432     ASSERT_EQ(name, i.name);
433     TestInst(this, *decode, i.has_rs2, i.rd_val);
434   }
435 }
436 
TEST_F(RISCVEmulatorTester,TestAMOSWAP)437 TEST_F(RISCVEmulatorTester, TestAMOSWAP) {
438   TestAtomic<uint32_t>(this, 0x8F7282F, 0x1, 0x2, 0x1, 0x2);
439   TestAtomic<uint64_t>(this, 0x8F7382F, 0x1, 0x2, 0x1, 0x2);
440 }
441 
TEST_F(RISCVEmulatorTester,TestAMOADD)442 TEST_F(RISCVEmulatorTester, TestAMOADD) {
443   TestAtomic<uint32_t>(this, 0xF7282F, 0x1, 0x2, 0x1, 0x3);
444   TestAtomic<uint64_t>(this, 0xF7382F, 0x1, 0x2, 0x1, 0x3);
445 }
446 
TEST_F(RISCVEmulatorTester,TestAMOXOR)447 TEST_F(RISCVEmulatorTester, TestAMOXOR) {
448   TestAtomic<uint32_t>(this, 0x20F7282F, 0x1, 0x2, 0x1, 0x3);
449   TestAtomic<uint32_t>(this, 0x20F7382F, 0x1, 0x2, 0x1, 0x3);
450 }
451 
TEST_F(RISCVEmulatorTester,TestAMOAND)452 TEST_F(RISCVEmulatorTester, TestAMOAND) {
453   TestAtomic<uint32_t>(this, 0x60F7282F, 0x1, 0x2, 0x1, 0x0);
454   TestAtomic<uint64_t>(this, 0x60F7382F, 0x1, 0x2, 0x1, 0x0);
455 }
456 
TEST_F(RISCVEmulatorTester,TestAMOOR)457 TEST_F(RISCVEmulatorTester, TestAMOOR) {
458   TestAtomic<uint32_t>(this, 0x40F7282F, 0x1, 0x2, 0x1, 0x3);
459   TestAtomic<uint32_t>(this, 0x40F7382F, 0x1, 0x2, 0x1, 0x3);
460 }
461 
TEST_F(RISCVEmulatorTester,TestAMOMIN)462 TEST_F(RISCVEmulatorTester, TestAMOMIN) {
463   TestAtomic<uint32_t>(this, 0x80F7282F, 0x1, 0x2, 0x1, 0x1);
464   TestAtomic<uint64_t>(this, 0x80F7382F, 0x1, 0x2, 0x1, 0x1);
465 }
466 
TEST_F(RISCVEmulatorTester,TestAMOMAX)467 TEST_F(RISCVEmulatorTester, TestAMOMAX) {
468   TestAtomic<uint32_t>(this, 0xA0F7282F, 0x1, 0x2, 0x1, 0x2);
469   TestAtomic<uint64_t>(this, 0xA0F7382F, 0x1, 0x2, 0x1, 0x2);
470 }
471 
TEST_F(RISCVEmulatorTester,TestAMOMINU)472 TEST_F(RISCVEmulatorTester, TestAMOMINU) {
473   TestAtomic<uint32_t>(this, 0xC0F7282F, 0x1, 0x2, 0x1, 0x1);
474   TestAtomic<uint64_t>(this, 0xC0F7382F, 0x1, 0x2, 0x1, 0x1);
475 }
476 
TEST_F(RISCVEmulatorTester,TestAMOMAXU)477 TEST_F(RISCVEmulatorTester, TestAMOMAXU) {
478   TestAtomic<uint32_t>(this, 0xE0F7282F, 0x1, 0x2, 0x1, 0x2);
479   TestAtomic<uint64_t>(this, 0xE0F7382F, 0x1, 0x2, 0x1, 0x2);
480 }
481 
482 template <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 
490 using FloatCalInst = F_D_CalInst<float>;
491 using DoubleCalInst = F_D_CalInst<double>;
492 
493 template <typename T>
TestF_D_CalInst(RISCVEmulatorTester * tester,DecodeResult inst,T rs1_val,T rs2_val,T rd_exp)494 static 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);
503   uint32_t rs1 = DecodeRS1(inst.inst);
504   uint32_t rs2 = DecodeRS2(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);
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 
TEST_F(RISCVEmulatorTester,TestFloatInst)546 TEST_F(RISCVEmulatorTester, TestFloatInst) {
547   std::vector<FloatCalInst> tests = {
548       {0x21F253, "FADD_S", 0.5f, 0.5f, 1.0f},
549       {0x821F253, "FSUB_S", 1.0f, 0.5f, 0.5f},
550       {0x1021F253, "FMUL_S", 0.5f, 0.5f, 0.25f},
551       {0x1821F253, "FDIV_S", 0.1f, 0.1f, 1.0f},
552       {0x20218253, "FSGNJ_S", 0.5f, 0.2f, 0.5f},
553       {0x20219253, "FSGNJN_S", 0.5f, -1.0f, 0.5f},
554       {0x2021A253, "FSGNJX_S", -0.5f, -0.5f, 0.5f},
555       {0x2021A253, "FSGNJX_S", -0.5f, 0.5f, -0.5f},
556       {0x28218253, "FMIN_S", -0.5f, 0.5f, -0.5f},
557       {0x28218253, "FMIN_S", -0.5f, -0.6f, -0.6f},
558       {0x28218253, "FMIN_S", 0.5f, 0.6f, 0.5f},
559       {0x28219253, "FMAX_S", -0.5f, -0.6f, -0.5f},
560       {0x28219253, "FMAX_S", 0.5f, 0.6f, 0.6f},
561       {0x28219253, "FMAX_S", 0.5f, -0.6f, 0.5f},
562       {0xA021A253, "FEQ_S", 0.5f, 0.5f, 1},
563       {0xA021A253, "FEQ_S", 0.5f, -0.5f, 0},
564       {0xA021A253, "FEQ_S", -0.5f, 0.5f, 0},
565       {0xA021A253, "FEQ_S", 0.4f, 0.5f, 0},
566       {0xA0219253, "FLT_S", 0.4f, 0.5f, 1},
567       {0xA0219253, "FLT_S", 0.5f, 0.5f, 0},
568       {0xA0218253, "FLE_S", 0.4f, 0.5f, 1},
569       {0xA0218253, "FLE_S", 0.5f, 0.5f, 1},
570       {0x4021F243, "FMADD_S", 0.5f, 0.5f, 0.75f},
571       {0x4021F247, "FMSUB_S", 0.5f, 0.5f, -0.25f},
572       {0x4021F24B, "FNMSUB_S", 0.5f, 0.5f, 0.25f},
573       {0x4021F24F, "FNMADD_S", 0.5f, 0.5f, -0.75f},
574   };
575   for (auto i : tests) {
576     auto decode = this->Decode(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(this, *decode, i.rs1_val, i.rs2_val, i.rd_val);
581   }
582 }
583 
TEST_F(RISCVEmulatorTester,TestDoubleInst)584 TEST_F(RISCVEmulatorTester, TestDoubleInst) {
585   std::vector<DoubleCalInst> tests = {
586       {0x221F253, "FADD_D", 0.5, 0.5, 1.0},
587       {0xA21F253, "FSUB_D", 1.0, 0.5, 0.5},
588       {0x1221F253, "FMUL_D", 0.5, 0.5, 0.25},
589       {0x1A21F253, "FDIV_D", 0.1, 0.1, 1.0},
590       {0x22218253, "FSGNJ_D", 0.5, 0.2, 0.5},
591       {0x22219253, "FSGNJN_D", 0.5, -1.0, 0.5},
592       {0x2221A253, "FSGNJX_D", -0.5, -0.5, 0.5},
593       {0x2221A253, "FSGNJX_D", -0.5, 0.5, -0.5},
594       {0x2A218253, "FMIN_D", -0.5, 0.5, -0.5},
595       {0x2A218253, "FMIN_D", -0.5, -0.6, -0.6},
596       {0x2A218253, "FMIN_D", 0.5, 0.6, 0.5},
597       {0x2A219253, "FMAX_D", -0.5, -0.6, -0.5},
598       {0x2A219253, "FMAX_D", 0.5, 0.6, 0.6},
599       {0x2A219253, "FMAX_D", 0.5, -0.6, 0.5},
600       {0xA221A253, "FEQ_D", 0.5, 0.5, 1},
601       {0xA221A253, "FEQ_D", 0.5, -0.5, 0},
602       {0xA221A253, "FEQ_D", -0.5, 0.5, 0},
603       {0xA221A253, "FEQ_D", 0.4, 0.5, 0},
604       {0xA2219253, "FLT_D", 0.4, 0.5, 1},
605       {0xA2219253, "FLT_D", 0.5, 0.5, 0},
606       {0xA2218253, "FLE_D", 0.4, 0.5, 1},
607       {0xA2218253, "FLE_D", 0.5, 0.5, 1},
608       {0x4221F243, "FMADD_D", 0.5, 0.5, 0.75},
609       {0x4221F247, "FMSUB_D", 0.5, 0.5, -0.25},
610       {0x4221F24B, "FNMSUB_D", 0.5, 0.5, 0.25},
611       {0x4221F24F, "FNMADD_D", 0.5, 0.5, -0.75},
612   };
613   for (auto i : tests) {
614     auto decode = this->Decode(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(this, *decode, i.rs1_val, i.rs2_val, i.rd_val);
619   }
620 }
621 
622 template <typename T>
TestInverse(RISCVEmulatorTester * tester,uint32_t f_reg,uint32_t x_reg,DecodeResult f2i,DecodeResult i2f,APFloat apf_val)623 static 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 
644 struct FCVTInst {
645   uint32_t f2i;
646   uint32_t i2f;
647   APFloat data;
648   bool isDouble;
649 };
650 
TEST_F(RISCVEmulatorTester,TestFCVT)651 TEST_F(RISCVEmulatorTester, TestFCVT) {
652   std::vector<FCVTInst> tests{
653       // FCVT_W_S and FCVT_S_W
654       {0xC000F0D3, 0xD000F0D3, APFloat(12.0f), false},
655       // FCVT_WU_S and FCVT_S_WU
656       {0xC010F0D3, 0xD010F0D3, APFloat(12.0f), false},
657       // FCVT_L_S and FCVT_S_L
658       {0xC020F0D3, 0xD020F0D3, APFloat(12.0f), false},
659       // FCVT_LU_S and FCVT_S_LU
660       {0xC030F0D3, 0xD030F0D3, APFloat(12.0f), false},
661       // FCVT_W_D and FCVT_D_W
662       {0xC200F0D3, 0xD200F0D3, APFloat(12.0), true},
663       // FCVT_WU_D and FCVT_D_WU
664       {0xC210F0D3, 0xD210F0D3, APFloat(12.0), true},
665       // FCVT_L_D and FCVT_D_L
666       {0xC220F0D3, 0xD220F0D3, APFloat(12.0), true},
667       // FCVT_LU_D and FCVT_D_LU
668       {0xC230F0D3, 0xD230F0D3, APFloat(12.0), true},
669   };
670   for (auto i : tests) {
671     auto f2i = this->Decode(i.f2i);
672     auto i2f = this->Decode(i.i2f);
673     ASSERT_TRUE(f2i.has_value());
674     ASSERT_TRUE(i2f.has_value());
675     uint32_t f_reg = DecodeRS1((*f2i).inst);
676     uint32_t x_reg = DecodeRS1((*i2f).inst);
677     if (i.isDouble)
678       TestInverse<double>(this, f_reg, x_reg, *f2i, *i2f, i.data);
679     else
680       TestInverse<float>(this, f_reg, x_reg, *f2i, *i2f, i.data);
681   }
682 }
683 
TEST_F(RISCVEmulatorTester,TestFDInverse)684 TEST_F(RISCVEmulatorTester, TestFDInverse) {
685   // FCVT_S_D
686   auto d2f = this->Decode(0x4010F0D3);
687   // FCVT_S_D
688   auto f2d = this->Decode(0x4200F0D3);
689   ASSERT_TRUE(d2f.has_value());
690   ASSERT_TRUE(f2d.has_value());
691   auto data = APFloat(12.0);
692   uint32_t reg = DecodeRS1((*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 
TEST_F(RISCVEmulatorTester,TestFloatLSInst)706 TEST_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(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(FSWInst)] = bits;
722   decode = this->Decode(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 
TEST_F(RISCVEmulatorTester,TestDoubleLSInst)730 TEST_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(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(FSDInst)] = bits;
746   decode = this->Decode(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 
TEST_F(RISCVEmulatorTester,TestFMV_X_WInst)754 TEST_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(FMV_X_WInst)] = NanBoxing(exp_bits);
760   auto decode = this->Decode(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 
TEST_F(RISCVEmulatorTester,TestFMV_X_DInst)768 TEST_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(FMV_X_DInst)] = exp_bits;
774   auto decode = this->Decode(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 
TEST_F(RISCVEmulatorTester,TestFMV_W_XInst)782 TEST_F(RISCVEmulatorTester, TestFMV_W_XInst) {
783   auto FMV_W_XInst = 0xF0018253;
784 
785   APFloat apf(12.0f);
786   uint64_t exp_bits = NanUnBoxing(apf.bitcastToAPInt().getZExtValue());
787   this->gpr.gpr[DecodeRS1(FMV_W_XInst)] = exp_bits;
788   auto decode = this->Decode(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 
TEST_F(RISCVEmulatorTester,TestFMV_D_XInst)796 TEST_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(FMV_D_XInst)] = bits;
802   auto decode = this->Decode(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