brintos

brintos / llvm-project-archived public Read only

0
0
Text · 28.1 KiB · 90d5a7c Raw
809 lines · cpp
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-exception6//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(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 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(dst, tester->memory + addr, 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(tester->memory + addr, dst, length);88    return length;89  };90 91  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 98  void ClearAll() {99    memset(&gpr, 0, sizeof(gpr));100    memset(&fpr, 0, sizeof(fpr));101    memset(memory, 0, sizeof(memory));102  }103};104 105TEST_F(RISCVEmulatorTester, testJAL) {106  addr_t old_pc = 0x114514;107  WritePC(old_pc);108  // jal x1, -6*4109  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(0b1100111, 0, rd, rs1, uint32_t(offset));125}126 127TEST_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 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(0b1100011, 0b000, rs1, rs2, uint32_t(offset));153}154 155constexpr uint32_t BNE(uint32_t rs1, uint32_t rs2, int32_t offset) {156  return EncodeBType(0b1100011, 0b001, rs1, rs2, uint32_t(offset));157}158 159constexpr uint32_t BLT(uint32_t rs1, uint32_t rs2, int32_t offset) {160  return EncodeBType(0b1100011, 0b100, rs1, rs2, uint32_t(offset));161}162 163constexpr uint32_t BGE(uint32_t rs1, uint32_t rs2, int32_t offset) {164  return EncodeBType(0b1100011, 0b101, rs1, rs2, uint32_t(offset));165}166 167constexpr uint32_t BLTU(uint32_t rs1, uint32_t rs2, int32_t offset) {168  return EncodeBType(0b1100011, 0b110, rs1, rs2, uint32_t(offset));169}170 171constexpr uint32_t BGEU(uint32_t rs1, uint32_t rs2, int32_t offset) {172  return EncodeBType(0b1100011, 0b111, rs1, rs2, 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 registers180  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 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(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 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 rs2249 250  uint32_t rd = DecodeRD(inst);251  uint32_t rs1 = DecodeRS1(inst);252  uint32_t rs2 = DecodeRS2(inst);253 254  // addr was stored in rs1255  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_addr261  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(0x0);271  *(uint32_t *)this->memory = 0x100427af;        // lr.w	a5,(s0)272  *(uint32_t *)(this->memory + 4) = 0x00079663;  // bnez	a5,12273  *(uint32_t *)(this->memory + 8) = 0x1ce426af;  // sc.w.aq	a3,a4,(s0)274  *(uint32_t *)(this->memory + 12) = 0xfe069ae3; // bnez	a3,-12275  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      {0x0000, INVALID{0x0000}},287      {0x0010, RESERVED{0x0010}},288      // ADDI4SPN here, decode as ADDI289      {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 ADDI300      {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 JAL313      {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 RV128319      {0x0082, HINT{0x0082}},320      // FLDSP here, decoded as FLD321      {0x2082, FLD{Rd{1}, Rs{2}, 0}},322      // LWSP here, decoded as LW323      {0x4082, LW{Rd{1}, Rs{2}, 0}},324      // LDSP here, decoded as LD325      {0x6082, LD{Rd{1}, Rs{2}, 0}},326      // C.JR here, decoded as JALR327      {0x8082, JALR{Rd{0}, Rs{1}, 0}},328      // C.MV here, decoded as ADD329      {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 FSD334      {0xA006, FSD{Rs{2}, Rs{1}, 0}},335      // C.SWSP here, decoded as SW336      {0xC006, SW{Rs{2}, Rs{1}, 0}},337      // C.SDSP here, decoded as SD338      {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 348class RISCVEmulatorTester32 : public RISCVEmulatorTester {349public:350  RISCVEmulatorTester32() : RISCVEmulatorTester("riscv32-unknown-linux-gnu") {}351};352 353TEST_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`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 Tests393      {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 Tests407      {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 437TEST_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 442TEST_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 447TEST_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 452TEST_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 457TEST_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 462TEST_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 467TEST_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 472TEST_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 477TEST_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 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);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 546TEST_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 584TEST_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 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_W654      {0xC000F0D3, 0xD000F0D3, APFloat(12.0f), false},655      // FCVT_WU_S and FCVT_S_WU656      {0xC010F0D3, 0xD010F0D3, APFloat(12.0f), false},657      // FCVT_L_S and FCVT_S_L658      {0xC020F0D3, 0xD020F0D3, APFloat(12.0f), false},659      // FCVT_LU_S and FCVT_S_LU660      {0xC030F0D3, 0xD030F0D3, APFloat(12.0f), false},661      // FCVT_W_D and FCVT_D_W662      {0xC200F0D3, 0xD200F0D3, APFloat(12.0), true},663      // FCVT_WU_D and FCVT_D_WU664      {0xC210F0D3, 0xD210F0D3, APFloat(12.0), true},665      // FCVT_L_D and FCVT_D_L666      {0xC220F0D3, 0xD220F0D3, APFloat(12.0), true},667      // FCVT_LU_D and FCVT_D_LU668      {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    else680      TestInverse<float>(this, f_reg, x_reg, *f2i, *i2f, i.data);681  }682}683 684TEST_F(RISCVEmulatorTester, TestFDInverse) {685  // FCVT_S_D686  auto d2f = this->Decode(0x4010F0D3);687  // FCVT_S_D688  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 float697  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 double702  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 = 0708  uint32_t FSWInst = 0x21A827; // imm = 16709 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 730TEST_F(RISCVEmulatorTester, TestDoubleLSInst) {731  uint32_t FLDInst = 0x1B207;  // imm = 0732  uint32_t FSDInst = 0x21B827; // imm = 16733 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 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(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 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(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 782TEST_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 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(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