mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:51:18 +00:00
Import "Add the ratified portions of the B extension: Zba, Zbb, Zbc, Zbs."
TEST=ci Change-Id: I7676dabc67762c0c2e4a1a9975100c59edcda769 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271441 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
parent
38ac261884
commit
b166d909c3
|
@ -1086,12 +1086,12 @@ void MicroAssembler::fsgnjxs(FRegister rd, FRegister rs1, FRegister rs2) {
|
||||||
|
|
||||||
void MicroAssembler::fmins(FRegister rd, FRegister rs1, FRegister rs2) {
|
void MicroAssembler::fmins(FRegister rd, FRegister rs1, FRegister rs2) {
|
||||||
ASSERT(Supports(RV_F));
|
ASSERT(Supports(RV_F));
|
||||||
EmitRType(FMINMAXS, rs2, rs1, MIN, rd, OPFP);
|
EmitRType(FMINMAXS, rs2, rs1, FMIN, rd, OPFP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroAssembler::fmaxs(FRegister rd, FRegister rs1, FRegister rs2) {
|
void MicroAssembler::fmaxs(FRegister rd, FRegister rs1, FRegister rs2) {
|
||||||
ASSERT(Supports(RV_F));
|
ASSERT(Supports(RV_F));
|
||||||
EmitRType(FMINMAXS, rs2, rs1, MAX, rd, OPFP);
|
EmitRType(FMINMAXS, rs2, rs1, FMAX, rd, OPFP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroAssembler::feqs(Register rd, FRegister rs1, FRegister rs2) {
|
void MicroAssembler::feqs(Register rd, FRegister rs1, FRegister rs2) {
|
||||||
|
@ -1296,12 +1296,12 @@ void MicroAssembler::fsgnjxd(FRegister rd, FRegister rs1, FRegister rs2) {
|
||||||
|
|
||||||
void MicroAssembler::fmind(FRegister rd, FRegister rs1, FRegister rs2) {
|
void MicroAssembler::fmind(FRegister rd, FRegister rs1, FRegister rs2) {
|
||||||
ASSERT(Supports(RV_D));
|
ASSERT(Supports(RV_D));
|
||||||
EmitRType(FMINMAXD, rs2, rs1, MIN, rd, OPFP);
|
EmitRType(FMINMAXD, rs2, rs1, FMIN, rd, OPFP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroAssembler::fmaxd(FRegister rd, FRegister rs1, FRegister rs2) {
|
void MicroAssembler::fmaxd(FRegister rd, FRegister rs1, FRegister rs2) {
|
||||||
ASSERT(Supports(RV_D));
|
ASSERT(Supports(RV_D));
|
||||||
EmitRType(FMINMAXD, rs2, rs1, MAX, rd, OPFP);
|
EmitRType(FMINMAXD, rs2, rs1, FMAX, rd, OPFP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroAssembler::fcvtsd(FRegister rd,
|
void MicroAssembler::fcvtsd(FRegister rd,
|
||||||
|
@ -1398,6 +1398,242 @@ void MicroAssembler::fmvdx(FRegister rd, Register rs1) {
|
||||||
}
|
}
|
||||||
#endif // XLEN >= 64
|
#endif // XLEN >= 64
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
void MicroAssembler::adduw(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(ADDUW, rs2, rs1, F3_0, rd, OP32);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void MicroAssembler::sh1add(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SHADD, rs2, rs1, SH1ADD, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
void MicroAssembler::sh1adduw(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SHADD, rs2, rs1, SH1ADD, rd, OP32);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void MicroAssembler::sh2add(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SHADD, rs2, rs1, SH2ADD, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
void MicroAssembler::sh2adduw(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SHADD, rs2, rs1, SH2ADD, rd, OP32);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void MicroAssembler::sh3add(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SHADD, rs2, rs1, SH3ADD, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
void MicroAssembler::sh3adduw(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SHADD, rs2, rs1, SH3ADD, rd, OP32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::slliuw(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT((shamt > 0) && (shamt < 32));
|
||||||
|
ASSERT(Supports(RV_Zba));
|
||||||
|
EmitRType(SLLIUW, shamt, rs1, SLLI, rd, OPIMM32);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void MicroAssembler::andn(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(SUB, rs2, rs1, AND, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::orn(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(SUB, rs2, rs1, OR, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::xnor(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(SUB, rs2, rs1, XOR, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::clz(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(COUNT, 0b00000, rs1, F3_COUNT, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::clzw(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(COUNT, 0b00000, rs1, F3_COUNT, rd, OPIMM32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::ctz(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(COUNT, 0b00001, rs1, F3_COUNT, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::ctzw(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(COUNT, 0b00001, rs1, F3_COUNT, rd, OPIMM32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::cpop(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(COUNT, 0b00010, rs1, F3_COUNT, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::cpopw(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(COUNT, 0b00010, rs1, F3_COUNT, rd, OPIMM32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::max(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, MAX, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::maxu(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, MAXU, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::min(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, MIN, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::minu(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, MINU, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::sextb(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType((Funct7)0b0110000, 0b00100, rs1, SEXT, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::sexth(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType((Funct7)0b0110000, 0b00101, rs1, SEXT, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::zexth(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
#if XLEN == 32
|
||||||
|
EmitRType((Funct7)0b0000100, 0b00000, rs1, ZEXT, rd, OP);
|
||||||
|
#elif XLEN == 64
|
||||||
|
EmitRType((Funct7)0b0000100, 0b00000, rs1, ZEXT, rd, OP32);
|
||||||
|
#else
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::rol(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(ROTATE, rs2, rs1, ROL, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::rolw(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(ROTATE, rs2, rs1, ROL, rd, OP32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::ror(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(ROTATE, rs2, rs1, ROR, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::rori(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(ROTATE, shamt, rs1, ROR, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::roriw(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(ROTATE, shamt, rs1, ROR, rd, OPIMM32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::rorw(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType(ROTATE, rs2, rs1, ROR, rd, OP32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::orcb(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
EmitRType((Funct7)0b0010100, 0b00111, rs1, (Funct3)0b101, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::rev8(Register rd, Register rs1) {
|
||||||
|
ASSERT(Supports(RV_Zbb));
|
||||||
|
#if XLEN == 32
|
||||||
|
EmitRType((Funct7)0b0110100, 0b11000, rs1, (Funct3)0b101, rd, OPIMM);
|
||||||
|
#elif XLEN == 64
|
||||||
|
EmitRType((Funct7)0b0110101, 0b11000, rs1, (Funct3)0b101, rd, OPIMM);
|
||||||
|
#else
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::clmul(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbc));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, CLMUL, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::clmulh(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbc));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, CLMULH, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::clmulr(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbc));
|
||||||
|
EmitRType(MINMAXCLMUL, rs2, rs1, CLMULR, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::bclr(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BCLRBEXT, rs2, rs1, BCLR, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::bclri(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BCLRBEXT, shamt, rs1, BCLR, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::bext(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BCLRBEXT, rs2, rs1, BEXT, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::bexti(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BCLRBEXT, shamt, rs1, BEXT, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::binv(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BINV, rs2, rs1, F3_BINV, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::binvi(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BINV, shamt, rs1, F3_BINV, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::bset(Register rd, Register rs1, Register rs2) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BSET, rs2, rs1, F3_BSET, rd, OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroAssembler::bseti(Register rd, Register rs1, intx_t shamt) {
|
||||||
|
ASSERT(Supports(RV_Zbs));
|
||||||
|
EmitRType(BSET, shamt, rs1, F3_BSET, rd, OPIMM);
|
||||||
|
}
|
||||||
|
|
||||||
void MicroAssembler::c_lwsp(Register rd, Address addr) {
|
void MicroAssembler::c_lwsp(Register rd, Address addr) {
|
||||||
ASSERT(rd != ZR);
|
ASSERT(rd != ZR);
|
||||||
ASSERT(addr.base() == SP);
|
ASSERT(addr.base() == SP);
|
||||||
|
|
|
@ -547,6 +547,57 @@ class MicroAssembler : public AssemblerBase {
|
||||||
void fmvdx(FRegister rd, Register rs1);
|
void fmvdx(FRegister rd, Register rs1);
|
||||||
#endif // XLEN >= 64
|
#endif // XLEN >= 64
|
||||||
|
|
||||||
|
// ==== Zba: Address generation ====
|
||||||
|
void adduw(Register rd, Register rs1, Register rs2);
|
||||||
|
void sh1add(Register rd, Register rs1, Register rs2);
|
||||||
|
void sh1adduw(Register rd, Register rs1, Register rs2);
|
||||||
|
void sh2add(Register rd, Register rs1, Register rs2);
|
||||||
|
void sh2adduw(Register rd, Register rs1, Register rs2);
|
||||||
|
void sh3add(Register rd, Register rs1, Register rs2);
|
||||||
|
void sh3adduw(Register rd, Register rs1, Register rs2);
|
||||||
|
void slliuw(Register rd, Register rs1, intx_t imm);
|
||||||
|
|
||||||
|
// ==== Zbb: Basic bit-manipulation ====
|
||||||
|
void andn(Register rd, Register rs1, Register rs2);
|
||||||
|
void orn(Register rd, Register rs1, Register rs2);
|
||||||
|
void xnor(Register rd, Register rs1, Register rs2);
|
||||||
|
void clz(Register rd, Register rs);
|
||||||
|
void clzw(Register rd, Register rs);
|
||||||
|
void ctz(Register rd, Register rs);
|
||||||
|
void ctzw(Register rd, Register rs);
|
||||||
|
void cpop(Register rd, Register rs);
|
||||||
|
void cpopw(Register rd, Register rs);
|
||||||
|
void max(Register rd, Register rs1, Register rs2);
|
||||||
|
void maxu(Register rd, Register rs1, Register rs2);
|
||||||
|
void min(Register rd, Register rs1, Register rs2);
|
||||||
|
void minu(Register rd, Register rs1, Register rs2);
|
||||||
|
void sextb(Register rd, Register rs);
|
||||||
|
void sexth(Register rd, Register rs);
|
||||||
|
void zexth(Register rd, Register rs);
|
||||||
|
void rol(Register rd, Register rs1, Register rs2);
|
||||||
|
void rolw(Register rd, Register rs1, Register rs2);
|
||||||
|
void ror(Register rd, Register rs1, Register rs2);
|
||||||
|
void rori(Register rd, Register rs1, intx_t imm);
|
||||||
|
void roriw(Register rd, Register rs1, intx_t imm);
|
||||||
|
void rorw(Register rd, Register rs1, Register rs2);
|
||||||
|
void orcb(Register rd, Register rs);
|
||||||
|
void rev8(Register rd, Register rs);
|
||||||
|
|
||||||
|
// ==== Zbc: Carry-less multiplication ====
|
||||||
|
void clmul(Register rd, Register rs1, Register rs2);
|
||||||
|
void clmulh(Register rd, Register rs1, Register rs2);
|
||||||
|
void clmulr(Register rd, Register rs1, Register rs2);
|
||||||
|
|
||||||
|
// ==== Zbs: Single-bit instructions ====
|
||||||
|
void bclr(Register rd, Register rs1, Register rs2);
|
||||||
|
void bclri(Register rd, Register rs1, intx_t shamt);
|
||||||
|
void bext(Register rd, Register rs1, Register rs2);
|
||||||
|
void bexti(Register rd, Register rs1, intx_t shamt);
|
||||||
|
void binv(Register rd, Register rs1, Register rs2);
|
||||||
|
void binvi(Register rd, Register rs1, intx_t shamt);
|
||||||
|
void bset(Register rd, Register rs1, Register rs2);
|
||||||
|
void bseti(Register rd, Register rs1, intx_t shamt);
|
||||||
|
|
||||||
// ==== Dart Simulator Debugging ====
|
// ==== Dart Simulator Debugging ====
|
||||||
void SimulatorPrintObject(Register rs1);
|
void SimulatorPrintObject(Register rs1);
|
||||||
|
|
||||||
|
|
|
@ -6165,6 +6165,952 @@ ASSEMBLER_TEST_RUN(CompressedEnvironmentBreak, test) {
|
||||||
// Not running: would trap.
|
// Not running: would trap.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
ASSEMBLER_TEST_GENERATE(AddUnsignedWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ adduw(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(AddUnsignedWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"08b5053b add.uw a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0x200000001, Call(test->entry(), 0x1, 0x200000000));
|
||||||
|
EXPECT_EQ(0x200000001, Call(test->entry(), 0x100000001, 0x200000000));
|
||||||
|
EXPECT_EQ(0x2FFFFFFFF, Call(test->entry(), -0x1, 0x200000000));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Shift1Add, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sh1add(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Shift1Add, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"20b52533 sh1add a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1002, Call(test->entry(), 1, 1000));
|
||||||
|
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
|
||||||
|
EXPECT_EQ(998, Call(test->entry(), -1, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Shift2Add, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sh2add(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Shift2Add, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"20b54533 sh2add a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1004, Call(test->entry(), 1, 1000));
|
||||||
|
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
|
||||||
|
EXPECT_EQ(996, Call(test->entry(), -1, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Shift3Add, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sh3add(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Shift3Add, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"20b56533 sh3add a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1008, Call(test->entry(), 1, 1000));
|
||||||
|
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
|
||||||
|
EXPECT_EQ(992, Call(test->entry(), -1, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
ASSEMBLER_TEST_GENERATE(Shift1AddUnsignedWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sh1adduw(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Shift1AddUnsignedWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"20b5253b sh1add.uw a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1002, Call(test->entry(), 1, 1000));
|
||||||
|
EXPECT_EQ(1002, Call(test->entry(), 0x100000001, 1000));
|
||||||
|
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
|
||||||
|
EXPECT_EQ(8589935590, Call(test->entry(), -1, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Shift2AddUnsignedWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sh2adduw(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Shift2AddUnsignedWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"20b5453b sh2add.uw a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1004, Call(test->entry(), 1, 1000));
|
||||||
|
EXPECT_EQ(1004, Call(test->entry(), 0x100000001, 1000));
|
||||||
|
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
|
||||||
|
EXPECT_EQ(17179870180, Call(test->entry(), -1, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Shift3AddUnsignedWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sh3adduw(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Shift3AddUnsignedWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"20b5653b sh3add.uw a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1008, Call(test->entry(), 1, 1000));
|
||||||
|
EXPECT_EQ(1008, Call(test->entry(), 0x100000001, 1000));
|
||||||
|
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
|
||||||
|
EXPECT_EQ(34359739360, Call(test->entry(), -1, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(ShiftLeftLogicalImmediateUnsignedWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ slliuw(A0, A0, 8);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(ShiftLeftLogicalImmediateUnsignedWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0885151b slli.uw a0, a0, 0x8\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0x100, Call(test->entry(), 0x1));
|
||||||
|
EXPECT_EQ(0x1000000000, Call(test->entry(), 0x10000000));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0x100000000));
|
||||||
|
EXPECT_EQ(0x100, Call(test->entry(), 0x100000001));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(AndNot, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ andn(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(AndNot, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"40b57533 andn a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(6, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(-24, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(16, Call(test->entry(), -7, -17));
|
||||||
|
EXPECT_EQ(16, Call(test->entry(), 17, 7));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 17, -7));
|
||||||
|
EXPECT_EQ(-24, Call(test->entry(), -17, 7));
|
||||||
|
EXPECT_EQ(6, Call(test->entry(), -17, -7));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(OrNot, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ orn(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(OrNot, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"40b56533 orn a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(-17, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(23, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), -7, -17));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), 17, 7));
|
||||||
|
EXPECT_EQ(23, Call(test->entry(), 17, -7));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -17, 7));
|
||||||
|
EXPECT_EQ(-17, Call(test->entry(), -17, -7));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(XorNot, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ xnor(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(XorNot, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"40b54533 xnor a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(-23, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(23, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(23, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(-23, Call(test->entry(), -7, -17));
|
||||||
|
EXPECT_EQ(-23, Call(test->entry(), 17, 7));
|
||||||
|
EXPECT_EQ(23, Call(test->entry(), 17, -7));
|
||||||
|
EXPECT_EQ(23, Call(test->entry(), -17, 7));
|
||||||
|
EXPECT_EQ(-23, Call(test->entry(), -17, -7));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CountLeadingZeroes, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ clz(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CountLeadingZeroes, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60051513 clz a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(XLEN, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(XLEN - 1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(XLEN - 2, Call(test->entry(), 2));
|
||||||
|
EXPECT_EQ(XLEN - 3, Call(test->entry(), 4));
|
||||||
|
EXPECT_EQ(XLEN - 8, Call(test->entry(), 240));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -2));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -4));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -240));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CountTrailingZeroes, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ ctz(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CountTrailingZeroes, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60151513 ctz a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(XLEN, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 2));
|
||||||
|
EXPECT_EQ(2, Call(test->entry(), 4));
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), 240));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), -2));
|
||||||
|
EXPECT_EQ(2, Call(test->entry(), -4));
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), -240));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CountPopulation, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ cpop(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CountPopulation, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60251513 cpop a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(3, Call(test->entry(), 7));
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), 30));
|
||||||
|
EXPECT_EQ(XLEN, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(XLEN - 2, Call(test->entry(), -7));
|
||||||
|
EXPECT_EQ(XLEN - 4, Call(test->entry(), -30));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
ASSEMBLER_TEST_GENERATE(CountLeadingZeroesWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ clzw(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CountLeadingZeroesWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"6005151b clzw a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(32, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(31, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(30, Call(test->entry(), 2));
|
||||||
|
EXPECT_EQ(29, Call(test->entry(), 4));
|
||||||
|
EXPECT_EQ(24, Call(test->entry(), 240));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -2));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -4));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -240));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CountTrailingZeroesWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ ctzw(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CountTrailingZeroesWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"6015151b ctzw a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(32, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 2));
|
||||||
|
EXPECT_EQ(2, Call(test->entry(), 4));
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), 240));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), -2));
|
||||||
|
EXPECT_EQ(2, Call(test->entry(), -4));
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), -240));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CountPopulationWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ cpopw(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CountPopulationWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"6025151b cpopw a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(3, Call(test->entry(), 7));
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), 30));
|
||||||
|
EXPECT_EQ(32, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(30, Call(test->entry(), -7));
|
||||||
|
EXPECT_EQ(28, Call(test->entry(), -30));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0x7FFFFFFF00000000));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Max, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ max(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Max, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab56533 max a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(17, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(17, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(7, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), -7, -17));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(MaxUnsigned, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ maxu(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(MaxUnsigned, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab57533 maxu a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(17, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(-17, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), -7, -17));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(Min, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ min(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(Min, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab54533 min a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(7, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(-17, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(-17, Call(test->entry(), -7, -17));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(MinUnsigned, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ minu(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(MinUnsigned, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab55533 minu a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(7, Call(test->entry(), 7, 17));
|
||||||
|
EXPECT_EQ(17, Call(test->entry(), -7, 17));
|
||||||
|
EXPECT_EQ(7, Call(test->entry(), 7, -17));
|
||||||
|
EXPECT_EQ(-17, Call(test->entry(), -7, -17));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(SignExtendByte, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sextb(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(SignExtendByte, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60451513 sext.b a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(127, Call(test->entry(), 127));
|
||||||
|
EXPECT_EQ(-128, Call(test->entry(), 128));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(SignExtendHalfWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ sexth(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(SignExtendHalfWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60551513 sext.h a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(0x7BCD, Call(test->entry(), 0x12347BCD));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), 0xFFFF));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(ZeroExtendHalfWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ zexth(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(ZeroExtendHalfWord, test) {
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"08054533 zext.h a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#else
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0805453b zext.h a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(0xABCD, Call(test->entry(), 0x1234ABCD));
|
||||||
|
EXPECT_EQ(0xFFFF, Call(test->entry(), 0xFFFF));
|
||||||
|
EXPECT_EQ(0xFFFF, Call(test->entry(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(RotateRight, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ ror(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(RotateRight, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60b55533 ror a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x12345678),
|
||||||
|
Call(test->entry(), 0x12345678, 0));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x81234567),
|
||||||
|
Call(test->entry(), 0x12345678, 4));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x23456781),
|
||||||
|
Call(test->entry(), 0x12345678, 28));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x81234567),
|
||||||
|
Call(test->entry(), 0x12345678, 36));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x0123456789ABCDEF),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 0));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 4));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x123456789ABCDEF0),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 60));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 68));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(RotateLeft, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ rol(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(RotateLeft, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60b51533 rol a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x12345678),
|
||||||
|
Call(test->entry(), 0x12345678, 0));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x23456781),
|
||||||
|
Call(test->entry(), 0x12345678, 4));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x81234567),
|
||||||
|
Call(test->entry(), 0x12345678, 28));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x23456781),
|
||||||
|
Call(test->entry(), 0x12345678, 36));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x0123456789ABCDEF),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 0));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x123456789ABCDEF0),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 4));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 60));
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x123456789ABCDEF0),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF, 68));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(RotateRightImmediate, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ rori(A0, A0, 4);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(RotateRightImmediate, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60455513 rori a0, a0, 0x4\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0x81234567), Call(test->entry(), 0x12345678));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
|
||||||
|
Call(test->entry(), 0x0123456789ABCDEF));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XLEN >= 64
|
||||||
|
ASSEMBLER_TEST_GENERATE(RotateRightWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ rorw(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(RotateRightWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60b5553b rorw a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(sign_extend(0x12345678), Call(test->entry(), 0x12345678, 0));
|
||||||
|
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678, 4));
|
||||||
|
EXPECT_EQ(sign_extend(0x23456781), Call(test->entry(), 0x12345678, 28));
|
||||||
|
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(RotateLeftWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ rolw(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(RotateLeftWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"60b5153b rolw a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(sign_extend(0x12345678), Call(test->entry(), 0x12345678, 0));
|
||||||
|
EXPECT_EQ(sign_extend(0x23456781), Call(test->entry(), 0x12345678, 4));
|
||||||
|
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678, 28));
|
||||||
|
EXPECT_EQ(sign_extend(0x23456781), Call(test->entry(), 0x12345678, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(RotateRightImmediateWord, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ roriw(A0, A0, 4);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(RotateRightImmediateWord, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"6045551b roriw a0, a0, 0x4\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(OrCombineBytes, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ orcb(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(OrCombineBytes, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"28755513 orc.b a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -1));
|
||||||
|
EXPECT_EQ(0x00FF00FF, Call(test->entry(), 0x00010001));
|
||||||
|
#if XLEN >= 64
|
||||||
|
EXPECT_EQ(0x00FF00FF00FF00FF, Call(test->entry(), 0x0001000100010001));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(ByteReverse, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ rev8(A0, A0);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(ByteReverse, test) {
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"69855513 rev8 a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#else
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"6b855513 rev8 a0, a0\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -1));
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(0x11223344, Call(test->entry(), 0x44332211));
|
||||||
|
#elif XLEN == 64
|
||||||
|
EXPECT_EQ(0x1122334455667788, Call(test->entry(), 0x8877665544332211));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CarrylessMultiply, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ clmul(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CarrylessMultiply, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab51533 clmul a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(0x55555555, Call(test->entry(), -1, -1));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(0x5555555555555555, Call(test->entry(), -1, -1));
|
||||||
|
#endif
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1, 0));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -1, 1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, 1));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), 1, -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1, 0));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 1, 1));
|
||||||
|
|
||||||
|
EXPECT_EQ(4, Call(test->entry(), 2, 2));
|
||||||
|
EXPECT_EQ(5, Call(test->entry(), 3, 3));
|
||||||
|
EXPECT_EQ(16, Call(test->entry(), 4, 4));
|
||||||
|
EXPECT_EQ(20, Call(test->entry(), 6, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CarrylessMultiplyHigh, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ clmulh(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CarrylessMultiplyHigh, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab53533 clmulh a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(0x55555555, Call(test->entry(), -1, -1));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(0x5555555555555555, Call(test->entry(), -1, -1));
|
||||||
|
#endif
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1, 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1, 1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, 1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1, -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1, 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1, 1));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 2, 2));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 3, 3));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 4, 4));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 6, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(CarrylessMultiplyReversed, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ clmulr(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(CarrylessMultiplyReversed, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"0ab52533 clmulr a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_EQ(-0x55555556, Call(test->entry(), -1, -1));
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(-0x5555555555555556, Call(test->entry(), -1, -1));
|
||||||
|
#endif
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -1, 0));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), -1, 1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0, 1));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 1, -1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1, 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1, 1));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 2, 2));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 3, 3));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 4, 4));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 6, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitClear, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bclr(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitClear, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"48b51533 bclr a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 0));
|
||||||
|
EXPECT_EQ(40, Call(test->entry(), 42, 1));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 2));
|
||||||
|
EXPECT_EQ(34, Call(test->entry(), 42, 3));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 4));
|
||||||
|
EXPECT_EQ(10, Call(test->entry(), 42, 5));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 6));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 7));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 8));
|
||||||
|
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 64));
|
||||||
|
EXPECT_EQ(40, Call(test->entry(), 42, 65));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitClearImmediate, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bclri(A0, A0, 3);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitClearImmediate, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"48351513 bclri a0, a0, 0x3\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(7, Call(test->entry(), 7));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 8));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 9));
|
||||||
|
EXPECT_EQ(-15, Call(test->entry(), -7));
|
||||||
|
EXPECT_EQ(-16, Call(test->entry(), -8));
|
||||||
|
EXPECT_EQ(-9, Call(test->entry(), -9));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitClearImmediate2, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bclri(A0, A0, XLEN - 1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitClearImmediate2, test) {
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"49f51513 bclri a0, a0, 0x1f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#elif XLEN == 64
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"4bf51513 bclri a0, a0, 0x3f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(kMaxIntX, Call(test->entry(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitExtract, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bext(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitExtract, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"48b55533 bext a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 0));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 42, 1));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 2));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 42, 3));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 4));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 42, 5));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 6));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 7));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 8));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 42, 64));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 42, 65));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitExtractImmediate, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bexti(A0, A0, 3);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitExtractImmediate, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"48355513 bexti a0, a0, 0x3\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 7));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 8));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 9));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), -7));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), -8));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), -9));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitExtractImmediate2, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bexti(A0, A0, XLEN - 1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitExtractImmediate2, test) {
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"49f55513 bexti a0, a0, 0x1f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#elif XLEN == 64
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"4bf55513 bexti a0, a0, 0x3f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitInvert, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ binv(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitInvert, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"68b51533 binv a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(43, Call(test->entry(), 42, 0));
|
||||||
|
EXPECT_EQ(40, Call(test->entry(), 42, 1));
|
||||||
|
EXPECT_EQ(46, Call(test->entry(), 42, 2));
|
||||||
|
EXPECT_EQ(34, Call(test->entry(), 42, 3));
|
||||||
|
EXPECT_EQ(58, Call(test->entry(), 42, 4));
|
||||||
|
EXPECT_EQ(10, Call(test->entry(), 42, 5));
|
||||||
|
EXPECT_EQ(106, Call(test->entry(), 42, 6));
|
||||||
|
EXPECT_EQ(170, Call(test->entry(), 42, 7));
|
||||||
|
EXPECT_EQ(298, Call(test->entry(), 42, 8));
|
||||||
|
|
||||||
|
EXPECT_EQ(43, Call(test->entry(), 42, 64));
|
||||||
|
EXPECT_EQ(40, Call(test->entry(), 42, 65));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitInvertImmediate, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ binvi(A0, A0, 3);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitInvertImmediate, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"68351513 binvi a0, a0, 0x3\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(8, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(15, Call(test->entry(), 7));
|
||||||
|
EXPECT_EQ(0, Call(test->entry(), 8));
|
||||||
|
EXPECT_EQ(1, Call(test->entry(), 9));
|
||||||
|
EXPECT_EQ(-15, Call(test->entry(), -7));
|
||||||
|
EXPECT_EQ(-16, Call(test->entry(), -8));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -9));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitInvertImmediate2, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ binvi(A0, A0, XLEN - 1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitInvertImmediate2, test) {
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"69f51513 binvi a0, a0, 0x1f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#elif XLEN == 64
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"6bf51513 binvi a0, a0, 0x3f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXPECT_EQ(kMinIntX, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(kMaxIntX, Call(test->entry(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitSet, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bset(A0, A0, A1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitSet, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"28b51533 bset a0, a0, a1\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(43, Call(test->entry(), 42, 0));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 1));
|
||||||
|
EXPECT_EQ(46, Call(test->entry(), 42, 2));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 3));
|
||||||
|
EXPECT_EQ(58, Call(test->entry(), 42, 4));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 5));
|
||||||
|
EXPECT_EQ(106, Call(test->entry(), 42, 6));
|
||||||
|
EXPECT_EQ(170, Call(test->entry(), 42, 7));
|
||||||
|
EXPECT_EQ(298, Call(test->entry(), 42, 8));
|
||||||
|
|
||||||
|
EXPECT_EQ(43, Call(test->entry(), 42, 64));
|
||||||
|
EXPECT_EQ(42, Call(test->entry(), 42, 65));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitSetImmediate, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bseti(A0, A0, 3);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitSetImmediate, test) {
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"28351513 bseti a0, a0, 0x3\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
|
||||||
|
EXPECT_EQ(8, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(15, Call(test->entry(), 7));
|
||||||
|
EXPECT_EQ(8, Call(test->entry(), 8));
|
||||||
|
EXPECT_EQ(9, Call(test->entry(), 9));
|
||||||
|
EXPECT_EQ(-7, Call(test->entry(), -7));
|
||||||
|
EXPECT_EQ(-8, Call(test->entry(), -8));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -9));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSEMBLER_TEST_GENERATE(BitSetImmediate2, assembler) {
|
||||||
|
__ SetExtensions(RV_GCB);
|
||||||
|
__ bseti(A0, A0, XLEN - 1);
|
||||||
|
__ ret();
|
||||||
|
}
|
||||||
|
ASSEMBLER_TEST_RUN(BitSetImmediate2, test) {
|
||||||
|
#if XLEN == 32
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"29f51513 bseti a0, a0, 0x1f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#elif XLEN == 64
|
||||||
|
EXPECT_DISASSEMBLY(
|
||||||
|
"2bf51513 bseti a0, a0, 0x3f\n"
|
||||||
|
" 8082 ret\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXPECT_EQ(kMinIntX, Call(test->entry(), 0));
|
||||||
|
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 1));
|
||||||
|
EXPECT_EQ(-1, Call(test->entry(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
ASSEMBLER_TEST_GENERATE(LoadImmediate_MaxInt32, assembler) {
|
ASSEMBLER_TEST_GENERATE(LoadImmediate_MaxInt32, assembler) {
|
||||||
FLAG_use_compressed_instructions = true;
|
FLAG_use_compressed_instructions = true;
|
||||||
__ SetExtensions(RV_GC);
|
__ SetExtensions(RV_GC);
|
||||||
|
@ -6346,6 +7292,7 @@ ASSEMBLER_TEST_RUN(AddBranchOverflow_NonDestructive, test) {
|
||||||
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 42, kMinIntX, 1));
|
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 42, kMinIntX, 1));
|
||||||
EXPECT_EQ(kMinIntX, Call(test->entry(), 42, kMinIntX, 0));
|
EXPECT_EQ(kMinIntX, Call(test->entry(), 42, kMinIntX, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSEMBLER_TEST_GENERATE(AddBranchOverflow_Destructive, assembler) {
|
ASSEMBLER_TEST_GENERATE(AddBranchOverflow_Destructive, assembler) {
|
||||||
FLAG_use_compressed_instructions = true;
|
FLAG_use_compressed_instructions = true;
|
||||||
__ SetExtensions(RV_GC);
|
__ SetExtensions(RV_GC);
|
||||||
|
@ -6357,7 +7304,6 @@ ASSEMBLER_TEST_GENERATE(AddBranchOverflow_Destructive, assembler) {
|
||||||
__ li(A0, 0);
|
__ li(A0, 0);
|
||||||
__ ret();
|
__ ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSEMBLER_TEST_RUN(AddBranchOverflow_Destructive, test) {
|
ASSEMBLER_TEST_RUN(AddBranchOverflow_Destructive, test) {
|
||||||
EXPECT_DISASSEMBLY(
|
EXPECT_DISASSEMBLY(
|
||||||
"00052693 slti tmp, a0, 0\n"
|
"00052693 slti tmp, a0, 0\n"
|
||||||
|
|
|
@ -65,10 +65,17 @@ class RISCVDisassembler {
|
||||||
void DisassembleOP_0(Instr instr);
|
void DisassembleOP_0(Instr instr);
|
||||||
void DisassembleOP_SUB(Instr instr);
|
void DisassembleOP_SUB(Instr instr);
|
||||||
void DisassembleOP_MULDIV(Instr instr);
|
void DisassembleOP_MULDIV(Instr instr);
|
||||||
|
void DisassembleOP_SHADD(Instr instr);
|
||||||
|
void DisassembleOP_MINMAXCLMUL(Instr instr);
|
||||||
|
void DisassembleOP_ROTATE(Instr instr);
|
||||||
|
void DisassembleOP_BCLRBEXT(Instr instr);
|
||||||
void DisassembleOP32(Instr instr);
|
void DisassembleOP32(Instr instr);
|
||||||
void DisassembleOP32_0(Instr instr);
|
void DisassembleOP32_0(Instr instr);
|
||||||
void DisassembleOP32_SUB(Instr instr);
|
void DisassembleOP32_SUB(Instr instr);
|
||||||
void DisassembleOP32_MULDIV(Instr instr);
|
void DisassembleOP32_MULDIV(Instr instr);
|
||||||
|
void DisassembleOP32_SHADD(Instr instr);
|
||||||
|
void DisassembleOP32_ADDUW(Instr instr);
|
||||||
|
void DisassembleOP32_ROTATE(Instr instr);
|
||||||
void DisassembleMISCMEM(Instr instr);
|
void DisassembleMISCMEM(Instr instr);
|
||||||
void DisassembleSYSTEM(Instr instr);
|
void DisassembleSYSTEM(Instr instr);
|
||||||
void DisassembleAMO(Instr instr);
|
void DisassembleAMO(Instr instr);
|
||||||
|
@ -579,11 +586,46 @@ void RISCVDisassembler::DisassembleOPIMM(Instr instr) {
|
||||||
Print("andi 'rd, 'rs1, 'iimm", instr, RV_I);
|
Print("andi 'rd, 'rs1, 'iimm", instr, RV_I);
|
||||||
break;
|
break;
|
||||||
case SLLI:
|
case SLLI:
|
||||||
Print("slli 'rd, 'rs1, 'shamt", instr, RV_I);
|
if (instr.funct7() == COUNT) {
|
||||||
|
if (instr.shamt() == 0b00000) {
|
||||||
|
Print("clz 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else if (instr.shamt() == 0b00001) {
|
||||||
|
Print("ctz 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else if (instr.shamt() == 0b00010) {
|
||||||
|
Print("cpop 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else if (instr.shamt() == 0b00100) {
|
||||||
|
Print("sext.b 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else if (instr.shamt() == 0b00101) {
|
||||||
|
Print("sext.h 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else {
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
|
||||||
|
Print("bclri 'rd, 'rs1, 'shamt", instr, RV_Zbs);
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BINV) {
|
||||||
|
Print("binvi 'rd, 'rs1, 'shamt", instr, RV_Zbs);
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BSET) {
|
||||||
|
Print("bseti 'rd, 'rs1, 'shamt", instr, RV_Zbs);
|
||||||
|
} else {
|
||||||
|
Print("slli 'rd, 'rs1, 'shamt", instr, RV_I);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SRI:
|
case SRI:
|
||||||
if ((instr.funct7() & 0b1111110) == SRA) {
|
if ((instr.funct7() & 0b1111110) == SRA) {
|
||||||
Print("srai 'rd, 'rs1, 'shamt", instr, RV_I);
|
Print("srai 'rd, 'rs1, 'shamt", instr, RV_I);
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == ROTATE) {
|
||||||
|
Print("rori 'rd, 'rs1, 'shamt", instr, RV_Zbb);
|
||||||
|
} else if (instr.funct7() == 0b0010100) {
|
||||||
|
Print("orc.b 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
#if XLEN == 32
|
||||||
|
} else if (instr.funct7() == 0b0110100) {
|
||||||
|
Print("rev8 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
#else
|
||||||
|
} else if (instr.funct7() == 0b0110101) {
|
||||||
|
Print("rev8 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
#endif
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
|
||||||
|
Print("bexti 'rd, 'rs1, 'shamt", instr, RV_Zbs);
|
||||||
} else {
|
} else {
|
||||||
Print("srli 'rd, 'rs1, 'shamt", instr, RV_I);
|
Print("srli 'rd, 'rs1, 'shamt", instr, RV_I);
|
||||||
}
|
}
|
||||||
|
@ -604,11 +646,27 @@ void RISCVDisassembler::DisassembleOPIMM32(Instr instr) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SLLI:
|
case SLLI:
|
||||||
Print("slliw 'rd, 'rs1, 'shamt", instr, RV_I);
|
if (instr.funct7() == SLLIUW) {
|
||||||
|
Print("slli.uw 'rd, 'rs1, 'shamt", instr, RV_Zba);
|
||||||
|
} else if (instr.funct7() == COUNT) {
|
||||||
|
if (instr.shamt() == 0b00000) {
|
||||||
|
Print("clzw 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else if (instr.shamt() == 0b00001) {
|
||||||
|
Print("ctzw 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else if (instr.shamt() == 0b00010) {
|
||||||
|
Print("cpopw 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
} else {
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Print("slliw 'rd, 'rs1, 'shamt", instr, RV_I);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SRI:
|
case SRI:
|
||||||
if (instr.funct7() == SRA) {
|
if (instr.funct7() == SRA) {
|
||||||
Print("sraiw 'rd, 'rs1, 'shamt", instr, RV_I);
|
Print("sraiw 'rd, 'rs1, 'shamt", instr, RV_I);
|
||||||
|
} else if (instr.funct7() == ROTATE) {
|
||||||
|
Print("roriw 'rd, 'rs1, 'shamt", instr, RV_Zbb);
|
||||||
} else {
|
} else {
|
||||||
Print("srliw 'rd, 'rs1, 'shamt", instr, RV_I);
|
Print("srliw 'rd, 'rs1, 'shamt", instr, RV_I);
|
||||||
}
|
}
|
||||||
|
@ -630,6 +688,29 @@ void RISCVDisassembler::DisassembleOP(Instr instr) {
|
||||||
case MULDIV:
|
case MULDIV:
|
||||||
DisassembleOP_MULDIV(instr);
|
DisassembleOP_MULDIV(instr);
|
||||||
break;
|
break;
|
||||||
|
case SHADD:
|
||||||
|
DisassembleOP_SHADD(instr);
|
||||||
|
break;
|
||||||
|
case MINMAXCLMUL:
|
||||||
|
DisassembleOP_MINMAXCLMUL(instr);
|
||||||
|
break;
|
||||||
|
case ROTATE:
|
||||||
|
DisassembleOP_ROTATE(instr);
|
||||||
|
break;
|
||||||
|
case BCLRBEXT:
|
||||||
|
DisassembleOP_BCLRBEXT(instr);
|
||||||
|
break;
|
||||||
|
case BINV:
|
||||||
|
Print("binv 'rd, 'rs1, 'rs2", instr, RV_Zbs);
|
||||||
|
break;
|
||||||
|
case BSET:
|
||||||
|
Print("bset 'rd, 'rs1, 'rs2", instr, RV_Zbs);
|
||||||
|
break;
|
||||||
|
#if XLEN == 32
|
||||||
|
case 0b0000100:
|
||||||
|
Print("zext.h 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
UnknownInstruction(instr);
|
UnknownInstruction(instr);
|
||||||
}
|
}
|
||||||
|
@ -688,6 +769,15 @@ void RISCVDisassembler::DisassembleOP_SUB(Instr instr) {
|
||||||
case SR:
|
case SR:
|
||||||
Print("sra 'rd, 'rs1, 'rs2", instr, RV_I);
|
Print("sra 'rd, 'rs1, 'rs2", instr, RV_I);
|
||||||
break;
|
break;
|
||||||
|
case AND:
|
||||||
|
Print("andn 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
Print("orn 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case XOR:
|
||||||
|
Print("xnor 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UnknownInstruction(instr);
|
UnknownInstruction(instr);
|
||||||
}
|
}
|
||||||
|
@ -724,6 +814,76 @@ void RISCVDisassembler::DisassembleOP_MULDIV(Instr instr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP_SHADD(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case SH1ADD:
|
||||||
|
Print("sh1add 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
case SH2ADD:
|
||||||
|
Print("sh2add 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
case SH3ADD:
|
||||||
|
Print("sh3add 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP_MINMAXCLMUL(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case MAX:
|
||||||
|
Print("max 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case MAXU:
|
||||||
|
Print("maxu 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case MIN:
|
||||||
|
Print("min 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case MINU:
|
||||||
|
Print("minu 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case CLMUL:
|
||||||
|
Print("clmul 'rd, 'rs1, 'rs2", instr, RV_Zbc);
|
||||||
|
break;
|
||||||
|
case CLMULH:
|
||||||
|
Print("clmulh 'rd, 'rs1, 'rs2", instr, RV_Zbc);
|
||||||
|
break;
|
||||||
|
case CLMULR:
|
||||||
|
Print("clmulr 'rd, 'rs1, 'rs2", instr, RV_Zbc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP_ROTATE(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case ROR:
|
||||||
|
Print("ror 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case ROL:
|
||||||
|
Print("rol 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP_BCLRBEXT(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case BCLR:
|
||||||
|
Print("bclr 'rd, 'rs1, 'rs2", instr, RV_Zbs);
|
||||||
|
break;
|
||||||
|
case BEXT:
|
||||||
|
Print("bext 'rd, 'rs1, 'rs2", instr, RV_Zbs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RISCVDisassembler::DisassembleOP32(Instr instr) {
|
void RISCVDisassembler::DisassembleOP32(Instr instr) {
|
||||||
switch (instr.funct7()) {
|
switch (instr.funct7()) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -735,6 +895,15 @@ void RISCVDisassembler::DisassembleOP32(Instr instr) {
|
||||||
case MULDIV:
|
case MULDIV:
|
||||||
DisassembleOP32_MULDIV(instr);
|
DisassembleOP32_MULDIV(instr);
|
||||||
break;
|
break;
|
||||||
|
case SHADD:
|
||||||
|
DisassembleOP32_SHADD(instr);
|
||||||
|
break;
|
||||||
|
case ADDUW:
|
||||||
|
DisassembleOP32_ADDUW(instr);
|
||||||
|
break;
|
||||||
|
case ROTATE:
|
||||||
|
DisassembleOP32_ROTATE(instr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UnknownInstruction(instr);
|
UnknownInstruction(instr);
|
||||||
}
|
}
|
||||||
|
@ -802,6 +971,50 @@ void RISCVDisassembler::DisassembleOP32_MULDIV(Instr instr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP32_SHADD(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case SH1ADD:
|
||||||
|
Print("sh1add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
case SH2ADD:
|
||||||
|
Print("sh2add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
case SH3ADD:
|
||||||
|
Print("sh3add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP32_ADDUW(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
#if XLEN >= 64
|
||||||
|
case F3_0:
|
||||||
|
Print("add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
|
||||||
|
break;
|
||||||
|
case ZEXT:
|
||||||
|
Print("zext.h 'rd, 'rs1", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RISCVDisassembler::DisassembleOP32_ROTATE(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case ROR:
|
||||||
|
Print("rorw 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
case ROL:
|
||||||
|
Print("rolw 'rd, 'rs1, 'rs2", instr, RV_Zbb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UnknownInstruction(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RISCVDisassembler::DisassembleMISCMEM(Instr instr) {
|
void RISCVDisassembler::DisassembleMISCMEM(Instr instr) {
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
case FENCE:
|
case FENCE:
|
||||||
|
@ -1076,10 +1289,10 @@ void RISCVDisassembler::DisassembleOPFP(Instr instr) {
|
||||||
}
|
}
|
||||||
case FMINMAXS: {
|
case FMINMAXS: {
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
case MIN:
|
case FMIN:
|
||||||
Print("fmin.s 'frd, 'frs1, 'frs2", instr, RV_F);
|
Print("fmin.s 'frd, 'frs1, 'frs2", instr, RV_F);
|
||||||
break;
|
break;
|
||||||
case MAX:
|
case FMAX:
|
||||||
Print("fmax.s 'frd, 'frs1, 'frs2", instr, RV_F);
|
Print("fmax.s 'frd, 'frs1, 'frs2", instr, RV_F);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1203,10 +1416,10 @@ void RISCVDisassembler::DisassembleOPFP(Instr instr) {
|
||||||
}
|
}
|
||||||
case FMINMAXD: {
|
case FMINMAXD: {
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
case MIN:
|
case FMIN:
|
||||||
Print("fmin.d 'frd, 'frs1, 'frs2", instr, RV_D);
|
Print("fmin.d 'frd, 'frs1, 'frs2", instr, RV_D);
|
||||||
break;
|
break;
|
||||||
case MAX:
|
case FMAX:
|
||||||
Print("fmax.d 'frd, 'frs1, 'frs2", instr, RV_D);
|
Print("fmax.d 'frd, 'frs1, 'frs2", instr, RV_D);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -780,11 +780,36 @@ enum Funct3 {
|
||||||
J = 0b000,
|
J = 0b000,
|
||||||
JN = 0b001,
|
JN = 0b001,
|
||||||
JX = 0b010,
|
JX = 0b010,
|
||||||
MIN = 0b000,
|
FMIN = 0b000,
|
||||||
MAX = 0b001,
|
FMAX = 0b001,
|
||||||
FEQ = 0b010,
|
FEQ = 0b010,
|
||||||
FLT = 0b001,
|
FLT = 0b001,
|
||||||
FLE = 0b000,
|
FLE = 0b000,
|
||||||
|
|
||||||
|
SH1ADD = 0b010,
|
||||||
|
SH2ADD = 0b100,
|
||||||
|
SH3ADD = 0b110,
|
||||||
|
|
||||||
|
F3_COUNT = 0b001,
|
||||||
|
|
||||||
|
MAX = 0b110,
|
||||||
|
MAXU = 0b111,
|
||||||
|
MIN = 0b100,
|
||||||
|
MINU = 0b101,
|
||||||
|
CLMUL = 0b001,
|
||||||
|
CLMULH = 0b011,
|
||||||
|
CLMULR = 0b010,
|
||||||
|
|
||||||
|
SEXT = 0b001,
|
||||||
|
ZEXT = 0b100,
|
||||||
|
|
||||||
|
ROL = 0b001,
|
||||||
|
ROR = 0b101,
|
||||||
|
|
||||||
|
BCLR = 0b001,
|
||||||
|
BEXT = 0b101,
|
||||||
|
F3_BINV = 0b001,
|
||||||
|
F3_BSET = 0b001,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Funct7 {
|
enum Funct7 {
|
||||||
|
@ -822,6 +847,16 @@ enum Funct7 {
|
||||||
FCVTDint = 0b1101001,
|
FCVTDint = 0b1101001,
|
||||||
FMVXD = 0b1110001,
|
FMVXD = 0b1110001,
|
||||||
FMVDX = 0b1111001,
|
FMVDX = 0b1111001,
|
||||||
|
|
||||||
|
ADDUW = 0b0000100,
|
||||||
|
SHADD = 0b0010000,
|
||||||
|
SLLIUW = 0b0000100,
|
||||||
|
COUNT = 0b0110000,
|
||||||
|
MINMAXCLMUL = 0b0000101,
|
||||||
|
ROTATE = 0b0110000,
|
||||||
|
BCLRBEXT = 0b0100100,
|
||||||
|
BINV = 0b0110100,
|
||||||
|
BSET = 0b0010100,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Funct5 {
|
enum Funct5 {
|
||||||
|
@ -1515,6 +1550,12 @@ static constexpr Extension RV_D(4); // Double-precision floating point
|
||||||
static constexpr Extension RV_C(5); // Compressed instructions
|
static constexpr Extension RV_C(5); // Compressed instructions
|
||||||
static constexpr ExtensionSet RV_G = RV_I | RV_M | RV_A | RV_F | RV_D;
|
static constexpr ExtensionSet RV_G = RV_I | RV_M | RV_A | RV_F | RV_D;
|
||||||
static constexpr ExtensionSet RV_GC = RV_G | RV_C;
|
static constexpr ExtensionSet RV_GC = RV_G | RV_C;
|
||||||
|
static constexpr Extension RV_Zba(6); // Address generation
|
||||||
|
static constexpr Extension RV_Zbb(7); // Basic bit-manipulation
|
||||||
|
static constexpr Extension RV_Zbc(8); // Carry-less multiplicatio
|
||||||
|
static constexpr Extension RV_Zbs(9); // Single-bit instructions
|
||||||
|
static constexpr ExtensionSet RV_B = RV_Zba | RV_Zbb | RV_Zbc | RV_Zbs;
|
||||||
|
static constexpr ExtensionSet RV_GCB = RV_GC | RV_B;
|
||||||
|
|
||||||
#undef R
|
#undef R
|
||||||
|
|
||||||
|
|
|
@ -1007,6 +1007,162 @@ void Simulator::InterpretSTOREFP(Instr instr) {
|
||||||
pc_ += instr.length();
|
pc_ += instr.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uintx_t clz(uintx_t a) {
|
||||||
|
for (int bit = XLEN - 1; bit >= 0; bit--) {
|
||||||
|
if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
|
||||||
|
return XLEN - bit - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return XLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintx_t ctz(uintx_t a) {
|
||||||
|
for (int bit = 0; bit < XLEN; bit++) {
|
||||||
|
if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return XLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintx_t cpop(uintx_t a) {
|
||||||
|
uintx_t count = 0;
|
||||||
|
for (int bit = 0; bit < XLEN; bit++) {
|
||||||
|
if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintx_t clzw(uint32_t a) {
|
||||||
|
for (int bit = 32 - 1; bit >= 0; bit--) {
|
||||||
|
if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
|
||||||
|
return 32 - bit - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintx_t ctzw(uint32_t a) {
|
||||||
|
for (int bit = 0; bit < 32; bit++) {
|
||||||
|
if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintx_t cpopw(uint32_t a) {
|
||||||
|
uintx_t count = 0;
|
||||||
|
for (int bit = 0; bit < 32; bit++) {
|
||||||
|
if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static intx_t max(intx_t a, intx_t b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
static uintx_t maxu(uintx_t a, uintx_t b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
static intx_t min(intx_t a, intx_t b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
static uintx_t minu(uintx_t a, uintx_t b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
static uintx_t clmul(uintx_t a, uintx_t b) {
|
||||||
|
uintx_t result = 0;
|
||||||
|
for (int bit = 0; bit < XLEN; bit++) {
|
||||||
|
if (((b >> bit) & 1) != 0) {
|
||||||
|
result ^= a << bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static uintx_t clmulh(uintx_t a, uintx_t b) {
|
||||||
|
uintx_t result = 0;
|
||||||
|
for (int bit = 1; bit < XLEN; bit++) {
|
||||||
|
if (((b >> bit) & 1) != 0) {
|
||||||
|
result ^= a >> (XLEN - bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static uintx_t clmulr(uintx_t a, uintx_t b) {
|
||||||
|
uintx_t result = 0;
|
||||||
|
for (int bit = 0; bit < XLEN; bit++) {
|
||||||
|
if (((b >> bit) & 1) != 0) {
|
||||||
|
result ^= a >> (XLEN - bit - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static uintx_t sextb(uintx_t a) {
|
||||||
|
return static_cast<intx_t>(a << (XLEN - 8)) >> (XLEN - 8);
|
||||||
|
}
|
||||||
|
static uintx_t sexth(uintx_t a) {
|
||||||
|
return static_cast<intx_t>(a << (XLEN - 16)) >> (XLEN - 16);
|
||||||
|
}
|
||||||
|
static uintx_t zexth(uintx_t a) {
|
||||||
|
return a << (XLEN - 16) >> (XLEN - 16);
|
||||||
|
}
|
||||||
|
static uintx_t ror(uintx_t a, uintx_t b) {
|
||||||
|
uintx_t r = b & (XLEN - 1);
|
||||||
|
uintx_t l = (XLEN - r) & (XLEN - 1);
|
||||||
|
return (a << l) | (a >> r);
|
||||||
|
}
|
||||||
|
static uintx_t rol(uintx_t a, uintx_t b) {
|
||||||
|
uintx_t l = b & (XLEN - 1);
|
||||||
|
uintx_t r = (XLEN - l) & (XLEN - 1);
|
||||||
|
return (a << l) | (a >> r);
|
||||||
|
}
|
||||||
|
static uintx_t rorw(uintx_t a, uintx_t b) {
|
||||||
|
uint32_t r = b & (XLEN - 1);
|
||||||
|
uint32_t l = (XLEN - r) & (XLEN - 1);
|
||||||
|
uint32_t x = a;
|
||||||
|
return sign_extend((x << l) | (x >> r));
|
||||||
|
}
|
||||||
|
static uintx_t rolw(uintx_t a, uintx_t b) {
|
||||||
|
uint32_t l = b & (XLEN - 1);
|
||||||
|
uint32_t r = (XLEN - l) & (XLEN - 1);
|
||||||
|
uint32_t x = a;
|
||||||
|
return sign_extend((x << l) | (x >> r));
|
||||||
|
}
|
||||||
|
static uintx_t orcb(uintx_t a) {
|
||||||
|
uintx_t result = 0;
|
||||||
|
for (int shift = 0; shift < XLEN; shift += 8) {
|
||||||
|
if (((a >> shift) & 0xFF) != 0) {
|
||||||
|
result |= static_cast<uintx_t>(0xFF) << shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static uintx_t rev8(uintx_t a) {
|
||||||
|
uintx_t result = 0;
|
||||||
|
for (int shift = 0; shift < XLEN; shift += 8) {
|
||||||
|
result <<= 8;
|
||||||
|
result |= (a >> shift) & 0xFF;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static uintx_t bclr(uintx_t a, uintx_t b) {
|
||||||
|
return a & ~(static_cast<uintx_t>(1) << (b & (XLEN - 1)));
|
||||||
|
}
|
||||||
|
static uintx_t bext(uintx_t a, uintx_t b) {
|
||||||
|
return (a >> (b & (XLEN - 1))) & 1;
|
||||||
|
}
|
||||||
|
static uintx_t binv(uintx_t a, uintx_t b) {
|
||||||
|
return a ^ (static_cast<uintx_t>(1) << (b & (XLEN - 1)));
|
||||||
|
}
|
||||||
|
static uintx_t bset(uintx_t a, uintx_t b) {
|
||||||
|
return a | (static_cast<uintx_t>(1) << (b & (XLEN - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
DART_FORCE_INLINE
|
DART_FORCE_INLINE
|
||||||
void Simulator::InterpretOPIMM(Instr instr) {
|
void Simulator::InterpretOPIMM(Instr instr) {
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
|
@ -1034,15 +1190,48 @@ void Simulator::InterpretOPIMM(Instr instr) {
|
||||||
break;
|
break;
|
||||||
case ANDI:
|
case ANDI:
|
||||||
set_xreg(instr.rd(), get_xreg(instr.rs1()) & instr.itype_imm());
|
set_xreg(instr.rd(), get_xreg(instr.rs1()) & instr.itype_imm());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SLLI:
|
case SLLI:
|
||||||
set_xreg(instr.rd(), get_xreg(instr.rs1()) << instr.shamt());
|
if (instr.funct7() == COUNT) {
|
||||||
|
if (instr.shamt() == 0b00000) {
|
||||||
|
set_xreg(instr.rd(), clz(get_xreg(instr.rs1())));
|
||||||
|
} else if (instr.shamt() == 0b00001) {
|
||||||
|
set_xreg(instr.rd(), ctz(get_xreg(instr.rs1())));
|
||||||
|
} else if (instr.shamt() == 0b00010) {
|
||||||
|
set_xreg(instr.rd(), cpop(get_xreg(instr.rs1())));
|
||||||
|
} else if (instr.shamt() == 0b00100) {
|
||||||
|
set_xreg(instr.rd(), sextb(get_xreg(instr.rs1())));
|
||||||
|
} else if (instr.shamt() == 0b00101) {
|
||||||
|
set_xreg(instr.rd(), sexth(get_xreg(instr.rs1())));
|
||||||
|
} else {
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
|
||||||
|
set_xreg(instr.rd(), bclr(get_xreg(instr.rs1()), instr.shamt()));
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BINV) {
|
||||||
|
set_xreg(instr.rd(), binv(get_xreg(instr.rs1()), instr.shamt()));
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BSET) {
|
||||||
|
set_xreg(instr.rd(), bset(get_xreg(instr.rs1()), instr.shamt()));
|
||||||
|
} else {
|
||||||
|
set_xreg(instr.rd(), get_xreg(instr.rs1()) << instr.shamt());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SRI:
|
case SRI:
|
||||||
if ((instr.funct7() & 0b1111110) == SRA) {
|
if ((instr.funct7() & 0b1111110) == SRA) {
|
||||||
set_xreg(instr.rd(),
|
set_xreg(instr.rd(),
|
||||||
static_cast<intx_t>(get_xreg(instr.rs1())) >> instr.shamt());
|
static_cast<intx_t>(get_xreg(instr.rs1())) >> instr.shamt());
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == ROTATE) {
|
||||||
|
set_xreg(instr.rd(), ror(get_xreg(instr.rs1()), instr.shamt()));
|
||||||
|
} else if (instr.funct7() == 0b0010100) {
|
||||||
|
set_xreg(instr.rd(), orcb(get_xreg(instr.rs1())));
|
||||||
|
#if XLEN == 32
|
||||||
|
} else if (instr.funct7() == 0b0110100) {
|
||||||
|
#else
|
||||||
|
} else if (instr.funct7() == 0b0110101) {
|
||||||
|
#endif
|
||||||
|
set_xreg(instr.rd(), rev8(get_xreg(instr.rs1())));
|
||||||
|
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
|
||||||
|
set_xreg(instr.rd(), bext(get_xreg(instr.rs1()), instr.shamt()));
|
||||||
} else {
|
} else {
|
||||||
set_xreg(instr.rd(),
|
set_xreg(instr.rd(),
|
||||||
static_cast<uintx_t>(get_xreg(instr.rs1())) >> instr.shamt());
|
static_cast<uintx_t>(get_xreg(instr.rs1())) >> instr.shamt());
|
||||||
|
@ -1064,9 +1253,25 @@ void Simulator::InterpretOPIMM32(Instr instr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SLLI: {
|
case SLLI: {
|
||||||
uint32_t a = get_xreg(instr.rs1());
|
if (instr.funct7() == SLLIUW) {
|
||||||
uint32_t b = instr.shamt();
|
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
|
||||||
set_xreg(instr.rd(), sign_extend(a << b));
|
uintx_t b = instr.shamt();
|
||||||
|
set_xreg(instr.rd(), a << b);
|
||||||
|
} else if (instr.funct7() == COUNT) {
|
||||||
|
if (instr.shamt() == 0b00000) {
|
||||||
|
set_xreg(instr.rd(), clzw(get_xreg(instr.rs1())));
|
||||||
|
} else if (instr.shamt() == 0b00001) {
|
||||||
|
set_xreg(instr.rd(), ctzw(get_xreg(instr.rs1())));
|
||||||
|
} else if (instr.shamt() == 0b00010) {
|
||||||
|
set_xreg(instr.rd(), cpopw(get_xreg(instr.rs1())));
|
||||||
|
} else {
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t a = get_xreg(instr.rs1());
|
||||||
|
uint32_t b = instr.shamt();
|
||||||
|
set_xreg(instr.rd(), sign_extend(a << b));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SRI:
|
case SRI:
|
||||||
|
@ -1074,6 +1279,8 @@ void Simulator::InterpretOPIMM32(Instr instr) {
|
||||||
int32_t a = get_xreg(instr.rs1());
|
int32_t a = get_xreg(instr.rs1());
|
||||||
int32_t b = instr.shamt();
|
int32_t b = instr.shamt();
|
||||||
set_xreg(instr.rd(), sign_extend(a >> b));
|
set_xreg(instr.rd(), sign_extend(a >> b));
|
||||||
|
} else if (instr.funct7() == ROTATE) {
|
||||||
|
set_xreg(instr.rd(), rorw(get_xreg(instr.rs1()), instr.shamt()));
|
||||||
} else {
|
} else {
|
||||||
uint32_t a = get_xreg(instr.rs1());
|
uint32_t a = get_xreg(instr.rs1());
|
||||||
uint32_t b = instr.shamt();
|
uint32_t b = instr.shamt();
|
||||||
|
@ -1098,6 +1305,32 @@ void Simulator::InterpretOP(Instr instr) {
|
||||||
case MULDIV:
|
case MULDIV:
|
||||||
InterpretOP_MULDIV(instr);
|
InterpretOP_MULDIV(instr);
|
||||||
break;
|
break;
|
||||||
|
case SHADD:
|
||||||
|
InterpretOP_SHADD(instr);
|
||||||
|
break;
|
||||||
|
case MINMAXCLMUL:
|
||||||
|
InterpretOP_MINMAXCLMUL(instr);
|
||||||
|
break;
|
||||||
|
case ROTATE:
|
||||||
|
InterpretOP_ROTATE(instr);
|
||||||
|
break;
|
||||||
|
case BCLRBEXT:
|
||||||
|
InterpretOP_BCLRBEXT(instr);
|
||||||
|
break;
|
||||||
|
case BINV:
|
||||||
|
set_xreg(instr.rd(), binv(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
pc_ += instr.length();
|
||||||
|
break;
|
||||||
|
case BSET:
|
||||||
|
set_xreg(instr.rd(), bset(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
pc_ += instr.length();
|
||||||
|
break;
|
||||||
|
#if XLEN == 32
|
||||||
|
case 0b0000100:
|
||||||
|
set_xreg(instr.rd(), zexth(get_xreg(instr.rs1())));
|
||||||
|
pc_ += instr.length();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
IllegalInstruction(instr);
|
IllegalInstruction(instr);
|
||||||
}
|
}
|
||||||
|
@ -1331,6 +1564,98 @@ void Simulator::InterpretOP_SUB(Instr instr) {
|
||||||
set_xreg(instr.rd(), static_cast<intx_t>(get_xreg(instr.rs1())) >> shamt);
|
set_xreg(instr.rd(), static_cast<intx_t>(get_xreg(instr.rs1())) >> shamt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case AND:
|
||||||
|
set_xreg(instr.rd(), get_xreg(instr.rs1()) & ~get_xreg(instr.rs2()));
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
set_xreg(instr.rd(), get_xreg(instr.rs1()) | ~get_xreg(instr.rs2()));
|
||||||
|
break;
|
||||||
|
case XOR:
|
||||||
|
set_xreg(instr.rd(), get_xreg(instr.rs1()) ^ ~get_xreg(instr.rs2()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP_SHADD(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case SH1ADD:
|
||||||
|
set_xreg(instr.rd(),
|
||||||
|
(get_xreg(instr.rs1()) << 1) + get_xreg(instr.rs2()));
|
||||||
|
break;
|
||||||
|
case SH2ADD:
|
||||||
|
set_xreg(instr.rd(),
|
||||||
|
(get_xreg(instr.rs1()) << 2) + get_xreg(instr.rs2()));
|
||||||
|
break;
|
||||||
|
case SH3ADD:
|
||||||
|
set_xreg(instr.rd(),
|
||||||
|
(get_xreg(instr.rs1()) << 3) + get_xreg(instr.rs2()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP_MINMAXCLMUL(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case MAX:
|
||||||
|
set_xreg(instr.rd(), max(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case MAXU:
|
||||||
|
set_xreg(instr.rd(), maxu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case MIN:
|
||||||
|
set_xreg(instr.rd(), min(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case MINU:
|
||||||
|
set_xreg(instr.rd(), minu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case CLMUL:
|
||||||
|
set_xreg(instr.rd(), clmul(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case CLMULH:
|
||||||
|
set_xreg(instr.rd(),
|
||||||
|
clmulh(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case CLMULR:
|
||||||
|
set_xreg(instr.rd(),
|
||||||
|
clmulr(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP_ROTATE(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case ROR:
|
||||||
|
set_xreg(instr.rd(), ror(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case ROL:
|
||||||
|
set_xreg(instr.rd(), rol(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP_BCLRBEXT(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case BCLR:
|
||||||
|
set_xreg(instr.rd(), bclr(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case BEXT:
|
||||||
|
set_xreg(instr.rd(), bext(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
IllegalInstruction(instr);
|
IllegalInstruction(instr);
|
||||||
}
|
}
|
||||||
|
@ -1350,6 +1675,15 @@ void Simulator::InterpretOP32(Instr instr) {
|
||||||
case MULDIV:
|
case MULDIV:
|
||||||
InterpretOP32_MULDIV(instr);
|
InterpretOP32_MULDIV(instr);
|
||||||
break;
|
break;
|
||||||
|
case SHADD:
|
||||||
|
InterpretOP32_SHADD(instr);
|
||||||
|
break;
|
||||||
|
case ADDUW:
|
||||||
|
InterpretOP32_ADDUW(instr);
|
||||||
|
break;
|
||||||
|
case ROTATE:
|
||||||
|
InterpretOP32_ROTATE(instr);
|
||||||
|
break;
|
||||||
#endif // XLEN >= 64
|
#endif // XLEN >= 64
|
||||||
default:
|
default:
|
||||||
IllegalInstruction(instr);
|
IllegalInstruction(instr);
|
||||||
|
@ -1439,6 +1773,68 @@ void Simulator::InterpretOP32_MULDIV(Instr instr) {
|
||||||
pc_ += instr.length();
|
pc_ += instr.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP32_SHADD(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case SH1ADD: {
|
||||||
|
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
|
||||||
|
uintx_t b = get_xreg(instr.rs2());
|
||||||
|
set_xreg(instr.rd(), (a << 1) + b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SH2ADD: {
|
||||||
|
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
|
||||||
|
uintx_t b = get_xreg(instr.rs2());
|
||||||
|
set_xreg(instr.rd(), (a << 2) + b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SH3ADD: {
|
||||||
|
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
|
||||||
|
uintx_t b = get_xreg(instr.rs2());
|
||||||
|
set_xreg(instr.rd(), (a << 3) + b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP32_ADDUW(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
#if XLEN >= 64
|
||||||
|
case F3_0: {
|
||||||
|
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
|
||||||
|
uintx_t b = get_xreg(instr.rs2());
|
||||||
|
set_xreg(instr.rd(), a + b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZEXT:
|
||||||
|
set_xreg(instr.rd(), zexth(get_xreg(instr.rs1())));
|
||||||
|
break;
|
||||||
|
#endif // XLEN >= 64
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
DART_FORCE_INLINE
|
||||||
|
void Simulator::InterpretOP32_ROTATE(Instr instr) {
|
||||||
|
switch (instr.funct3()) {
|
||||||
|
case ROR:
|
||||||
|
set_xreg(instr.rd(), rorw(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
case ROL:
|
||||||
|
set_xreg(instr.rd(), rolw(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
IllegalInstruction(instr);
|
||||||
|
}
|
||||||
|
pc_ += instr.length();
|
||||||
|
}
|
||||||
|
|
||||||
void Simulator::InterpretMISCMEM(Instr instr) {
|
void Simulator::InterpretMISCMEM(Instr instr) {
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
case FENCE:
|
case FENCE:
|
||||||
|
@ -2295,10 +2691,10 @@ void Simulator::InterpretOPFP(Instr instr) {
|
||||||
float rs1 = get_fregs(instr.frs1());
|
float rs1 = get_fregs(instr.frs1());
|
||||||
float rs2 = get_fregs(instr.frs2());
|
float rs2 = get_fregs(instr.frs2());
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
case MIN:
|
case FMIN:
|
||||||
set_fregs(instr.frd(), rv_fminf(rs1, rs2));
|
set_fregs(instr.frd(), rv_fminf(rs1, rs2));
|
||||||
break;
|
break;
|
||||||
case MAX:
|
case FMAX:
|
||||||
set_fregs(instr.frd(), rv_fmaxf(rs1, rs2));
|
set_fregs(instr.frd(), rv_fmaxf(rs1, rs2));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2449,10 +2845,10 @@ void Simulator::InterpretOPFP(Instr instr) {
|
||||||
double rs1 = get_fregd(instr.frs1());
|
double rs1 = get_fregd(instr.frs1());
|
||||||
double rs2 = get_fregd(instr.frs2());
|
double rs2 = get_fregd(instr.frs2());
|
||||||
switch (instr.funct3()) {
|
switch (instr.funct3()) {
|
||||||
case MIN:
|
case FMIN:
|
||||||
set_fregd(instr.frd(), rv_fmin(rs1, rs2));
|
set_fregd(instr.frd(), rv_fmin(rs1, rs2));
|
||||||
break;
|
break;
|
||||||
case MAX:
|
case FMAX:
|
||||||
set_fregd(instr.frd(), rv_fmax(rs1, rs2));
|
set_fregd(instr.frd(), rv_fmax(rs1, rs2));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -208,10 +208,17 @@ class Simulator {
|
||||||
void InterpretOP_0(Instr instr);
|
void InterpretOP_0(Instr instr);
|
||||||
void InterpretOP_SUB(Instr instr);
|
void InterpretOP_SUB(Instr instr);
|
||||||
void InterpretOP_MULDIV(Instr instr);
|
void InterpretOP_MULDIV(Instr instr);
|
||||||
|
void InterpretOP_SHADD(Instr instr);
|
||||||
|
void InterpretOP_MINMAXCLMUL(Instr instr);
|
||||||
|
void InterpretOP_ROTATE(Instr instr);
|
||||||
|
void InterpretOP_BCLRBEXT(Instr instr);
|
||||||
void InterpretOP32(Instr instr);
|
void InterpretOP32(Instr instr);
|
||||||
void InterpretOP32_0(Instr instr);
|
void InterpretOP32_0(Instr instr);
|
||||||
void InterpretOP32_SUB(Instr instr);
|
void InterpretOP32_SUB(Instr instr);
|
||||||
void InterpretOP32_MULDIV(Instr instr);
|
void InterpretOP32_MULDIV(Instr instr);
|
||||||
|
void InterpretOP32_SHADD(Instr instr);
|
||||||
|
void InterpretOP32_ADDUW(Instr instr);
|
||||||
|
void InterpretOP32_ROTATE(Instr instr);
|
||||||
void InterpretMISCMEM(Instr instr);
|
void InterpretMISCMEM(Instr instr);
|
||||||
void InterpretSYSTEM(Instr instr);
|
void InterpretSYSTEM(Instr instr);
|
||||||
void InterpretECALL(Instr instr);
|
void InterpretECALL(Instr instr);
|
||||||
|
|
Loading…
Reference in a new issue