Extend test coverage for kelvin_encoder PiperOrigin-RevId: 558820949
diff --git a/sim/kelvin_encoding.cc b/sim/kelvin_encoding.cc index 9e3eee4..6f4d1dc 100644 --- a/sim/kelvin_encoding.cc +++ b/sim/kelvin_encoding.cc
@@ -397,7 +397,7 @@ auto sz = encoding::kelvin_v2_args_type::ExtractSz(inst_word_); auto func2_ignore_unsigned = func2 & (~(1u << 0)); - // Func1 0b100 VAcc[u] needs 2x src1 registers. + // Func1 0b100 VAcc.[h,w].[u] needs 2x src1 registers. if ((func1 == 0b100) && (func2_ignore_unsigned == 0b1010)) { return 2; }
diff --git a/sim/test/BUILD b/sim/test/BUILD index 6e1ac0a..76ad1e3 100644 --- a/sim/test/BUILD +++ b/sim/test/BUILD
@@ -21,6 +21,7 @@ "//sim:kelvin_state", "@com_google_googletest//:gtest_main", "@com_google_mpact-riscv//riscv:riscv_state", + "@com_google_mpact-sim//mpact/sim/generic:arch_state", ], )
diff --git a/sim/test/kelvin_encoding_test.cc b/sim/test/kelvin_encoding_test.cc index 66ec918..d962321 100644 --- a/sim/test/kelvin_encoding_test.cc +++ b/sim/test/kelvin_encoding_test.cc
@@ -1,11 +1,14 @@ #include "sim/kelvin_encoding.h" +#include <any> #include <cstdint> +#include <type_traits> #include "sim/kelvin_enums.h" #include "sim/kelvin_state.h" #include "googletest/include/gtest/gtest.h" #include "riscv/riscv_register.h" +#include "mpact/sim/generic/register.h" namespace { @@ -15,6 +18,11 @@ using OpcodeEnum = kelvin::sim::isa32::OpcodeEnum; using SourceOpEnum = kelvin::sim::isa32::SourceOpEnum; using RV32VectorSourceOperand = mpact::sim::riscv::RV32VectorSourceOperand; +using RV32SourceOperand = mpact::sim::generic::RegisterSourceOperand<uint64_t>; +using DestOpEnum = kelvin::sim::isa32::DestOpEnum; +using RV32VectorDestOperand = mpact::sim::riscv::RV32VectorDestinationOperand; +using RV32DestOperand = + mpact::sim::generic::RegisterDestinationOperand<uint64_t>; // RV32I constexpr uint32_t kLui = 0b0000000000000000000000000'0110111; @@ -100,13 +108,20 @@ delete state_; } - RV32VectorSourceOperand *VectorSourceEncodeHelper( - uint32_t inst_word, OpcodeEnum opcode, SourceOpEnum source_op) const { + template <typename T> + T *EncodeOpHelper(uint32_t inst_word, OpcodeEnum opcode, std::any op) const { enc_->ParseInstruction(inst_word); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), opcode); - auto source = enc_->GetSource(SlotEnum::kKelvin, 0, opcode, source_op, 0); - return reinterpret_cast<mpact::sim::riscv::RV32VectorSourceOperand *>( - source); + if (std::is_same<T, RV32SourceOperand>::value || + std::is_same<T, RV32VectorSourceOperand>::value) { + auto *source = enc_->GetSource(SlotEnum::kKelvin, 0, opcode, + std::any_cast<SourceOpEnum>(op), 0); + return reinterpret_cast<T *>(source); + } + auto *dest = enc_->GetDestination(SlotEnum::kKelvin, 0, opcode, + std::any_cast<DestOpEnum>(op), 0, + /*latency=*/0); + return reinterpret_cast<T *>(dest); } KelvinState *state_; @@ -137,6 +152,10 @@ return (iword | ((succ & 0xf) << 20)); } +static inline uint32_t SetSz(uint32_t iword, uint32_t sz) { + return (iword | ((sz & 0x3) << 12)); +} + TEST_F(KelvinEncodingTest, RV32IOpcodes) { enc_->ParseInstruction(SetRd(kLui, kRdValue)); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLui); @@ -252,16 +271,6 @@ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kKlog); } -TEST_F(KelvinEncodingTest, KelvinVldOpcodes) { - enc_->ParseInstruction(SetRs1(kVld, kRdValue)); - EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldBX); - enc_->ParseInstruction(SetRs1(kVld, kRdValue) | (0b01 << 12 /* sz */)); - EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldHX); - enc_->ParseInstruction(SetRs1(kVld, kRdValue) | (0b10 << 12 /* sz */) | - (0b10 << 20 /* xs2 */) | (0b1 << 26 /* length */)); - EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldWLXx); -} - TEST_F(KelvinEncodingTest, ZifenceiOpcodes) { // RV32 Zifencei enc_->ParseInstruction(kFencei); @@ -316,40 +325,160 @@ EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kRemu); } -TEST_F(KelvinEncodingTest, VsraxsWideningVs1) { +TEST_F(KelvinEncodingTest, KelvinVldEncodeXs1Xs2) { + enc_->ParseInstruction(SetRs1(kVld, kRdValue)); + EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldBX); + enc_->ParseInstruction(SetSz(SetRs1(kVld, kRdValue), 0b1)); + EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kVldHX); + // Test vld.w.l.xx + auto *src = EncodeOpHelper<RV32SourceOperand>( + SetSz(SetRs1(kVld, kRdValue), 0b10) | (0b10 << 20 /* xs2 */) | + (0b1 << 26 /* length */), + OpcodeEnum::kVldWLXx, SourceOpEnum::kVs1); + EXPECT_EQ(src->AsString(), "ra"); + delete src; + src = EncodeOpHelper<RV32SourceOperand>( + SetSz(SetRs1(kVld, kRdValue), 0b10) | (0b10 << 20 /* xs2 */) | + (0b1 << 26 /* length */), + OpcodeEnum::kVldWLXx, SourceOpEnum::kVs2); + EXPECT_EQ(src->AsString(), "sp"); + delete src; +} + +TEST_F(KelvinEncodingTest, KelvinVstEncodeXs1Xs2Vd) { + constexpr uint32_t kVstBase = 0b001000'000000'000000'00'000000'0'111'11; + // Test vd in vst.b.x as source + auto *v_src = EncodeOpHelper<RV32VectorSourceOperand>( + SetRs1(kVstBase, kRdValue), OpcodeEnum::kVstBX, SourceOpEnum::kVd); + EXPECT_EQ(v_src->AsString(), "v0"); + delete v_src; + + // Test xs1 in vst.w.l.xx as destination + auto *dest = EncodeOpHelper<RV32DestOperand>( + SetSz(SetRs1(kVstBase, kRdValue), 0b10) | (0b10 << 20 /* xs2 */) | + (1 << 26 /* length */), + OpcodeEnum::kVstWLXx, DestOpEnum::kVs1); + EXPECT_EQ(dest->AsString(), "ra"); + delete dest; + + // Test xs2 in vstq.b.s.xx as source + auto *src = EncodeOpHelper<RV32SourceOperand>( + SetRs1(kVstBase, kRdValue) | (1 << 30 /* vstq */) | + (0b10 << 20 /* xs2 */) | (1 << 27 /* stride */), + OpcodeEnum::kVstqBSXx, SourceOpEnum::kVs2); + EXPECT_EQ(src->AsString(), "sp"); + delete src; +} + +TEST_F(KelvinEncodingTest, KelvinWideningVs1) { constexpr uint32_t kVSransBase = 0b010000'000001'000000'00'001000'0'010'00; - auto v_src = VectorSourceEncodeHelper(kVSransBase, OpcodeEnum::kVsransBVv, - SourceOpEnum::kVs1); + auto *v_src = EncodeOpHelper<RV32VectorSourceOperand>( + kVSransBase, OpcodeEnum::kVsransBVv, SourceOpEnum::kVs1); EXPECT_EQ(v_src->size(), 2); delete v_src; // Test vsrans.b.r.vv - v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 27), - OpcodeEnum::kVsransBRVv, SourceOpEnum::kVs1); + v_src = EncodeOpHelper<RV32VectorSourceOperand>( + kVSransBase | (1 << 27 /* vsrans.r */), OpcodeEnum::kVsransBRVv, + SourceOpEnum::kVs1); EXPECT_EQ(v_src->size(), 2); delete v_src; // Test vsrans.h.vv - v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 12), - OpcodeEnum::kVsransHVv, SourceOpEnum::kVs1); + v_src = EncodeOpHelper<RV32VectorSourceOperand>( + SetSz(kVSransBase, 0b1), OpcodeEnum::kVsransHVv, SourceOpEnum::kVs1); EXPECT_EQ(v_src->size(), 2); delete v_src; // Test vsraqs.b.vv - v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 29), - OpcodeEnum::kVsraqsBVv, SourceOpEnum::kVs1); + v_src = EncodeOpHelper<RV32VectorSourceOperand>( + kVSransBase | (1 << 29 /* vsraqs */), OpcodeEnum::kVsraqsBVv, + SourceOpEnum::kVs1); EXPECT_EQ(v_src->size(), 4); delete v_src; // Test vsraqs.b.r.vv - v_src = VectorSourceEncodeHelper(kVSransBase | (1 << 29) | (1 << 27), - OpcodeEnum::kVsraqsBRVv, SourceOpEnum::kVs1); + v_src = EncodeOpHelper<RV32VectorSourceOperand>( + kVSransBase | (1 << 29) | (1 << 27), OpcodeEnum::kVsraqsBRVv, + SourceOpEnum::kVs1); EXPECT_EQ(v_src->size(), 4); delete v_src; // Test illegal vsrans (vsrans.w.vv) - enc_->ParseInstruction(kVSransBase | (2 << 12)); + enc_->ParseInstruction(SetSz(kVSransBase, 0b10)); EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kNone); + + // Test vacc.h.vv + constexpr uint32_t kVAccsBase = 0b001010'000001'000000'00'001000'0'100'00; + v_src = EncodeOpHelper<RV32VectorSourceOperand>( + SetSz(kVAccsBase, 0b1), OpcodeEnum::kVaccHVv, SourceOpEnum::kVs1); + EXPECT_EQ(v_src->size(), 2); + delete v_src; + + // Test vacc.w.u.vv + v_src = EncodeOpHelper<RV32VectorSourceOperand>( + SetSz(kVAccsBase, 0b10) | (1 << 26), OpcodeEnum::kVaccWUVv, + SourceOpEnum::kVs1); + EXPECT_EQ(v_src->size(), 2); + delete v_src; +} + +TEST_F(KelvinEncodingTest, KelvinWideningVd) { + // No widening for vld + auto *v_dest = EncodeOpHelper<RV32VectorDestOperand>( + SetRs1(kVld, kRdValue), OpcodeEnum::kVldBX, DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 1); + delete v_dest; + + // Test vaddw.h.vv + constexpr uint32_t kVAddwBase = 0b000100'000001'000000'00'001000'0'100'00; + v_dest = EncodeOpHelper<RV32VectorDestOperand>( + SetSz(kVAddwBase, 0b1), OpcodeEnum::kVaddwHVv, DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; + + // Test vsubw.w.u.vv + v_dest = EncodeOpHelper<RV32VectorDestOperand>( + SetSz(kVAddwBase, 0b10) | (0b11 << 26 /* vsubw.u */), + OpcodeEnum::kVsubwWUVv, DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; + + // Test vmvp.vv + constexpr uint32_t kVMvpBase = 0b001101'000001'000000'00'001000'0'001'00; + v_dest = EncodeOpHelper<RV32VectorDestOperand>(kVMvpBase, OpcodeEnum::kVmvpVv, + DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; + + // Test vmulw.h.vv + constexpr uint32_t kVMulwBase = 0b000100'000001'000000'00'001000'0'011'00; + v_dest = EncodeOpHelper<RV32VectorDestOperand>( + SetSz(kVMulwBase, 0b1), OpcodeEnum::kVmulwHVv, DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; + + // Test vmulw.w.u.vv + v_dest = EncodeOpHelper<RV32VectorDestOperand>( + SetSz(kVMulwBase, 0b10) | (1 << 26 /* vmulw.u */), OpcodeEnum::kVmulwWUVv, + DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; + + // Test vevnodd.b.vv + constexpr uint32_t kVEvnoddBase = 0b011000'000001'000000'00'001000'0'110'00; + v_dest = EncodeOpHelper<RV32VectorDestOperand>( + kVEvnoddBase | (0b10 << 26 /* vevenodd */), OpcodeEnum::kVevnoddBVv, + DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; + + // Test vzip.h.vv + v_dest = EncodeOpHelper<RV32VectorDestOperand>( + SetSz(kVEvnoddBase, 0b1) | (0b100 << 26 /* vzip */), OpcodeEnum::kVzipHVv, + DestOpEnum::kVd); + EXPECT_EQ(v_dest->size(), 2); + delete v_dest; } } // namespace