1 //===-- TestRISCVEmulator.cpp ---------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "gtest/gtest.h"
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"
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"
24 using namespace lldb_private
;
26 struct RISCVEmulatorTester
: public EmulateInstructionRISCV
, testing::Test
{
27 RegisterInfoPOSIX_riscv64::GPR gpr
;
28 RegisterInfoPOSIX_riscv64::FPR fpr
;
29 uint8_t memory
[1024] = {0};
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
);
40 static bool ReadRegisterCallback(EmulateInstruction
*instruction
, void *baton
,
41 const RegisterInfo
*reg_info
,
42 RegisterValue
®_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
],
52 if (reg
== fpr_fcsr_riscv
)
53 reg_value
.SetUInt(tester
->fpr
.fcsr
, reg_info
->byte_size
);
57 static bool WriteRegisterCallback(EmulateInstruction
*instruction
,
58 void *baton
, const Context
&context
,
59 const RegisterInfo
*reg_info
,
60 const RegisterValue
®_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();
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(dst
, tester
->memory
+ addr
, length
);
81 static size_t WriteMemoryCallback(EmulateInstruction
*instruction
,
82 void *baton
, const Context
&context
,
83 addr_t addr
, const void *dst
,
85 RISCVEmulatorTester
*tester
= (RISCVEmulatorTester
*)instruction
;
86 assert(addr
+ length
< sizeof(tester
->memory
));
87 memcpy(tester
->memory
+ addr
, dst
, length
);
91 bool DecodeAndExecute(uint32_t inst
, bool ignore_cond
) {
92 return llvm::transformOptional(
94 [&](DecodeResult res
) { return Execute(res
, ignore_cond
); })
99 memset(&gpr
, 0, sizeof(gpr
));
100 memset(&fpr
, 0, sizeof(fpr
));
101 memset(memory
, 0, sizeof(memory
));
105 TEST_F(RISCVEmulatorTester
, testJAL
) {
106 addr_t old_pc
= 0x114514;
109 uint32_t inst
= 0b11111110100111111111000011101111;
110 ASSERT_TRUE(DecodeAndExecute(inst
, false));
111 auto x1
= gpr
.gpr
[1];
113 ASSERT_TRUE(pc
.has_value());
114 ASSERT_EQ(x1
, old_pc
+ 4);
115 ASSERT_EQ(*pc
, old_pc
+ (-6 * 4));
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
;
123 constexpr uint32_t EncodeJALR(uint32_t rd
, uint32_t rs1
, int32_t offset
) {
124 return EncodeIType(0b1100111, 0, rd
, rs1
, uint32_t(offset
));
127 TEST_F(RISCVEmulatorTester
, testJALR
) {
128 addr_t old_pc
= 0x114514;
129 addr_t old_x2
= 0x1024;
133 uint32_t inst
= EncodeJALR(1, 2, -255);
134 ASSERT_TRUE(DecodeAndExecute(inst
, false));
135 auto x1
= gpr
.gpr
[1];
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));
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;
148 return rs2
<< 20 | rs1
<< 15 | funct3
<< 12 | opcode
| bimm
;
151 constexpr uint32_t BEQ(uint32_t rs1
, uint32_t rs2
, int32_t offset
) {
152 return EncodeBType(0b1100011, 0b000, rs1
, rs2
, uint32_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
));
159 constexpr uint32_t BLT(uint32_t rs1
, uint32_t rs2
, int32_t offset
) {
160 return EncodeBType(0b1100011, 0b100, rs1
, rs2
, uint32_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
));
167 constexpr uint32_t BLTU(uint32_t rs1
, uint32_t rs2
, int32_t offset
) {
168 return EncodeBType(0b1100011, 0b110, rs1
, rs2
, uint32_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
));
175 using EncoderB
= uint32_t (*)(uint32_t rs1
, uint32_t rs2
, int32_t offset
);
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));
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); \
196 TEST_F(RISCVEmulatorTester, test##name##Continued) { \
197 testBranch(this, name, false, rs1, rs2_continued); \
200 static void CheckRD(RISCVEmulatorTester
*tester
, uint64_t rd
, uint64_t value
) {
201 ASSERT_EQ(tester
->gpr
.gpr
[rd
], value
);
204 template <typename T
>
205 static void CheckMem(RISCVEmulatorTester
*tester
, uint64_t addr
,
207 auto mem
= tester
->ReadMem
<T
>(addr
);
208 ASSERT_TRUE(mem
.has_value());
209 ASSERT_EQ(*mem
, value
);
212 using RS1
= uint64_t;
213 using RS2
= uint64_t;
215 using RDComputer
= std::function
<uint64_t(RS1
, RS2
, PC
)>;
217 static void TestInst(RISCVEmulatorTester
*tester
, DecodeResult inst
,
218 bool has_rs2
, RDComputer rd_val
) {
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
);
226 uint64_t rs1_val
= 0x19;
227 uint64_t rs2_val
= 0x81;
230 tester
->gpr
.gpr
[rs1
] = rs1_val
;
233 rs2
= DecodeRS2(inst
.inst
);
237 tester
->gpr
.gpr
[rs2
] = rs2_val
;
241 ASSERT_TRUE(tester
->Execute(inst
, false));
242 CheckRD(tester
, rd
, rd_val(rs1_val
, rs2
? rs2_val
: 0, old_pc
));
245 template <typename T
>
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
250 uint32_t rd
= DecodeRD(inst
);
251 uint32_t rs1
= DecodeRS1(inst
);
252 uint32_t rs2
= DecodeRS2(inst
);
254 // addr was stored in rs1
255 uint64_t atomic_addr
= 0x100;
257 tester
->gpr
.gpr
[rs1
] = atomic_addr
;
258 tester
->gpr
.gpr
[rs2
] = rs2_val
;
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
);
264 ASSERT_TRUE(tester
->DecodeAndExecute(inst
, false));
265 CheckRD(tester
, rd
, rd_expected
);
266 CheckMem
<T
>(tester
, atomic_addr
, mem_expected
);
269 TEST_F(RISCVEmulatorTester
, TestAtomicSequence
) {
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));
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}},
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
);
348 class RISCVEmulatorTester32
: public RISCVEmulatorTester
{
350 RISCVEmulatorTester32() : RISCVEmulatorTester("riscv32-unknown-linux-gnu") {}
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}},
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}},
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
);
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)
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
; }},
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
; }},
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
);
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);
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);
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);
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);
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);
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);
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);
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);
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);
482 template <typename T
> struct F_D_CalInst
{
490 using FloatCalInst
= F_D_CalInst
<float>;
491 using DoubleCalInst
= F_D_CalInst
<double>;
493 template <typename T
>
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"};
502 uint32_t rd
= DecodeRD(inst
.inst
);
503 uint32_t rs1
= DecodeRS1(inst
.inst
);
504 uint32_t rs2
= DecodeRS2(inst
.inst
);
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);
517 tester
->fpr
.fpr
[rs1
] = ap_rs1_val
.bitcastToAPInt().getZExtValue();
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();
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
);
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
);
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
);
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
},
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
);
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},
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
);
622 template <typename T
>
623 static void TestInverse(RISCVEmulatorTester
*tester
, uint32_t f_reg
,
624 uint32_t x_reg
, DecodeResult f2i
, DecodeResult i2f
,
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());
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
);
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());
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},
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
);
678 TestInverse
<double>(this, f_reg
, x_reg
, *f2i
, *i2f
, i
.data
);
680 TestInverse
<float>(this, f_reg
, x_reg
, *f2i
, *i2f
, i
.data
);
684 TEST_F(RISCVEmulatorTester
, TestFDInverse
) {
686 auto d2f
= this->Decode(0x4010F0D3);
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
);
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());
702 ASSERT_TRUE(this->Execute(*f2d
, false));
703 ASSERT_EQ(this->fpr
.fpr
[reg
], APFloat(exp_d
).bitcastToAPInt().getZExtValue());
706 TEST_F(RISCVEmulatorTester
, TestFloatLSInst
) {
707 uint32_t FLWInst
= 0x1A207; // imm = 0
708 uint32_t FSWInst
= 0x21A827; // imm = 16
711 uint64_t bits
= apf
.bitcastToAPInt().getZExtValue();
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
);
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
);
730 TEST_F(RISCVEmulatorTester
, TestDoubleLSInst
) {
731 uint32_t FLDInst
= 0x1B207; // imm = 0
732 uint32_t FSDInst
= 0x21B827; // imm = 16
735 uint64_t bits
= apf
.bitcastToAPInt().getZExtValue();
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
);
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
);
754 TEST_F(RISCVEmulatorTester
, TestFMV_X_WInst
) {
755 auto FMV_X_WInst
= 0xE0018253;
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
);
768 TEST_F(RISCVEmulatorTester
, TestFMV_X_DInst
) {
769 auto FMV_X_DInst
= 0xE2018253;
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
);
782 TEST_F(RISCVEmulatorTester
, TestFMV_W_XInst
) {
783 auto FMV_W_XInst
= 0xF0018253;
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
);
796 TEST_F(RISCVEmulatorTester
, TestFMV_D_XInst
) {
797 auto FMV_D_XInst
= 0xF2018253;
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
);