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