Split Zfh32 and Zfh64 isa and bin_fmt

Adjust the encoding and tests to cover Zfh64 as well.

PiperOrigin-RevId: 764813758
Change-Id: I54f5192fcc3299ca1a7dc95ad0b7079a2e2648aa
diff --git a/riscv/BUILD b/riscv/BUILD
index 962213f..ca708da 100644
--- a/riscv/BUILD
+++ b/riscv/BUILD
@@ -678,11 +678,24 @@
 )
 
 mpact_isa_decoder(
-    name = "zfh_isa",
+    name = "zfh32_isa",
     src = "riscv_zfh.isa",
     includes = [],
-    isa_name = "ZFH",
-    prefix = "zfh",
+    isa_name = "ZFH32",
+    prefix = "zfh32",
+    deps = [
+        ":riscv_g",
+        ":riscv_zfh_instructions",
+        "@com_google_absl//absl/functional:bind_front",
+    ],
+)
+
+mpact_isa_decoder(
+    name = "zfh64_isa",
+    src = "riscv_zfh.isa",
+    includes = [],
+    isa_name = "ZFH64",
+    prefix = "zfh64",
     deps = [
         ":riscv_g",
         ":riscv_zfh_instructions",
@@ -691,15 +704,28 @@
 )
 
 mpact_bin_fmt_decoder(
-    name = "zfh_bin_fmt",
-    src = "riscv_zfh.bin_fmt",
+    name = "zfh32_bin_fmt",
+    src = "riscv_zfh32.bin_fmt",
     decoder_name = "ZFH",
     includes = [
         "riscv32g.bin_fmt",
     ],
-    prefix = "zfh",
+    prefix = "zfh32",
     deps = [
-        ":zfh_isa",
+        ":zfh32_isa",
+    ],
+)
+
+mpact_bin_fmt_decoder(
+    name = "zfh64_bin_fmt",
+    src = "riscv_zfh64.bin_fmt",
+    decoder_name = "ZFH",
+    includes = [
+        "riscv32g.bin_fmt",
+    ],
+    prefix = "zfh64",
+    deps = [
+        ":zfh64_isa",
     ],
 )
 
diff --git a/riscv/riscv_zfh.isa b/riscv/riscv_zfh.isa
index 66c944d..5aec5ae 100644
--- a/riscv/riscv_zfh.isa
+++ b/riscv/riscv_zfh.isa
@@ -15,13 +15,20 @@
 // This file contains the ISA description of the RiscV ZFH extention
 // instructions.
 
-isa ZFH {
-  namespace mpact::sim::riscv::zfh;
+isa ZFH32 {
+  namespace mpact::sim::riscv::zfh32;
   slots {
     riscv32_zfh;
   }
 }
 
+isa ZFH64 {
+  namespace mpact::sim::riscv::zfh64;
+  slots {
+    riscv64_zfh;
+  }
+}
+
 // First disasm field is 18 char wide and left justified.
 disasm widths = {-18};
 
@@ -97,7 +104,7 @@
   opcodes {
     flh{(: rs1, I_imm12 : ), (: : frd)},
       resources: {next_pc, rs1 : frd[0..]},
-      semfunc: "&RV64::RiscVILhu", "&RV64::RiscVZfhFlhChild",
+      semfunc: "&RV64::RiscVILhu", "&RiscVZfhFlhChild",
       disasm: "flh", "%frd, %I_imm12(%rs1)";
     fsh{: rs1, S_imm12, frs2},
       resources: {next_pc, rs1, frs2},
diff --git a/riscv/riscv_zfh.bin_fmt b/riscv/riscv_zfh32.bin_fmt
similarity index 94%
rename from riscv/riscv_zfh.bin_fmt
rename to riscv/riscv_zfh32.bin_fmt
index 7ed55d4..9a49ae9 100644
--- a/riscv/riscv_zfh.bin_fmt
+++ b/riscv/riscv_zfh32.bin_fmt
@@ -15,15 +15,15 @@
 #include "riscv/riscv32g.bin_fmt"
 
 decoder ZFH {
-  namespace mpact::sim::riscv::zfh;
+  namespace mpact::sim::riscv::zfh32;
   opcode_enum = "OpcodeEnum";
   includes {
-    #include "riscv/zfh_decoder.h"
+    #include "riscv/zfh32_decoder.h"
   }
-  RiscVZfhInst32 = { RiscVZfhminInst32 };
+  RiscVZfhInst32 = { RiscVZfh32Inst32 };
 }
 
-instruction group RiscVZfhminInst32[32] : Inst32Format {
+instruction group RiscVZfh32Inst32[32] : Inst32Format {
   flh      : IType : func3 == 0b001,  opcode == 0b000'0111;
   fsh      : SType : func3 == 0b001,  opcode == 0b010'0111;
   fmv_xh   : RType : func7 == 0b1110010, rs2 == 0, func3 == 0b000, opcode == 0b1010011;
diff --git a/riscv/riscv_zfh.bin_fmt b/riscv/riscv_zfh64.bin_fmt
similarity index 94%
copy from riscv/riscv_zfh.bin_fmt
copy to riscv/riscv_zfh64.bin_fmt
index 7ed55d4..538628c 100644
--- a/riscv/riscv_zfh.bin_fmt
+++ b/riscv/riscv_zfh64.bin_fmt
@@ -15,15 +15,15 @@
 #include "riscv/riscv32g.bin_fmt"
 
 decoder ZFH {
-  namespace mpact::sim::riscv::zfh;
+  namespace mpact::sim::riscv::zfh64;
   opcode_enum = "OpcodeEnum";
   includes {
-    #include "riscv/zfh_decoder.h"
+    #include "riscv/zfh64_decoder.h"
   }
-  RiscVZfhInst32 = { RiscVZfhminInst32 };
+  RiscVZfhInst32 = { RiscVZfh64Inst32 };
 }
 
-instruction group RiscVZfhminInst32[32] : Inst32Format {
+instruction group RiscVZfh64Inst32[32] : Inst32Format {
   flh      : IType : func3 == 0b001,  opcode == 0b000'0111;
   fsh      : SType : func3 == 0b001,  opcode == 0b010'0111;
   fmv_xh   : RType : func7 == 0b1110010, rs2 == 0, func3 == 0b000, opcode == 0b1010011;
diff --git a/riscv/test/BUILD b/riscv/test/BUILD
index fe13e35..31d9040 100644
--- a/riscv/test/BUILD
+++ b/riscv/test/BUILD
@@ -118,7 +118,6 @@
     deps = [
         "//riscv:riscv_g",
         "//riscv:riscv_state",
-        "@com_google_absl//absl/log",
         "@com_google_absl//absl/log:check",
         "@com_google_absl//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -373,7 +372,6 @@
         "zvbb_encoding_test.cc",
     ],
     deps = [
-        "//riscv:riscv32g_bitmanip_decoder",
         "//riscv:riscv_state",
         "//riscv:zvbb_decoder",
         "//riscv:zvbb_isa",
@@ -383,40 +381,23 @@
     ],
 )
 
-cc_library(
-    name = "zfh_decoder",
-    testonly = True,
-    srcs = [
-        "zfh_encoding.cc",
-    ],
-    hdrs = [
-        "riscv_getters_zfh.h",
-        "zfh_encoding.h",
-    ],
-    copts = ["-O3"],
-    deps = [
-        "//riscv:riscv_encoding_common",
-        "//riscv:riscv_getters",
-        "//riscv:riscv_state",
-        "//riscv:zfh_bin_fmt",
-        "//riscv:zfh_isa",
-        "@com_google_absl//absl/log",
-        "@com_google_absl//absl/strings",
-        "@com_google_mpact-sim//mpact/sim/generic:core",
-        "@com_google_mpact-sim//mpact/sim/generic:type_helpers",
-    ],
-)
-
 cc_test(
     name = "zfh_encoding_test",
     size = "small",
     srcs = [
+        "riscv_getters_zfh.h",
+        "zfh_encoding.h",
         "zfh_encoding_test.cc",
     ],
     deps = [
-        ":zfh_decoder",
+        "//riscv:riscv_encoding_common",
+        "//riscv:riscv_getters",
         "//riscv:riscv_state",
-        "//riscv:zfh_isa",
+        "//riscv:zfh32_bin_fmt",
+        "//riscv:zfh32_isa",
+        "//riscv:zfh64_bin_fmt",
+        "//riscv:zfh64_isa",
+        "@com_google_absl//absl/log",
         "@com_google_absl//absl/random",
         "@com_google_absl//absl/strings",
         "@com_google_googletest//:gtest_main",
@@ -588,7 +569,6 @@
         "@com_google_absl//absl/base",
         "@com_google_absl//absl/log:check",
         "@com_google_absl//absl/numeric:int128",
-        "@com_google_absl//absl/random",
         "@com_google_absl//absl/strings",
         "@com_google_googletest//:gtest_main",
         "@com_google_mpact-sim//mpact/sim/generic:instruction",
@@ -655,7 +635,6 @@
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/types:span",
         "@com_google_googletest//:gtest_main",
-        "@com_google_mpact-sim//mpact/sim/generic:core",
         "@com_google_mpact-sim//mpact/sim/generic:instruction",
         "@com_google_mpact-sim//mpact/sim/generic:type_helpers",
     ],
@@ -680,7 +659,6 @@
         "//riscv:riscv_fp_state",
         "//riscv:riscv_state",
         "//riscv:riscv_v",
-        "@com_google_absl//absl/log",
         "@com_google_absl//absl/random",
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/types:span",
@@ -776,7 +754,6 @@
         "//riscv:riscv32g_decoder",
         "//riscv:riscv64g_decoder",
         "//riscv:riscv_arm_semihost",
-        "//riscv:riscv_fp_state",
         "//riscv:riscv_state",
         "//riscv:riscv_top",
         "@com_google_absl//absl/log:check",
@@ -832,7 +809,6 @@
         "@com_google_absl//absl/log:check",
         "@com_google_googletest//:gtest_main",
         "@com_google_mpact-sim//mpact/sim/generic:core",
-        "@com_googlesource_code_re2//:re2",
     ],
 )
 
@@ -907,7 +883,6 @@
         "@com_google_googletest//:gtest_main",
         "@com_google_mpact-sim//mpact/sim/generic:core",
         "@com_google_mpact-sim//mpact/sim/generic:instruction",
-        "@com_google_mpact-sim//mpact/sim/generic:type_helpers",
     ],
 )
 
@@ -924,7 +899,6 @@
         "@com_google_googletest//:gtest_main",
         "@com_google_mpact-sim//mpact/sim/generic:core",
         "@com_google_mpact-sim//mpact/sim/generic:instruction",
-        "@com_google_mpact-sim//mpact/sim/generic:type_helpers",
     ],
 )
 
@@ -995,7 +969,6 @@
     deps = [
         ":riscv_vector_instructions_test_base",
         "//riscv:riscv_state",
-        "//riscv:riscv_v",
         "//riscv:riscv_vector_basic_bit_manipulation_instructions",
         "@com_google_absl//absl/strings",
         "@com_google_googletest//:gtest_main",
diff --git a/riscv/test/zfh_encoding.cc b/riscv/test/zfh_encoding.cc
deleted file mode 100644
index 7be9df3..0000000
--- a/riscv/test/zfh_encoding.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2025 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "riscv/test/zfh_encoding.h"
-
-#include <cstdint>
-
-#include "absl/log/log.h"
-#include "absl/strings/str_cat.h"
-#include "mpact/sim/generic/simple_resource_operand.h"
-#include "mpact/sim/generic/type_helpers.h"
-#include "riscv/riscv_getter_helpers.h"
-#include "riscv/riscv_register.h"
-#include "riscv/riscv_state.h"
-#include "riscv/test/riscv_getters_zfh.h"
-#include "riscv/zfh_bin_decoder.h"
-#include "riscv/zfh_decoder.h"
-#include "riscv/zfh_enums.h"
-
-namespace mpact::sim::riscv::zfh {
-
-using ::mpact::sim::generic::operator*;  // NOLINT: clang-tidy false positive.
-
-ZFHEncoding::ZFHEncoding(RiscVState *state)
-    : state_(state),
-      inst_word_(0),
-      opcode_(OpcodeEnum::kNone),
-      format_(FormatEnum::kNone) {
-  resource_delay_line_ =
-      state_->CreateAndAddDelayLine<generic::SimpleResourceDelayLine>(8);
-  // Initialize getters.
-  source_op_getters_.emplace(*SourceOpEnum::kNone, []() { return nullptr; });
-  dest_op_getters_.emplace(*DestOpEnum::kNone,
-                           [](int latency) { return nullptr; });
-  simple_resource_getters_.emplace(*SimpleResourceEnum::kNone,
-                                   []() { return nullptr; });
-  complex_resource_getters_.emplace(
-      *ComplexResourceEnum::kNone,
-      [](int latency, int end) { return nullptr; });
-
-  AddRiscVZfhSourceScalarGetters<SourceOpEnum, Extractors, RVXRegister>(
-      source_op_getters_, this);
-  AddRiscVZfhSourceFloatGetters<SourceOpEnum, Extractors, RVFpRegister>(
-      source_op_getters_, this);
-  AddRiscVZfhDestScalarGetters<DestOpEnum, Extractors, RVXRegister>(
-      dest_op_getters_, this);
-  AddRiscVZfhDestFloatGetters<DestOpEnum, Extractors, RVFpRegister>(
-      dest_op_getters_, this);
-  AddRiscVZfhSimpleResourceGetters<SimpleResourceEnum, Extractors>(
-      simple_resource_getters_, this);
-
-  // Verify that there are getters for each enum value.
-  for (int i = *SourceOpEnum::kNone; i < *SourceOpEnum::kPastMaxValue; ++i) {
-    if (source_op_getters_.find(i) == source_op_getters_.end()) {
-      LOG(ERROR) << "No getter for source op enum value " << i;
-    }
-  }
-  for (int i = *DestOpEnum::kNone; i < *DestOpEnum::kPastMaxValue; ++i) {
-    if (dest_op_getters_.find(i) == dest_op_getters_.end()) {
-      LOG(ERROR) << "No getter for destination op enum value " << i;
-    }
-  }
-  for (int i = *SimpleResourceEnum::kNone;
-       i < *SimpleResourceEnum::kPastMaxValue; ++i) {
-    if (simple_resource_getters_.find(i) == simple_resource_getters_.end()) {
-      LOG(ERROR) << "No getter for simple resource enum value " << i;
-    }
-  }
-}
-
-ZFHEncoding::~ZFHEncoding() { delete resource_pool_; }
-
-void ZFHEncoding::ParseInstruction(uint32_t inst_word) {
-  inst_word_ = inst_word;
-  auto [opcode, format] = DecodeRiscVZfhInst32WithFormat(inst_word_);
-  opcode_ = opcode;
-  format_ = format;
-}
-
-ResourceOperandInterface *ZFHEncoding::GetComplexResourceOperand(
-    SlotEnum, int, OpcodeEnum, ComplexResourceEnum resource, int begin,
-    int end) {
-  return nullptr;
-}
-
-ResourceOperandInterface *ZFHEncoding::GetSimpleResourceOperand(
-    SlotEnum, int, OpcodeEnum, SimpleResourceVector &resource_vec, int end) {
-  return nullptr;
-}
-
-DestinationOperandInterface *ZFHEncoding::GetDestination(SlotEnum, int,
-                                                         OpcodeEnum opcode,
-                                                         DestOpEnum dest_op,
-                                                         int dest_no,
-                                                         int latency) {
-  int index = static_cast<int>(dest_op);
-  auto iter = dest_op_getters_.find(index);
-  if (iter == dest_op_getters_.end()) {
-    LOG(ERROR) << absl::StrCat("No getter for destination op enum value ",
-                               index, "for instruction ",
-                               kOpcodeNames[static_cast<int>(opcode)]);
-    return nullptr;
-  }
-  return (iter->second)(latency);
-}
-
-SourceOperandInterface *ZFHEncoding::GetSource(SlotEnum, int, OpcodeEnum opcode,
-                                               SourceOpEnum source_op,
-                                               int source_no) {
-  int index = static_cast<int>(source_op);
-  auto iter = source_op_getters_.find(index);
-  if (iter == source_op_getters_.end()) {
-    LOG(ERROR) << absl::StrCat("No getter for source op enum value ", index,
-                               " for instruction ",
-                               kOpcodeNames[static_cast<int>(opcode)]);
-    return nullptr;
-  }
-  return (iter->second)();
-}
-
-}  // namespace mpact::sim::riscv::zfh
diff --git a/riscv/test/zfh_encoding.h b/riscv/test/zfh_encoding.h
index 9e77a56..eb7311e 100644
--- a/riscv/test/zfh_encoding.h
+++ b/riscv/test/zfh_encoding.h
@@ -18,50 +18,197 @@
 #include <cstdint>
 #include <string>
 
+#include "absl/log/log.h"
+#include "mpact/sim/generic/operand_interface.h"
 #include "mpact/sim/generic/simple_resource.h"
 #include "mpact/sim/generic/simple_resource_operand.h"
 #include "riscv/riscv_encoding_common.h"
 #include "riscv/riscv_getter_helpers.h"
+#include "riscv/riscv_register.h"
 #include "riscv/riscv_state.h"
-#include "riscv/zfh_bin_decoder.h"
-#include "riscv/zfh_decoder.h"
-#include "riscv/zfh_enums.h"
+#include "riscv/test/riscv_getters_zfh.h"
+#include "riscv/zfh32_bin_decoder.h"
+#include "riscv/zfh32_decoder.h"
+#include "riscv/zfh32_enums.h"
+#include "riscv/zfh64_bin_decoder.h"
+#include "riscv/zfh64_decoder.h"
+#include "riscv/zfh64_enums.h"
 
 namespace mpact::sim::riscv::zfh {
 
-// This class provides the interface between the generated instruction decoder
-// framework (which is agnostic of the actual bit representation of
-// instructions) and the instruction representation. This class provides methods
-// to return the opcode, source operands, and destination operands for
-// instructions according to the operand fields in the encoding.
-class ZFHEncoding : public ZFHEncodingBase, public RiscVEncodingCommon {
- public:
-  explicit ZFHEncoding(RiscVState *state);
-  ~ZFHEncoding() override;
+template <int XLen>
+class ZfhEncoding;
 
-  void ParseInstruction(uint32_t inst_word);
+template <int XLen>
+struct ZfhTraits;
+
+template <>
+struct ZfhTraits<32> {
+  using EncodingBase = ::mpact::sim::riscv::zfh32::ZFH32EncodingBase;
+  using SlotEnum = ::mpact::sim::riscv::zfh32::SlotEnum;
+  using OpcodeEnum = ::mpact::sim::riscv::zfh32::OpcodeEnum;
+  using FormatEnum = ::mpact::sim::riscv::zfh32::FormatEnum;
+  using DestOpEnum = ::mpact::sim::riscv::zfh32::DestOpEnum;
+  using SourceOpEnum = ::mpact::sim::riscv::zfh32::SourceOpEnum;
+  using ComplexResourceEnum = ::mpact::sim::riscv::zfh32::ComplexResourceEnum;
+  using SimpleResourceEnum = ::mpact::sim::riscv::zfh32::SimpleResourceEnum;
+  using PredOpEnum = ::mpact::sim::riscv::zfh32::PredOpEnum;
+  using SimpleResourceVector = ::mpact::sim::riscv::zfh32::SimpleResourceVector;
+  using Extractors = ::mpact::sim::riscv::zfh32::Extractors;
+  using XRegister = ::mpact::sim::riscv::RV32Register;
+  using SelfEncoding = ZfhEncoding<32>;
+  static constexpr int kXLen = 32;
+  static constexpr const char *const *kOpcodeNames =
+      ::mpact::sim::riscv::zfh32::kOpcodeNames;
+};
+
+template <>
+struct ZfhTraits<64> {
+  using EncodingBase = ::mpact::sim::riscv::zfh64::ZFH64EncodingBase;
+  using SlotEnum = ::mpact::sim::riscv::zfh64::SlotEnum;
+  using OpcodeEnum = ::mpact::sim::riscv::zfh64::OpcodeEnum;
+  using FormatEnum = ::mpact::sim::riscv::zfh64::FormatEnum;
+  using DestOpEnum = ::mpact::sim::riscv::zfh64::DestOpEnum;
+  using SourceOpEnum = ::mpact::sim::riscv::zfh64::SourceOpEnum;
+  using ComplexResourceEnum = ::mpact::sim::riscv::zfh64::ComplexResourceEnum;
+  using SimpleResourceEnum = ::mpact::sim::riscv::zfh64::SimpleResourceEnum;
+  using PredOpEnum = ::mpact::sim::riscv::zfh64::PredOpEnum;
+  using SimpleResourceVector = ::mpact::sim::riscv::zfh64::SimpleResourceVector;
+  using Extractors = ::mpact::sim::riscv::zfh64::Extractors;
+  using XRegister = ::mpact::sim::riscv::RV64Register;
+  using SelfEncoding = ZfhEncoding<64>;
+  static constexpr int kXLen = 64;
+  static constexpr const char *const *kOpcodeNames =
+      ::mpact::sim::riscv::zfh64::kOpcodeNames;
+};
+
+template <int XLen>
+class ZfhEncoding : public ZfhTraits<XLen>::EncodingBase,
+                    public RiscVEncodingCommon {
+ public:
+  using OpcodeEnum = ZfhTraits<XLen>::OpcodeEnum;
+  using FormatEnum = ZfhTraits<XLen>::FormatEnum;
+  using DestOpEnum = ZfhTraits<XLen>::DestOpEnum;
+  using SourceOpEnum = ZfhTraits<XLen>::SourceOpEnum;
+  using ComplexResourceEnum = ZfhTraits<XLen>::ComplexResourceEnum;
+  using SimpleResourceEnum = ZfhTraits<XLen>::SimpleResourceEnum;
+  using PredOpEnum = ZfhTraits<XLen>::PredOpEnum;
+  using SlotEnum = ZfhTraits<XLen>::SlotEnum;
+  using SimpleResourceVector = ZfhTraits<XLen>::SimpleResourceVector;
+  using Extractors = ZfhTraits<XLen>::Extractors;
+  using XRegister = ZfhTraits<XLen>::XRegister;
+
+  explicit ZfhEncoding(RiscVState *state)
+      : state_(state),
+        inst_word_(0),
+        opcode_(OpcodeEnum::kNone),
+        format_(FormatEnum::kNone) {
+    resource_delay_line_ =
+        state_->CreateAndAddDelayLine<generic::SimpleResourceDelayLine>(8);
+    // Initialize getters.
+    source_op_getters_.insert({*SourceOpEnum::kNone, []() { return nullptr; }});
+    dest_op_getters_.insert(
+        {*DestOpEnum::kNone, [](int latency) { return nullptr; }});
+    simple_resource_getters_.insert(
+        {*SimpleResourceEnum::kNone, []() { return nullptr; }});
+    complex_resource_getters_.insert(
+        {*ComplexResourceEnum::kNone,
+         [](int latency, int end) { return nullptr; }});
+
+    AddRiscVZfhSourceScalarGetters<SourceOpEnum, Extractors, XRegister>(
+        source_op_getters_, this);
+    AddRiscVZfhSourceFloatGetters<SourceOpEnum, Extractors, RVFpRegister>(
+        source_op_getters_, this);
+    AddRiscVZfhDestScalarGetters<DestOpEnum, Extractors, XRegister>(
+        dest_op_getters_, this);
+    AddRiscVZfhDestFloatGetters<DestOpEnum, Extractors, RVFpRegister>(
+        dest_op_getters_, this);
+    AddRiscVZfhSimpleResourceGetters<SimpleResourceEnum, Extractors>(
+        simple_resource_getters_, this);
+
+    // Verify that there are getters for each enum value.
+    for (int i = *SourceOpEnum::kNone; i < *SourceOpEnum::kPastMaxValue; ++i) {
+      if (!source_op_getters_.contains(i)) {
+        LOG(ERROR) << "No getter for source op enum value " << i;
+      }
+    }
+    for (int i = *DestOpEnum::kNone; i < *DestOpEnum::kPastMaxValue; ++i) {
+      if (!dest_op_getters_.contains(i)) {
+        LOG(ERROR) << "No getter for destination op enum value " << i;
+      }
+    }
+    for (int i = *SimpleResourceEnum::kNone;
+         i < *SimpleResourceEnum::kPastMaxValue; ++i) {
+      if (!simple_resource_getters_.contains(i)) {
+        LOG(ERROR) << "No getter for simple resource enum value " << i;
+      }
+    }
+  }
+
+  ~ZfhEncoding() { delete resource_pool_; }
+
+  void ParseInstruction(uint32_t inst_word) {
+    inst_word_ = inst_word;
+    if constexpr (XLen == 32) {
+      auto [opcode, format] =
+          ::mpact::sim::riscv::zfh32::DecodeRiscVZfhInst32WithFormat(
+              inst_word_);
+      opcode_ = opcode;
+      format_ = format;
+    } else {
+      auto [opcode, format] =
+          ::mpact::sim::riscv::zfh64::DecodeRiscVZfhInst32WithFormat(
+              inst_word_);
+      opcode_ = opcode;
+      format_ = format;
+    }
+  }
+
   OpcodeEnum GetOpcode(SlotEnum, int) override { return opcode_; }
   FormatEnum GetFormat(SlotEnum, int) { return format_; }
 
-  PredicateOperandInterface *GetPredicate(SlotEnum, int, OpcodeEnum,
-                                          PredOpEnum) override {
+  ::mpact::sim::generic::PredicateOperandInterface *GetPredicate(
+      SlotEnum, int, OpcodeEnum, PredOpEnum) override {
     return nullptr;
   }
 
   ResourceOperandInterface *GetSimpleResourceOperand(
-      SlotEnum, int, OpcodeEnum, SimpleResourceVector &resource_vec,
-      int end) override;
+      SlotEnum, int, OpcodeEnum, SimpleResourceVector &resource_vec, int end) {
+    return nullptr;
+  }
 
   ResourceOperandInterface *GetComplexResourceOperand(
       SlotEnum, int, OpcodeEnum, ComplexResourceEnum resource, int begin,
-      int end) override;
+      int end) {
+    return nullptr;
+  }
 
-  SourceOperandInterface *GetSource(SlotEnum, int, OpcodeEnum, SourceOpEnum op,
-                                    int source_no) override;
+  DestinationOperandInterface *GetDestination(SlotEnum, int, OpcodeEnum opcode,
+                                              DestOpEnum dest_op, int dest_no,
+                                              int latency) {
+    int index = static_cast<int>(dest_op);
+    auto iter = dest_op_getters_.find(index);
+    if (iter == dest_op_getters_.end()) {
+      LOG(ERROR) << absl::StrCat(
+          "No getter for destination op enum value ", index, "for instruction ",
+          ZfhTraits<XLen>::kOpcodeNames[static_cast<int>(opcode)]);
+      return nullptr;
+    }
+    return (iter->second)(latency);
+  }
 
-  DestinationOperandInterface *GetDestination(SlotEnum, int, OpcodeEnum,
-                                              DestOpEnum op, int dest_no,
-                                              int latency) override;
+  SourceOperandInterface *GetSource(SlotEnum, int, OpcodeEnum opcode,
+                                    SourceOpEnum source_op, int source_no) {
+    int index = static_cast<int>(source_op);
+    auto iter = source_op_getters_.find(index);
+    if (iter == source_op_getters_.end()) {
+      LOG(ERROR) << absl::StrCat(
+          "No getter for source op enum value ", index, " for instruction ",
+          ZfhTraits<XLen>::kOpcodeNames[static_cast<int>(opcode)]);
+      return nullptr;
+    }
+    return (iter->second)();
+  }
 
   int GetLatency(SlotEnum, int, OpcodeEnum, DestOpEnum, int) override {
     return 0;
@@ -97,7 +244,6 @@
   generic::SimpleResourceDelayLine *resource_delay_line_ = nullptr;
   generic::SimpleResourcePool *resource_pool_ = nullptr;
 };
-
 }  // namespace mpact::sim::riscv::zfh
 
 #endif  // THIRD_PARTY_MPACT_RISCV_TEST_ZFH_ENCODING_H_
diff --git a/riscv/test/zfh_encoding_test.cc b/riscv/test/zfh_encoding_test.cc
index f767556..044a9a4 100644
--- a/riscv/test/zfh_encoding_test.cc
+++ b/riscv/test/zfh_encoding_test.cc
@@ -20,6 +20,7 @@
 #include <ios>
 #include <memory>
 #include <tuple>
+#include <vector>
 
 #include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
@@ -30,7 +31,9 @@
 #include "mpact/sim/util/memory/flat_demand_memory.h"
 #include "riscv/riscv_register.h"
 #include "riscv/riscv_state.h"
-#include "riscv/zfh_enums.h"
+#include "riscv/zfh32_enums.h"
+#include "riscv/zfh64_enums.h"
+#include "testing/base/public/gmock.h"
 #include "testing/base/public/gunit.h"
 
 // Test that hand crafted zfh instructions are decoded and parsed correctly.
@@ -41,23 +44,11 @@
 using ::mpact::sim::generic::ImmediateOperand;
 using ::mpact::sim::generic::RegisterDestinationOperand;
 using ::mpact::sim::generic::SourceOperandInterface;
-using mpact::sim::riscv::RiscVState;
-using mpact::sim::riscv::RiscVXlen;
-using mpact::sim::riscv::RVFpRegister;
-using mpact::sim::riscv::RVXRegister;
-using mpact::sim::util::FlatDemandMemory;
-
-using mpact::sim::riscv::zfh::kComplexResourceNames;
-using mpact::sim::riscv::zfh::kDestOpNames;
-using mpact::sim::riscv::zfh::kSourceOpNames;
-
-using SlotEnum = mpact::sim::riscv::zfh::SlotEnum;
-using OpcodeEnum = mpact::sim::riscv::zfh::OpcodeEnum;
-using SourceOpEnum = mpact::sim::riscv::zfh::SourceOpEnum;
-using DestOpEnum = mpact::sim::riscv::zfh::DestOpEnum;
-using ComplexResourceEnum = mpact::sim::riscv::zfh::ComplexResourceEnum;
-
-using mpact::sim::riscv::zfh::ZFHEncoding;
+using ::mpact::sim::riscv::RiscVState;
+using ::mpact::sim::riscv::RiscVXlen;
+using ::mpact::sim::riscv::RVFpRegister;
+using ::mpact::sim::riscv::zfh::ZfhEncoding;
+using ::mpact::sim::util::FlatDemandMemory;
 
 //                           imm12      | rs1 |   | rd  | opcode
 constexpr uint32_t kFlh = 0b000000000000'00000'001'00000'0000111;
@@ -120,11 +111,53 @@
 //                              rs3  |f2| rs2 | rs1 |rm | rd  | opcode
 constexpr uint32_t kFnmsubH = 0b00000'10'00000'00000'000'00000'1001011;
 
-class ZfhEncodingTest : public testing::Test {
+struct Zfh32Config {
+  using XRegister = ::mpact::sim::riscv::RV32Register;
+  using XValue = typename XRegister::ValueType;
+  using SlotEnum = ::mpact::sim::riscv::zfh32::SlotEnum;
+  using DestOpEnum = ::mpact::sim::riscv::zfh32::DestOpEnum;
+  using SourceOpEnum = ::mpact::sim::riscv::zfh32::SourceOpEnum;
+  using OpcodeEnum = ::mpact::sim::riscv::zfh32::OpcodeEnum;
+  using ComplexResourceEnum = ::mpact::sim::riscv::zfh32::ComplexResourceEnum;
+  using SimpleResourceEnum = ::mpact::sim::riscv::zfh32::SimpleResourceEnum;
+  static constexpr RiscVXlen rvXLen = RiscVXlen::RV32;
+  static constexpr int kXLen = 32;
+  static constexpr int slot = static_cast<int>(SlotEnum::kRiscv32Zfh);
+  static constexpr const char *const *kSourceOpNames =
+      ::mpact::sim::riscv::zfh32::kSourceOpNames;
+  static constexpr const char *const *kDestOpNames =
+      ::mpact::sim::riscv::zfh32::kDestOpNames;
+  static constexpr const char *const *kComplexResourceNames =
+      ::mpact::sim::riscv::zfh32::kComplexResourceNames;
+};
+
+struct Zfh64Config {
+  using XRegister = ::mpact::sim::riscv::RV64Register;
+  using XValue = typename XRegister::ValueType;
+  using SlotEnum = ::mpact::sim::riscv::zfh64::SlotEnum;
+  using DestOpEnum = ::mpact::sim::riscv::zfh64::DestOpEnum;
+  using SourceOpEnum = ::mpact::sim::riscv::zfh64::SourceOpEnum;
+  using OpcodeEnum = ::mpact::sim::riscv::zfh64::OpcodeEnum;
+  using ComplexResourceEnum = ::mpact::sim::riscv::zfh64::ComplexResourceEnum;
+  using SimpleResourceEnum = ::mpact::sim::riscv::zfh64::SimpleResourceEnum;
+  static constexpr RiscVXlen rvXLen = RiscVXlen::RV64;
+  static constexpr int kXLen = 64;
+  static constexpr int slot = static_cast<int>(SlotEnum::kRiscv64Zfh);
+  static constexpr const char *const *kSourceOpNames =
+      ::mpact::sim::riscv::zfh64::kSourceOpNames;
+  static constexpr const char *const *kDestOpNames =
+      ::mpact::sim::riscv::zfh64::kDestOpNames;
+  static constexpr const char *const *kComplexResourceNames =
+      ::mpact::sim::riscv::zfh64::kComplexResourceNames;
+};
+
+template <typename ConfigT>
+struct ZfhEncodingTest : public testing::Test {
  protected:
   ZfhEncodingTest() {
-    state_ = new RiscVState("test", RiscVXlen::RV32, &memory_);
-    enc_ = new ZFHEncoding(state_);
+    state_ = new RiscVState("test", ConfigT::rvXLen, &memory_);
+    enc_ = new ZfhEncoding<ConfigT::kXLen>(state_);
+    expected_slot_ = static_cast<ConfigT::SlotEnum>(ConfigT::slot);
   }
 
   ~ZfhEncodingTest() override {
@@ -132,51 +165,72 @@
     delete state_;
   }
 
-  void ScalarRs1Helper(uint32_t, OpcodeEnum);
-  void FloatFrdHelper(uint32_t, OpcodeEnum);
-  void FloatSourceHelper(uint32_t, OpcodeEnum, int);
-  void FloatSourceHelper(uint32_t, OpcodeEnum, SourceOpEnum, int);
-  void FloatFrs1Helper(uint32_t, OpcodeEnum);
-  void FloatFrs2Helper(uint32_t, OpcodeEnum);
-  void FloatFrs3Helper(uint32_t, OpcodeEnum);
-  void FloatRmHelper(uint32_t, OpcodeEnum);
+  typename ConfigT::XValue RandomizeScalarRegister(int);
+  void ParseInstructionWithRs1(uint32_t, int);
+  typename ConfigT::XValue GetRs1SourceValue(typename ConfigT::OpcodeEnum);
+  void FloatFrdHelper(uint32_t, typename ConfigT::OpcodeEnum);
+  void FloatSourceHelper(uint32_t, typename ConfigT::OpcodeEnum, int);
+  void FloatSourceHelper(uint32_t, typename ConfigT::OpcodeEnum,
+                         typename ConfigT::SourceOpEnum, int);
+  void FloatFrs1Helper(uint32_t, typename ConfigT::OpcodeEnum);
+  void FloatFrs2Helper(uint32_t, typename ConfigT::OpcodeEnum);
+  void FloatFrs3Helper(uint32_t, typename ConfigT::OpcodeEnum);
+  void FloatRmHelper(uint32_t, typename ConfigT::OpcodeEnum);
+  ConfigT::OpcodeEnum GetOpcode();
 
   FlatDemandMemory memory_;
   RiscVState *state_;
-  ZFHEncoding *enc_;
+  ZfhEncoding<ConfigT::kXLen> *enc_;
   absl::BitGen gen_;
+  typename ConfigT::SlotEnum expected_slot_;
 };
 
-void ZfhEncodingTest::ScalarRs1Helper(uint32_t binary_instruction,
-                                      OpcodeEnum opcode_enum) {
-  int rs1_offset = 15;
-  uint32_t base_instruction = binary_instruction & ~(0x0000'001F << rs1_offset);
-  for (int rs1_index = 0; rs1_index < 32; ++rs1_index) {
-    uint32_t expected_value = rs1_index ? absl::Uniform<uint32_t>(gen_) : 0;
-
-    // Set the register value with a test value.
-    RVXRegister *rs1_reg;
-    std::tie(rs1_reg, std::ignore) = state_->GetRegister<RVXRegister>(
-        absl::StrCat("x", static_cast<uint32_t>(rs1_index)));
-    rs1_reg->data_buffer()->Set<uint32_t>(0, expected_value);
-
-    // Parse the instruction and get the source operand.
-    uint32_t rs1_adjustment = static_cast<uint32_t>(rs1_index) << rs1_offset;
-    enc_->ParseInstruction(base_instruction | rs1_adjustment);
-    std::unique_ptr<SourceOperandInterface> src(enc_->GetSource(
-        SlotEnum::kRiscv32Zfh, 0, opcode_enum, SourceOpEnum::kRs1, 0));
-
-    // Pull the value from the source operand and compare it to the expected
-    // value.
-    EXPECT_EQ(src->AsUint32(0), expected_value)
-        << "rs1_index: " << rs1_index << ", expected_value: " << std::hex
-        << expected_value << ", observed value: " << std::hex
-        << src->AsUint32(0);
-  }
+template <typename ConfigT>
+ConfigT::OpcodeEnum ZfhEncodingTest<ConfigT>::GetOpcode() {
+  return static_cast<ConfigT::OpcodeEnum>(enc_->GetOpcode(expected_slot_, 0));
 }
 
-void ZfhEncodingTest::FloatFrdHelper(uint32_t binary_instruction,
-                                     OpcodeEnum opcode_enum) {
+template <typename ConfigT>
+typename ConfigT::XValue ZfhEncodingTest<ConfigT>::RandomizeScalarRegister(
+    int register_index) {
+  using XRegister = typename ConfigT::XRegister;
+  using XValue = typename ConfigT::XValue;
+  XValue register_value = register_index ? absl::Uniform<XValue>(gen_) : 0;
+  XRegister *rs1_reg;
+  std::tie(rs1_reg, std::ignore) = state_->GetRegister<XRegister>(
+      absl::StrCat("x", static_cast<uint32_t>(register_index)));
+  rs1_reg->data_buffer()->template Set<XValue>(0, register_value);
+  return register_value;
+}
+
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::ParseInstructionWithRs1(
+    uint32_t binary_instruction, int rs1_index) {
+  int rs1_offset = 15;
+  uint32_t rs1_adjustment = static_cast<uint32_t>(rs1_index) << rs1_offset;
+  enc_->ParseInstruction(binary_instruction | rs1_adjustment);
+}
+
+template <typename ConfigT>
+typename ConfigT::XValue ZfhEncodingTest<ConfigT>::GetRs1SourceValue(
+    typename ConfigT::OpcodeEnum opcode_enum) {
+  using XValue = typename ConfigT::XValue;
+  std::unique_ptr<SourceOperandInterface> src(enc_->GetSource(
+      expected_slot_, 0, opcode_enum, ConfigT::SourceOpEnum::kRs1, 0));
+
+  XValue observed_value;
+  if constexpr (ConfigT::kXLen == 32) {
+    observed_value = src->AsUint32(0);
+  } else {
+    observed_value = src->AsUint64(0);
+  }
+  return observed_value;
+}
+
+// TODO: b/421177084 - Move EXPECT_* out of helpers and back to test body.
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::FloatFrdHelper(
+    uint32_t binary_instruction, typename ConfigT::OpcodeEnum opcode_enum) {
   int frd_offset = 7;
   uint32_t base_instruction = binary_instruction & ~(0x0000'001F << frd_offset);
   for (int frd_index = 0; frd_index < 32; ++frd_index) {
@@ -193,8 +247,8 @@
     enc_->ParseInstruction(base_instruction | frd_adjustment);
     std::unique_ptr<RegisterDestinationOperand<RVFpRegister>> dst(
         static_cast<RegisterDestinationOperand<RVFpRegister> *>(
-            enc_->GetDestination(SlotEnum::kRiscv32Zfh, 0, opcode_enum,
-                                 DestOpEnum::kFrd, 0, 0)));
+            enc_->GetDestination(expected_slot_, 0, opcode_enum,
+                                 ConfigT::DestOpEnum::kFrd, 0, 0)));
 
     // Pull the value from the destination operand and compare it to the
     // expected value.
@@ -206,25 +260,27 @@
   }
 }
 
-void ZfhEncodingTest::FloatSourceHelper(uint32_t binary_instruction,
-                                        OpcodeEnum opcode_enum,
-                                        SourceOpEnum source_op_enum,
-                                        int offset) {
+// TODO: b/421177084 - Move EXPECT_* out of helpers and back to test body.
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::FloatSourceHelper(
+    uint32_t binary_instruction, typename ConfigT::OpcodeEnum opcode_enum,
+    typename ConfigT::SourceOpEnum source_op_enum, int offset) {
+  using RegisterValue = typename RVFpRegister::ValueType;
   uint32_t base_instruction = binary_instruction & ~(0x0000'001F << offset);
   for (uint32_t frs1_index = 0; frs1_index < 32; ++frs1_index) {
     uint32_t src_adjustment = frs1_index << offset;
-    uint64_t expected_value = absl::Uniform<uint64_t>(gen_);
+    RegisterValue expected_value = absl::Uniform<RegisterValue>(gen_);
 
     // Set the register value with a test value.
     RVFpRegister *frs1_reg;
     std::tie(frs1_reg, std::ignore) =
         state_->GetRegister<RVFpRegister>(absl::StrCat("f", frs1_index));
-    frs1_reg->data_buffer()->Set<uint64_t>(0, expected_value);
+    frs1_reg->data_buffer()->Set<RegisterValue>(0, expected_value);
 
     // Parse the instruction and get the source operand.
     enc_->ParseInstruction(base_instruction | src_adjustment);
-    std::unique_ptr<SourceOperandInterface> src(enc_->GetSource(
-        SlotEnum::kRiscv32Zfh, 0, opcode_enum, source_op_enum, 0));
+    std::unique_ptr<SourceOperandInterface> src(
+        enc_->GetSource(expected_slot_, 0, opcode_enum, source_op_enum, 0));
 
     // Pull the value from the source operand and compare it to the expected
     // value.
@@ -235,637 +291,696 @@
   }
 }
 
-void ZfhEncodingTest::FloatFrs1Helper(uint32_t binary_instruction,
-                                      OpcodeEnum opcode_enum) {
-  FloatSourceHelper(binary_instruction, opcode_enum, SourceOpEnum::kFrs1, 15);
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::FloatFrs1Helper(
+    uint32_t binary_instruction, typename ConfigT::OpcodeEnum opcode_enum) {
+  FloatSourceHelper(binary_instruction, opcode_enum,
+                    ConfigT::SourceOpEnum::kFrs1, 15);
 }
 
-void ZfhEncodingTest::FloatFrs2Helper(uint32_t binary_instruction,
-                                      OpcodeEnum opcode_enum) {
-  FloatSourceHelper(binary_instruction, opcode_enum, SourceOpEnum::kFrs2, 20);
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::FloatFrs2Helper(
+    uint32_t binary_instruction, typename ConfigT::OpcodeEnum opcode_enum) {
+  FloatSourceHelper(binary_instruction, opcode_enum,
+                    ConfigT::SourceOpEnum::kFrs2, 20);
 }
 
-void ZfhEncodingTest::FloatFrs3Helper(uint32_t binary_instruction,
-                                      OpcodeEnum opcode_enum) {
-  FloatSourceHelper(binary_instruction, opcode_enum, SourceOpEnum::kFrs3, 27);
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::FloatFrs3Helper(
+    uint32_t binary_instruction, typename ConfigT::OpcodeEnum opcode_enum) {
+  FloatSourceHelper(binary_instruction, opcode_enum,
+                    ConfigT::SourceOpEnum::kFrs3, 27);
 }
 
-void ZfhEncodingTest::FloatRmHelper(uint32_t binary_instruction,
-                                    OpcodeEnum opcode_enum) {
+// TODO: b/421177084 - Move EXPECT_* out of helpers and back to test body.
+template <typename ConfigT>
+void ZfhEncodingTest<ConfigT>::FloatRmHelper(
+    uint32_t binary_instruction, typename ConfigT::OpcodeEnum opcode_enum) {
   for (int rm = 0; rm <= 6; ++rm) {
     uint32_t rm_adjustment = rm << 12;
     enc_->ParseInstruction(kFcvtSh | rm_adjustment);
-    std::unique_ptr<SourceOperandInterface> src(enc_->GetSource(
-        SlotEnum::kRiscv32Zfh, 0, OpcodeEnum::kFcvtSh, SourceOpEnum::kRm, 0));
+    std::unique_ptr<SourceOperandInterface> src(
+        enc_->GetSource(expected_slot_, 0, ConfigT::OpcodeEnum::kFcvtSh,
+                        ConfigT::SourceOpEnum::kRm, 0));
     EXPECT_EQ(src->AsUint32(0), rm);
   }
 }
 
-TEST_F(ZfhEncodingTest, SourceOperands) {
-  auto &getters = enc_->source_op_getters();
-  for (int i = *SourceOpEnum::kNone; i < *SourceOpEnum::kPastMaxValue; ++i) {
-    EXPECT_TRUE(getters.contains(i)) << "No source operand for enum value " << i
-                                     << " (" << kSourceOpNames[i] << ")";
+using MyTypes = ::testing::Types<Zfh32Config, Zfh64Config>;
+TYPED_TEST_SUITE(ZfhEncodingTest, MyTypes);
+
+TYPED_TEST(ZfhEncodingTest, SourceOperands) {
+  auto &getters = this->enc_->source_op_getters();
+  for (int i = *TypeParam::SourceOpEnum::kNone;
+       i < *TypeParam::SourceOpEnum::kPastMaxValue; ++i) {
+    EXPECT_TRUE(getters.contains(i))
+        << "No source operand for enum value " << i << " ("
+        << TypeParam::kSourceOpNames[i] << ")";
   }
 }
 
-TEST_F(ZfhEncodingTest, DestOperands) {
-  auto &getters = enc_->dest_op_getters();
-  for (int i = *DestOpEnum::kNone; i < *DestOpEnum::kPastMaxValue; ++i) {
-    EXPECT_TRUE(getters.contains(i)) << "No dest operand for enum value " << i
-                                     << " (" << kDestOpNames[i] << ")";
+TYPED_TEST(ZfhEncodingTest, DestOperands) {
+  auto &getters = this->enc_->dest_op_getters();
+  for (int i = *TypeParam::DestOpEnum::kNone;
+       i < *TypeParam::DestOpEnum::kPastMaxValue; ++i) {
+    EXPECT_TRUE(getters.contains(i))
+        << "No dest operand for enum value " << i << " ("
+        << TypeParam::kDestOpNames[i] << ")";
   }
 }
 
-// TODO(julianmb): Add simple resource getters when appropriate.
-// TEST_F(ZfhEncodingTest, SimpleResources) {
-//   auto &getters = enc_->simple_resource_getters();
-//   for (int i = *SimpleResourceEnum::kNone;
-//        i < *SimpleResourceEnum::kPastMaxValue; ++i) {
-//     EXPECT_TRUE(getters.contains(i)) << "No source operand for enum value "
-//     << i
-//                                      << " (" << kSimpleResourceNames[i] <<
-//                                      ")";
-//   }
-// }
+// TODO: b/420935002 - Add simple resource getters and tests when we start using
+// them.
 
-TEST_F(ZfhEncodingTest, ComplexResources) {
-  auto &getters = enc_->source_op_getters();
-  for (int i = *ComplexResourceEnum::kNone;
-       i < *ComplexResourceEnum::kPastMaxValue; ++i) {
-    EXPECT_TRUE(getters.contains(i)) << "No source operand for enum value " << i
-                                     << " (" << kComplexResourceNames[i] << ")";
+TYPED_TEST(ZfhEncodingTest, ComplexResources) {
+  auto &getters = this->enc_->source_op_getters();
+  for (int i = *TypeParam::ComplexResourceEnum::kNone;
+       i < *TypeParam::ComplexResourceEnum::kPastMaxValue; ++i) {
+    EXPECT_TRUE(getters.contains(i))
+        << "No source operand for enum value " << i << " ("
+        << TypeParam::kComplexResourceNames[i] << ")";
   }
 }
 
-TEST_F(ZfhEncodingTest, Flh) {
-  enc_->ParseInstruction(kFlh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFlh);
+TYPED_TEST(ZfhEncodingTest, Flh) {
+  this->enc_->ParseInstruction(kFlh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFlh);
 }
 
-TEST_F(ZfhEncodingTest, Flh_imm12) {
+TYPED_TEST(ZfhEncodingTest, Flh_imm12) {
   for (int iter = 0; iter < 1000; ++iter) {
     int32_t expected_imm =
-        absl::Uniform<int32_t>(gen_, -1 * (1 << 11), 1 << 11);
+        absl::Uniform<int32_t>(this->gen_, -1 * (1 << 11), 1 << 11);
     bool sign = expected_imm < 0;
     uint32_t imm_adjustment =
         (sign ? 0x8000'0000 : 0) | ((expected_imm & 0x0000'07FF) << 20);
-    enc_->ParseInstruction(kFlh | imm_adjustment);
+    this->enc_->ParseInstruction(kFlh | imm_adjustment);
     std::unique_ptr<ImmediateOperand<int32_t>> src(
-        static_cast<ImmediateOperand<int32_t> *>(
-            enc_->GetSource(SlotEnum::kRiscv32Zfh, 0, OpcodeEnum::kFlh,
-                            SourceOpEnum::kIImm12, 0)));
+        static_cast<ImmediateOperand<int32_t> *>(this->enc_->GetSource(
+            this->expected_slot_, 0, TypeParam::OpcodeEnum::kFlh,
+            TypeParam::SourceOpEnum::kIImm12, 0)));
     EXPECT_EQ(src->AsInt32(0), expected_imm);
   }
 }
 
-TEST_F(ZfhEncodingTest, Flh_rs1) { ScalarRs1Helper(kFlh, OpcodeEnum::kFlh); }
-
-TEST_F(ZfhEncodingTest, Flh_frd) { FloatFrdHelper(kFlh, OpcodeEnum::kFlh); }
-
-TEST_F(ZfhEncodingTest, Fsh) {
-  enc_->ParseInstruction(kFsh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFsh);
+TYPED_TEST(ZfhEncodingTest, Flh_rs1) {
+  using XValue = typename TypeParam::XValue;
+  std::vector<int> failed_scalar_sources;
+  for (int register_index = 0; register_index < 32; register_index++) {
+    XValue test_register_value = this->RandomizeScalarRegister(register_index);
+    this->ParseInstructionWithRs1(kFlh, register_index);
+    XValue source_value = this->GetRs1SourceValue(TypeParam::OpcodeEnum::kFlh);
+    if (source_value != test_register_value) {
+      failed_scalar_sources.push_back(register_index);
+    }
+  }
+  EXPECT_THAT(failed_scalar_sources, ::testing::IsEmpty());
 }
 
-TEST_F(ZfhEncodingTest, Fsh_imm12) {
+TYPED_TEST(ZfhEncodingTest, Flh_frd) {
+  this->FloatFrdHelper(kFlh, TypeParam::OpcodeEnum::kFlh);
+}
+
+TYPED_TEST(ZfhEncodingTest, Fsh) {
+  this->enc_->ParseInstruction(kFsh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFsh);
+}
+
+TYPED_TEST(ZfhEncodingTest, Fsh_imm12) {
   for (int iter = 0; iter < 1000; ++iter) {
     int32_t expected_imm =
-        absl::Uniform<int32_t>(gen_, -1 * (1 << 11), 1 << 11);
+        absl::Uniform<int32_t>(this->gen_, -1 * (1 << 11), 1 << 11);
     bool sign = expected_imm < 0;
     uint32_t imm_adjustment = (sign ? 0x8000'0000 : 0) |
                               ((expected_imm & 0x0000'001F) << 7) |
                               ((expected_imm & 0x0000'07E0) << 20);
-    enc_->ParseInstruction(kFsh | imm_adjustment);
+    this->enc_->ParseInstruction(kFsh | imm_adjustment);
     std::unique_ptr<ImmediateOperand<int32_t>> src(
-        static_cast<ImmediateOperand<int32_t> *>(
-            enc_->GetSource(SlotEnum::kRiscv32Zfh, 0, OpcodeEnum::kFsh,
-                            SourceOpEnum::kSImm12, 0)));
+        static_cast<ImmediateOperand<int32_t> *>(this->enc_->GetSource(
+            this->expected_slot_, 0, TypeParam::OpcodeEnum::kFsh,
+            TypeParam::SourceOpEnum::kSImm12, 0)));
     EXPECT_EQ(src->AsInt32(0), expected_imm);
   }
 }
 
-TEST_F(ZfhEncodingTest, Fsh_rs1) { ScalarRs1Helper(kFsh, OpcodeEnum::kFsh); }
-
-TEST_F(ZfhEncodingTest, Fsh_frs2) { FloatFrs2Helper(kFsh, OpcodeEnum::kFsh); }
-
-TEST_F(ZfhEncodingTest, FmvXh) {
-  enc_->ParseInstruction(kFmvXh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmvXh);
+TYPED_TEST(ZfhEncodingTest, Fsh_rs1) {
+  using XValue = typename TypeParam::XValue;
+  std::vector<int> failed_scalar_sources;
+  for (int register_index = 0; register_index < 32; register_index++) {
+    XValue test_register_value = this->RandomizeScalarRegister(register_index);
+    this->ParseInstructionWithRs1(kFsh, register_index);
+    XValue source_value = this->GetRs1SourceValue(TypeParam::OpcodeEnum::kFsh);
+    if (source_value != test_register_value) {
+      failed_scalar_sources.push_back(register_index);
+    }
+  }
+  EXPECT_THAT(failed_scalar_sources, ::testing::IsEmpty());
 }
 
-TEST_F(ZfhEncodingTest, FmvXh_frs1) {
-  FloatFrs1Helper(kFmvXh, OpcodeEnum::kFmvXh);
+TYPED_TEST(ZfhEncodingTest, Fsh_frs2) {
+  this->FloatFrs2Helper(kFsh, TypeParam::OpcodeEnum::kFsh);
 }
 
-TEST_F(ZfhEncodingTest, FmvXh_rd) {
+TYPED_TEST(ZfhEncodingTest, FmvXh) {
+  this->enc_->ParseInstruction(kFmvXh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFmvXh);
+}
+
+TYPED_TEST(ZfhEncodingTest, FmvXh_frs1) {
+  this->FloatFrs1Helper(kFmvXh, TypeParam::OpcodeEnum::kFmvXh);
+}
+
+TYPED_TEST(ZfhEncodingTest, FmvXh_rd) {
+  using XRegister = TypeParam::XRegister;
+  using XValue = typename TypeParam::XRegister::ValueType;
   for (uint32_t rd_index = 1; rd_index < 32; ++rd_index) {
     uint32_t rd_adjustment = rd_index << 7;
-    uint32_t expected_value = absl::Uniform<uint32_t>(gen_);
-    RVXRegister *rd_reg;
+    XValue expected_value = absl::Uniform<XValue>(this->gen_);
+    XRegister *rd_reg;
     std::tie(rd_reg, std::ignore) =
-        state_->GetRegister<RVXRegister>(absl::StrCat("x", rd_index));
-    rd_reg->data_buffer()->Set<uint32_t>(0, expected_value);
-    enc_->ParseInstruction(kFmvXh | rd_adjustment);
-    std::unique_ptr<RegisterDestinationOperand<RVXRegister>> dst(
-        static_cast<RegisterDestinationOperand<RVXRegister> *>(
-            enc_->GetDestination(SlotEnum::kRiscv32Zfh, 0, OpcodeEnum::kFmvXh,
-                                 DestOpEnum::kRd, 0, 0)));
-    uint32_t observed_value =
-        dst->GetRegister()->data_buffer()->Get<uint32_t>(0);
+        this->state_->template GetRegister<XRegister>(
+            absl::StrCat("x", rd_index));
+    rd_reg->data_buffer()->template Set<XValue>(0, expected_value);
+    this->enc_->ParseInstruction(kFmvXh | rd_adjustment);
+    std::unique_ptr<RegisterDestinationOperand<XRegister>> dst(
+        static_cast<RegisterDestinationOperand<XRegister> *>(
+            this->enc_->GetDestination(this->expected_slot_, 0,
+                                       TypeParam::OpcodeEnum::kFmvXh,
+                                       TypeParam::DestOpEnum::kRd, 0, 0)));
+    XValue observed_value =
+        dst->GetRegister()->data_buffer()->template Get<XValue>(0);
     EXPECT_EQ(observed_value, expected_value);
   }
 }
 
-TEST_F(ZfhEncodingTest, FmvHx) {
-  enc_->ParseInstruction(kFmvHx);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmvHx);
+TYPED_TEST(ZfhEncodingTest, FmvHx) {
+  this->enc_->ParseInstruction(kFmvHx);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFmvHx);
 }
 
-TEST_F(ZfhEncodingTest, FmvHx_rs1) {
-  ScalarRs1Helper(kFmvHx, OpcodeEnum::kFmvHx);
+TYPED_TEST(ZfhEncodingTest, FmvHx_rs1) {
+  using XValue = typename TypeParam::XValue;
+  std::vector<int> failed_scalar_sources;
+  for (int register_index = 0; register_index < 32; register_index++) {
+    XValue test_register_value = this->RandomizeScalarRegister(register_index);
+    this->ParseInstructionWithRs1(kFmvHx, register_index);
+    XValue source_value =
+        this->GetRs1SourceValue(TypeParam::OpcodeEnum::kFmvHx);
+    if (source_value != test_register_value) {
+      failed_scalar_sources.push_back(register_index);
+    }
+  }
+  EXPECT_THAT(failed_scalar_sources, ::testing::IsEmpty());
 }
 
-TEST_F(ZfhEncodingTest, FmvHx_frd) {
-  FloatFrdHelper(kFmvHx, OpcodeEnum::kFmvHx);
+TYPED_TEST(ZfhEncodingTest, FmvHx_frd) {
+  this->FloatFrdHelper(kFmvHx, TypeParam::OpcodeEnum::kFmvHx);
 }
 
-TEST_F(ZfhEncodingTest, FcvtSh) {
-  enc_->ParseInstruction(kFcvtSh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtSh);
+TYPED_TEST(ZfhEncodingTest, FcvtSh) {
+  this->enc_->ParseInstruction(kFcvtSh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtSh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtSh_frs1) {
-  FloatFrs1Helper(kFcvtSh, OpcodeEnum::kFcvtSh);
+TYPED_TEST(ZfhEncodingTest, FcvtSh_frs1) {
+  this->FloatFrs1Helper(kFcvtSh, TypeParam::OpcodeEnum::kFcvtSh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtSh_frd) {
-  FloatFrdHelper(kFcvtSh, OpcodeEnum::kFcvtSh);
+TYPED_TEST(ZfhEncodingTest, FcvtSh_frd) {
+  this->FloatFrdHelper(kFcvtSh, TypeParam::OpcodeEnum::kFcvtSh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtSh_rm) {
-  FloatRmHelper(kFcvtSh, OpcodeEnum::kFcvtSh);
+TYPED_TEST(ZfhEncodingTest, FcvtSh_rm) {
+  this->FloatRmHelper(kFcvtSh, TypeParam::OpcodeEnum::kFcvtSh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHs) {
-  enc_->ParseInstruction(kFcvtHs);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtHs);
+TYPED_TEST(ZfhEncodingTest, FcvtHs) {
+  this->enc_->ParseInstruction(kFcvtHs);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtHs);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHs_frs1) {
-  FloatFrs1Helper(kFcvtHs, OpcodeEnum::kFcvtHs);
+TYPED_TEST(ZfhEncodingTest, FcvtHs_frs1) {
+  this->FloatFrs1Helper(kFcvtHs, TypeParam::OpcodeEnum::kFcvtHs);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHs_frd) {
-  FloatFrdHelper(kFcvtHs, OpcodeEnum::kFcvtHs);
+TYPED_TEST(ZfhEncodingTest, FcvtHs_frd) {
+  this->FloatFrdHelper(kFcvtHs, TypeParam::OpcodeEnum::kFcvtHs);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHs_rm) {
-  FloatRmHelper(kFcvtHs, OpcodeEnum::kFcvtHs);
+TYPED_TEST(ZfhEncodingTest, FcvtHs_rm) {
+  this->FloatRmHelper(kFcvtHs, TypeParam::OpcodeEnum::kFcvtHs);
 }
 
-TEST_F(ZfhEncodingTest, FcvtDh) {
-  enc_->ParseInstruction(kFcvtDh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtDh);
+TYPED_TEST(ZfhEncodingTest, FcvtDh) {
+  this->enc_->ParseInstruction(kFcvtDh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtDh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtDh_frs1) {
-  FloatFrs1Helper(kFcvtDh, OpcodeEnum::kFcvtDh);
+TYPED_TEST(ZfhEncodingTest, FcvtDh_frs1) {
+  this->FloatFrs1Helper(kFcvtDh, TypeParam::OpcodeEnum::kFcvtDh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtDh_frd) {
-  FloatFrdHelper(kFcvtDh, OpcodeEnum::kFcvtDh);
+TYPED_TEST(ZfhEncodingTest, FcvtDh_frd) {
+  this->FloatFrdHelper(kFcvtDh, TypeParam::OpcodeEnum::kFcvtDh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtDh_rm) {
-  FloatRmHelper(kFcvtDh, OpcodeEnum::kFcvtDh);
+TYPED_TEST(ZfhEncodingTest, FcvtDh_rm) {
+  this->FloatRmHelper(kFcvtDh, TypeParam::OpcodeEnum::kFcvtDh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHd) {
-  enc_->ParseInstruction(kFcvtHd);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtHd);
+TYPED_TEST(ZfhEncodingTest, FcvtHd) {
+  this->enc_->ParseInstruction(kFcvtHd);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtHd);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHd_frs1) {
-  FloatFrs1Helper(kFcvtHd, OpcodeEnum::kFcvtHd);
+TYPED_TEST(ZfhEncodingTest, FcvtHd_frs1) {
+  this->FloatFrs1Helper(kFcvtHd, TypeParam::OpcodeEnum::kFcvtHd);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHd_frd) {
-  FloatFrdHelper(kFcvtHd, OpcodeEnum::kFcvtHd);
+TYPED_TEST(ZfhEncodingTest, FcvtHd_frd) {
+  this->FloatFrdHelper(kFcvtHd, TypeParam::OpcodeEnum::kFcvtHd);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHd_rm) {
-  FloatRmHelper(kFcvtHd, OpcodeEnum::kFcvtHd);
+TYPED_TEST(ZfhEncodingTest, FcvtHd_rm) {
+  this->FloatRmHelper(kFcvtHd, TypeParam::OpcodeEnum::kFcvtHd);
 }
 
-TEST_F(ZfhEncodingTest, FaddH) {
-  enc_->ParseInstruction(kFaddH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFaddH);
+TYPED_TEST(ZfhEncodingTest, FaddH) {
+  this->enc_->ParseInstruction(kFaddH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFaddH);
 }
 
-TEST_F(ZfhEncodingTest, FaddH_frs1) {
-  FloatFrs1Helper(kFaddH, OpcodeEnum::kFaddH);
+TYPED_TEST(ZfhEncodingTest, FaddH_frs1) {
+  this->FloatFrs1Helper(kFaddH, TypeParam::OpcodeEnum::kFaddH);
 }
 
-TEST_F(ZfhEncodingTest, FaddH_frs2) {
-  FloatFrs2Helper(kFaddH, OpcodeEnum::kFaddH);
+TYPED_TEST(ZfhEncodingTest, FaddH_frs2) {
+  this->FloatFrs2Helper(kFaddH, TypeParam::OpcodeEnum::kFaddH);
 }
 
-TEST_F(ZfhEncodingTest, FaddH_frd) {
-  FloatFrdHelper(kFaddH, OpcodeEnum::kFaddH);
+TYPED_TEST(ZfhEncodingTest, FaddH_frd) {
+  this->FloatFrdHelper(kFaddH, TypeParam::OpcodeEnum::kFaddH);
 }
 
-TEST_F(ZfhEncodingTest, FaddH_rm) { FloatRmHelper(kFaddH, OpcodeEnum::kFaddH); }
+TYPED_TEST(ZfhEncodingTest, FaddH_rm) {
+  this->FloatRmHelper(kFaddH, TypeParam::OpcodeEnum::kFaddH);
+}
 
-TEST_F(ZfhEncodingTest, FsubH) {
-  enc_->ParseInstruction(kFsubH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFsubH);
+TYPED_TEST(ZfhEncodingTest, FsubH) {
+  this->enc_->ParseInstruction(kFsubH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFsubH);
 }
 
-TEST_F(ZfhEncodingTest, FsubH_frs1) {
-  FloatFrs1Helper(kFsubH, OpcodeEnum::kFsubH);
+TYPED_TEST(ZfhEncodingTest, FsubH_frs1) {
+  this->FloatFrs1Helper(kFsubH, TypeParam::OpcodeEnum::kFsubH);
 }
 
-TEST_F(ZfhEncodingTest, FsubH_frs2) {
-  FloatFrs2Helper(kFsubH, OpcodeEnum::kFsubH);
+TYPED_TEST(ZfhEncodingTest, FsubH_frs2) {
+  this->FloatFrs2Helper(kFsubH, TypeParam::OpcodeEnum::kFsubH);
 }
 
-TEST_F(ZfhEncodingTest, FsubH_frd) {
-  FloatFrdHelper(kFsubH, OpcodeEnum::kFsubH);
+TYPED_TEST(ZfhEncodingTest, FsubH_frd) {
+  this->FloatFrdHelper(kFsubH, TypeParam::OpcodeEnum::kFsubH);
 }
 
-TEST_F(ZfhEncodingTest, FsubH_rm) { FloatRmHelper(kFsubH, OpcodeEnum::kFsubH); }
+TYPED_TEST(ZfhEncodingTest, FsubH_rm) {
+  this->FloatRmHelper(kFsubH, TypeParam::OpcodeEnum::kFsubH);
+}
 
-TEST_F(ZfhEncodingTest, FmulH) {
-  enc_->ParseInstruction(kFmulH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmulH);
+TYPED_TEST(ZfhEncodingTest, FmulH) {
+  this->enc_->ParseInstruction(kFmulH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFmulH);
 }
 
-TEST_F(ZfhEncodingTest, FmulH_frs1) {
-  FloatFrs1Helper(kFmulH, OpcodeEnum::kFmulH);
+TYPED_TEST(ZfhEncodingTest, FmulH_frs1) {
+  this->FloatFrs1Helper(kFmulH, TypeParam::OpcodeEnum::kFmulH);
 }
 
-TEST_F(ZfhEncodingTest, FmulH_frs2) {
-  FloatFrs2Helper(kFmulH, OpcodeEnum::kFmulH);
+TYPED_TEST(ZfhEncodingTest, FmulH_frs2) {
+  this->FloatFrs2Helper(kFmulH, TypeParam::OpcodeEnum::kFmulH);
 }
 
-TEST_F(ZfhEncodingTest, FmulH_frd) {
-  FloatFrdHelper(kFmulH, OpcodeEnum::kFmulH);
+TYPED_TEST(ZfhEncodingTest, FmulH_frd) {
+  this->FloatFrdHelper(kFmulH, TypeParam::OpcodeEnum::kFmulH);
 }
 
-TEST_F(ZfhEncodingTest, FmulH_rm) { FloatRmHelper(kFmulH, OpcodeEnum::kFmulH); }
+TYPED_TEST(ZfhEncodingTest, FmulH_rm) {
+  this->FloatRmHelper(kFmulH, TypeParam::OpcodeEnum::kFmulH);
+}
 
-TEST_F(ZfhEncodingTest, FdivH) {
-  enc_->ParseInstruction(kFdivH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFdivH);
+TYPED_TEST(ZfhEncodingTest, FdivH) {
+  this->enc_->ParseInstruction(kFdivH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFdivH);
 }
 
-TEST_F(ZfhEncodingTest, FdivH_frs1) {
-  FloatFrs1Helper(kFdivH, OpcodeEnum::kFdivH);
+TYPED_TEST(ZfhEncodingTest, FdivH_frs1) {
+  this->FloatFrs1Helper(kFdivH, TypeParam::OpcodeEnum::kFdivH);
 }
 
-TEST_F(ZfhEncodingTest, FdivH_frs2) {
-  FloatFrs2Helper(kFdivH, OpcodeEnum::kFdivH);
+TYPED_TEST(ZfhEncodingTest, FdivH_frs2) {
+  this->FloatFrs2Helper(kFdivH, TypeParam::OpcodeEnum::kFdivH);
 }
 
-TEST_F(ZfhEncodingTest, FdivH_frd) {
-  FloatFrdHelper(kFdivH, OpcodeEnum::kFdivH);
+TYPED_TEST(ZfhEncodingTest, FdivH_frd) {
+  this->FloatFrdHelper(kFdivH, TypeParam::OpcodeEnum::kFdivH);
 }
 
-TEST_F(ZfhEncodingTest, FdivH_rm) { FloatRmHelper(kFdivH, OpcodeEnum::kFdivH); }
+TYPED_TEST(ZfhEncodingTest, FdivH_rm) {
+  this->FloatRmHelper(kFdivH, TypeParam::OpcodeEnum::kFdivH);
+}
 
-TEST_F(ZfhEncodingTest, FminH) {
-  enc_->ParseInstruction(kFminH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFminH);
+TYPED_TEST(ZfhEncodingTest, FminH) {
+  this->enc_->ParseInstruction(kFminH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFminH);
 }
 
-TEST_F(ZfhEncodingTest, FminH_frs1) {
-  FloatFrs1Helper(kFminH, OpcodeEnum::kFminH);
+TYPED_TEST(ZfhEncodingTest, FminH_frs1) {
+  this->FloatFrs1Helper(kFminH, TypeParam::OpcodeEnum::kFminH);
 }
 
-TEST_F(ZfhEncodingTest, FminH_frs2) {
-  FloatFrs2Helper(kFminH, OpcodeEnum::kFminH);
+TYPED_TEST(ZfhEncodingTest, FminH_frs2) {
+  this->FloatFrs2Helper(kFminH, TypeParam::OpcodeEnum::kFminH);
 }
 
-TEST_F(ZfhEncodingTest, FminH_frd) {
-  FloatFrdHelper(kFminH, OpcodeEnum::kFminH);
+TYPED_TEST(ZfhEncodingTest, FminH_frd) {
+  this->FloatFrdHelper(kFminH, TypeParam::OpcodeEnum::kFminH);
 }
 
-TEST_F(ZfhEncodingTest, FmaxH) {
-  enc_->ParseInstruction(kFmaxH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmaxH);
+TYPED_TEST(ZfhEncodingTest, FmaxH) {
+  this->enc_->ParseInstruction(kFmaxH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFmaxH);
 }
 
-TEST_F(ZfhEncodingTest, FmaxH_frs1) {
-  FloatFrs1Helper(kFmaxH, OpcodeEnum::kFmaxH);
+TYPED_TEST(ZfhEncodingTest, FmaxH_frs1) {
+  this->FloatFrs1Helper(kFmaxH, TypeParam::OpcodeEnum::kFmaxH);
 }
 
-TEST_F(ZfhEncodingTest, FmaxH_frs2) {
-  FloatFrs2Helper(kFmaxH, OpcodeEnum::kFmaxH);
+TYPED_TEST(ZfhEncodingTest, FmaxH_frs2) {
+  this->FloatFrs2Helper(kFmaxH, TypeParam::OpcodeEnum::kFmaxH);
 }
 
-TEST_F(ZfhEncodingTest, FmaxH_frd) {
-  FloatFrdHelper(kFmaxH, OpcodeEnum::kFmaxH);
+TYPED_TEST(ZfhEncodingTest, FmaxH_frd) {
+  this->FloatFrdHelper(kFmaxH, TypeParam::OpcodeEnum::kFmaxH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjH) {
-  enc_->ParseInstruction(kFsgnjH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFsgnjH);
+TYPED_TEST(ZfhEncodingTest, FsgnjH) {
+  this->enc_->ParseInstruction(kFsgnjH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFsgnjH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjH_frs1) {
-  FloatFrs1Helper(kFsgnjH, OpcodeEnum::kFsgnjH);
+TYPED_TEST(ZfhEncodingTest, FsgnjH_frs1) {
+  this->FloatFrs1Helper(kFsgnjH, TypeParam::OpcodeEnum::kFsgnjH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjH_frs2) {
-  FloatFrs2Helper(kFsgnjH, OpcodeEnum::kFsgnjH);
+TYPED_TEST(ZfhEncodingTest, FsgnjH_frs2) {
+  this->FloatFrs2Helper(kFsgnjH, TypeParam::OpcodeEnum::kFsgnjH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjH_frd) {
-  FloatFrdHelper(kFsgnjH, OpcodeEnum::kFsgnjH);
+TYPED_TEST(ZfhEncodingTest, FsgnjH_frd) {
+  this->FloatFrdHelper(kFsgnjH, TypeParam::OpcodeEnum::kFsgnjH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjnH) {
-  enc_->ParseInstruction(kFsgnjnH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFsgnjnH);
+TYPED_TEST(ZfhEncodingTest, FsgnjnH) {
+  this->enc_->ParseInstruction(kFsgnjnH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFsgnjnH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjnH_frs1) {
-  FloatFrs1Helper(kFsgnjnH, OpcodeEnum::kFsgnjnH);
+TYPED_TEST(ZfhEncodingTest, FsgnjnH_frs1) {
+  this->FloatFrs1Helper(kFsgnjnH, TypeParam::OpcodeEnum::kFsgnjnH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjnH_frs2) {
-  FloatFrs2Helper(kFsgnjnH, OpcodeEnum::kFsgnjnH);
+TYPED_TEST(ZfhEncodingTest, FsgnjnH_frs2) {
+  this->FloatFrs2Helper(kFsgnjnH, TypeParam::OpcodeEnum::kFsgnjnH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjnH_frd) {
-  FloatFrdHelper(kFsgnjnH, OpcodeEnum::kFsgnjnH);
+TYPED_TEST(ZfhEncodingTest, FsgnjnH_frd) {
+  this->FloatFrdHelper(kFsgnjnH, TypeParam::OpcodeEnum::kFsgnjnH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjxH) {
-  enc_->ParseInstruction(kFsgnjxH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFsgnjxH);
+TYPED_TEST(ZfhEncodingTest, FsgnjxH) {
+  this->enc_->ParseInstruction(kFsgnjxH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFsgnjxH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjxH_frs1) {
-  FloatFrs1Helper(kFsgnjxH, OpcodeEnum::kFsgnjxH);
+TYPED_TEST(ZfhEncodingTest, FsgnjxH_frs1) {
+  this->FloatFrs1Helper(kFsgnjxH, TypeParam::OpcodeEnum::kFsgnjxH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjxH_frs2) {
-  FloatFrs2Helper(kFsgnjxH, OpcodeEnum::kFsgnjxH);
+TYPED_TEST(ZfhEncodingTest, FsgnjxH_frs2) {
+  this->FloatFrs2Helper(kFsgnjxH, TypeParam::OpcodeEnum::kFsgnjxH);
 }
 
-TEST_F(ZfhEncodingTest, FsgnjxH_frd) {
-  FloatFrdHelper(kFsgnjxH, OpcodeEnum::kFsgnjxH);
+TYPED_TEST(ZfhEncodingTest, FsgnjxH_frd) {
+  this->FloatFrdHelper(kFsgnjxH, TypeParam::OpcodeEnum::kFsgnjxH);
 }
 
-TEST_F(ZfhEncodingTest, FsqrtH) {
-  enc_->ParseInstruction(kFsqrtH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFsqrtH);
+TYPED_TEST(ZfhEncodingTest, FsqrtH) {
+  this->enc_->ParseInstruction(kFsqrtH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFsqrtH);
 }
 
-TEST_F(ZfhEncodingTest, FsqrtH_frs1) {
-  FloatFrs1Helper(kFsqrtH, OpcodeEnum::kFsqrtH);
+TYPED_TEST(ZfhEncodingTest, FsqrtH_frs1) {
+  this->FloatFrs1Helper(kFsqrtH, TypeParam::OpcodeEnum::kFsqrtH);
 }
 
-TEST_F(ZfhEncodingTest, FsqrtH_rm) {
-  FloatRmHelper(kFsqrtH, OpcodeEnum::kFsqrtH);
+TYPED_TEST(ZfhEncodingTest, FsqrtH_rm) {
+  this->FloatRmHelper(kFsqrtH, TypeParam::OpcodeEnum::kFsqrtH);
 }
 
-TEST_F(ZfhEncodingTest, FsqrtH_frd) {
-  FloatFrdHelper(kFsqrtH, OpcodeEnum::kFsqrtH);
+TYPED_TEST(ZfhEncodingTest, FsqrtH_frd) {
+  this->FloatFrdHelper(kFsqrtH, TypeParam::OpcodeEnum::kFsqrtH);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHw) {
-  enc_->ParseInstruction(kFcvtHw);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtHw);
+TYPED_TEST(ZfhEncodingTest, FcvtHw) {
+  this->enc_->ParseInstruction(kFcvtHw);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtHw);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHw_frs1) {
-  FloatFrs1Helper(kFcvtHw, OpcodeEnum::kFcvtHw);
+TYPED_TEST(ZfhEncodingTest, FcvtHw_frs1) {
+  this->FloatFrs1Helper(kFcvtHw, TypeParam::OpcodeEnum::kFcvtHw);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHw_rm) {
-  FloatRmHelper(kFcvtHw, OpcodeEnum::kFcvtHw);
+TYPED_TEST(ZfhEncodingTest, FcvtHw_rm) {
+  this->FloatRmHelper(kFcvtHw, TypeParam::OpcodeEnum::kFcvtHw);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHw_frd) {
-  FloatFrdHelper(kFcvtHw, OpcodeEnum::kFcvtHw);
+TYPED_TEST(ZfhEncodingTest, FcvtHw_frd) {
+  this->FloatFrdHelper(kFcvtHw, TypeParam::OpcodeEnum::kFcvtHw);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWh) {
-  enc_->ParseInstruction(kFcvtWh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtWh);
+TYPED_TEST(ZfhEncodingTest, FcvtWh) {
+  this->enc_->ParseInstruction(kFcvtWh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtWh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWh_frs1) {
-  FloatFrs1Helper(kFcvtWh, OpcodeEnum::kFcvtWh);
+TYPED_TEST(ZfhEncodingTest, FcvtWh_frs1) {
+  this->FloatFrs1Helper(kFcvtWh, TypeParam::OpcodeEnum::kFcvtWh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWh_rm) {
-  FloatRmHelper(kFcvtWh, OpcodeEnum::kFcvtWh);
+TYPED_TEST(ZfhEncodingTest, FcvtWh_rm) {
+  this->FloatRmHelper(kFcvtWh, TypeParam::OpcodeEnum::kFcvtWh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWh_frd) {
-  FloatFrdHelper(kFcvtWh, OpcodeEnum::kFcvtWh);
+TYPED_TEST(ZfhEncodingTest, FcvtWh_frd) {
+  this->FloatFrdHelper(kFcvtWh, TypeParam::OpcodeEnum::kFcvtWh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHwu) {
-  enc_->ParseInstruction(kFcvtHwu);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtHwu);
+TYPED_TEST(ZfhEncodingTest, FcvtHwu) {
+  this->enc_->ParseInstruction(kFcvtHwu);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtHwu);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHwu_frs1) {
-  FloatFrs1Helper(kFcvtHwu, OpcodeEnum::kFcvtHwu);
+TYPED_TEST(ZfhEncodingTest, FcvtHwu_frs1) {
+  this->FloatFrs1Helper(kFcvtHwu, TypeParam::OpcodeEnum::kFcvtHwu);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHwu_rm) {
-  FloatRmHelper(kFcvtHwu, OpcodeEnum::kFcvtHwu);
+TYPED_TEST(ZfhEncodingTest, FcvtHwu_rm) {
+  this->FloatRmHelper(kFcvtHwu, TypeParam::OpcodeEnum::kFcvtHwu);
 }
 
-TEST_F(ZfhEncodingTest, FcvtHwu_frd) {
-  FloatFrdHelper(kFcvtHwu, OpcodeEnum::kFcvtHwu);
+TYPED_TEST(ZfhEncodingTest, FcvtHwu_frd) {
+  this->FloatFrdHelper(kFcvtHwu, TypeParam::OpcodeEnum::kFcvtHwu);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWuh) {
-  enc_->ParseInstruction(kFcvtWuh);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcvtWuh);
+TYPED_TEST(ZfhEncodingTest, FcvtWuh) {
+  this->enc_->ParseInstruction(kFcvtWuh);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcvtWuh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWuh_frs1) {
-  FloatFrs1Helper(kFcvtWuh, OpcodeEnum::kFcvtWuh);
+TYPED_TEST(ZfhEncodingTest, FcvtWuh_frs1) {
+  this->FloatFrs1Helper(kFcvtWuh, TypeParam::OpcodeEnum::kFcvtWuh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWuh_rm) {
-  FloatRmHelper(kFcvtWuh, OpcodeEnum::kFcvtWuh);
+TYPED_TEST(ZfhEncodingTest, FcvtWuh_rm) {
+  this->FloatRmHelper(kFcvtWuh, TypeParam::OpcodeEnum::kFcvtWuh);
 }
 
-TEST_F(ZfhEncodingTest, FcvtWuh_frd) {
-  FloatFrdHelper(kFcvtWuh, OpcodeEnum::kFcvtWuh);
+TYPED_TEST(ZfhEncodingTest, FcvtWuh_frd) {
+  this->FloatFrdHelper(kFcvtWuh, TypeParam::OpcodeEnum::kFcvtWuh);
 }
 
-TEST_F(ZfhEncodingTest, FcmpeqH) {
-  enc_->ParseInstruction(kFcmpeqH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcmpeqH);
+TYPED_TEST(ZfhEncodingTest, FcmpeqH) {
+  this->enc_->ParseInstruction(kFcmpeqH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcmpeqH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpeqH_frs1) {
-  FloatFrs1Helper(kFcmpeqH, OpcodeEnum::kFcmpeqH);
+TYPED_TEST(ZfhEncodingTest, FcmpeqH_frs1) {
+  this->FloatFrs1Helper(kFcmpeqH, TypeParam::OpcodeEnum::kFcmpeqH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpeqH_frs2) {
-  FloatFrs2Helper(kFcmpeqH, OpcodeEnum::kFcmpeqH);
+TYPED_TEST(ZfhEncodingTest, FcmpeqH_frs2) {
+  this->FloatFrs2Helper(kFcmpeqH, TypeParam::OpcodeEnum::kFcmpeqH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpeqH_frd) {
-  FloatFrdHelper(kFcmpeqH, OpcodeEnum::kFcmpeqH);
+TYPED_TEST(ZfhEncodingTest, FcmpeqH_frd) {
+  this->FloatFrdHelper(kFcmpeqH, TypeParam::OpcodeEnum::kFcmpeqH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpltH) {
-  enc_->ParseInstruction(kFcmpltH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcmpltH);
+TYPED_TEST(ZfhEncodingTest, FcmpltH) {
+  this->enc_->ParseInstruction(kFcmpltH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcmpltH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpltH_frs1) {
-  FloatFrs1Helper(kFcmpltH, OpcodeEnum::kFcmpltH);
+TYPED_TEST(ZfhEncodingTest, FcmpltH_frs1) {
+  this->FloatFrs1Helper(kFcmpltH, TypeParam::OpcodeEnum::kFcmpltH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpltH_frs2) {
-  FloatFrs2Helper(kFcmpltH, OpcodeEnum::kFcmpltH);
+TYPED_TEST(ZfhEncodingTest, FcmpltH_frs2) {
+  this->FloatFrs2Helper(kFcmpltH, TypeParam::OpcodeEnum::kFcmpltH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpltH_frd) {
-  FloatFrdHelper(kFcmpltH, OpcodeEnum::kFcmpltH);
+TYPED_TEST(ZfhEncodingTest, FcmpltH_frd) {
+  this->FloatFrdHelper(kFcmpltH, TypeParam::OpcodeEnum::kFcmpltH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpleH) {
-  enc_->ParseInstruction(kFcmpleH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFcmpleH);
+TYPED_TEST(ZfhEncodingTest, FcmpleH) {
+  this->enc_->ParseInstruction(kFcmpleH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFcmpleH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpleH_frs1) {
-  FloatFrs1Helper(kFcmpleH, OpcodeEnum::kFcmpleH);
+TYPED_TEST(ZfhEncodingTest, FcmpleH_frs1) {
+  this->FloatFrs1Helper(kFcmpleH, TypeParam::OpcodeEnum::kFcmpleH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpleH_frs2) {
-  FloatFrs2Helper(kFcmpleH, OpcodeEnum::kFcmpleH);
+TYPED_TEST(ZfhEncodingTest, FcmpleH_frs2) {
+  this->FloatFrs2Helper(kFcmpleH, TypeParam::OpcodeEnum::kFcmpleH);
 }
 
-TEST_F(ZfhEncodingTest, FcmpleH_frd) {
-  FloatFrdHelper(kFcmpleH, OpcodeEnum::kFcmpleH);
+TYPED_TEST(ZfhEncodingTest, FcmpleH_frd) {
+  this->FloatFrdHelper(kFcmpleH, TypeParam::OpcodeEnum::kFcmpleH);
 }
 
-TEST_F(ZfhEncodingTest, FclassH) {
-  enc_->ParseInstruction(kFclassH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFclassH);
+TYPED_TEST(ZfhEncodingTest, FclassH) {
+  this->enc_->ParseInstruction(kFclassH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFclassH);
 }
 
-TEST_F(ZfhEncodingTest, FclassH_frs1) {
-  FloatFrs1Helper(kFclassH, OpcodeEnum::kFclassH);
+TYPED_TEST(ZfhEncodingTest, FclassH_frs1) {
+  this->FloatFrs1Helper(kFclassH, TypeParam::OpcodeEnum::kFclassH);
 }
 
-TEST_F(ZfhEncodingTest, FclassH_frd) {
-  FloatFrdHelper(kFclassH, OpcodeEnum::kFclassH);
+TYPED_TEST(ZfhEncodingTest, FclassH_frd) {
+  this->FloatFrdHelper(kFclassH, TypeParam::OpcodeEnum::kFclassH);
 }
 
-TEST_F(ZfhEncodingTest, FmaddH) {
-  enc_->ParseInstruction(kFmaddH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmaddH);
+TYPED_TEST(ZfhEncodingTest, FmaddH) {
+  this->enc_->ParseInstruction(kFmaddH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FmaddH_frs1) {
-  FloatFrs1Helper(kFmaddH, OpcodeEnum::kFmaddH);
+TYPED_TEST(ZfhEncodingTest, FmaddH_frs1) {
+  this->FloatFrs1Helper(kFmaddH, TypeParam::OpcodeEnum::kFmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FmaddH_frs2) {
-  FloatFrs2Helper(kFmaddH, OpcodeEnum::kFmaddH);
+TYPED_TEST(ZfhEncodingTest, FmaddH_frs2) {
+  this->FloatFrs2Helper(kFmaddH, TypeParam::OpcodeEnum::kFmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FmaddH_frs3) {
-  FloatFrs3Helper(kFmaddH, OpcodeEnum::kFmaddH);
+TYPED_TEST(ZfhEncodingTest, FmaddH_frs3) {
+  this->FloatFrs3Helper(kFmaddH, TypeParam::OpcodeEnum::kFmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FmaddH_rm) {
-  FloatRmHelper(kFmaddH, OpcodeEnum::kFmaddH);
+TYPED_TEST(ZfhEncodingTest, FmaddH_rm) {
+  this->FloatRmHelper(kFmaddH, TypeParam::OpcodeEnum::kFmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FmaddH_frd) {
-  FloatFrdHelper(kFmaddH, OpcodeEnum::kFmaddH);
+TYPED_TEST(ZfhEncodingTest, FmaddH_frd) {
+  this->FloatFrdHelper(kFmaddH, TypeParam::OpcodeEnum::kFmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FmsubH) {
-  enc_->ParseInstruction(kFmsubH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFmsubH);
+TYPED_TEST(ZfhEncodingTest, FmsubH) {
+  this->enc_->ParseInstruction(kFmsubH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FmsubH_frs1) {
-  FloatFrs1Helper(kFmsubH, OpcodeEnum::kFmsubH);
+TYPED_TEST(ZfhEncodingTest, FmsubH_frs1) {
+  this->FloatFrs1Helper(kFmsubH, TypeParam::OpcodeEnum::kFmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FmsubH_frs2) {
-  FloatFrs2Helper(kFmsubH, OpcodeEnum::kFmsubH);
+TYPED_TEST(ZfhEncodingTest, FmsubH_frs2) {
+  this->FloatFrs2Helper(kFmsubH, TypeParam::OpcodeEnum::kFmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FmsubH_frs3) {
-  FloatFrs3Helper(kFmsubH, OpcodeEnum::kFmsubH);
+TYPED_TEST(ZfhEncodingTest, FmsubH_frs3) {
+  this->FloatFrs3Helper(kFmsubH, TypeParam::OpcodeEnum::kFmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FmsubH_rm) {
-  FloatRmHelper(kFmsubH, OpcodeEnum::kFmsubH);
+TYPED_TEST(ZfhEncodingTest, FmsubH_rm) {
+  this->FloatRmHelper(kFmsubH, TypeParam::OpcodeEnum::kFmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FmsubH_frd) {
-  FloatFrdHelper(kFmsubH, OpcodeEnum::kFmsubH);
+TYPED_TEST(ZfhEncodingTest, FmsubH_frd) {
+  this->FloatFrdHelper(kFmsubH, TypeParam::OpcodeEnum::kFmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FnmaddH) {
-  enc_->ParseInstruction(kFnmaddH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFnmaddH);
+TYPED_TEST(ZfhEncodingTest, FnmaddH) {
+  this->enc_->ParseInstruction(kFnmaddH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFnmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FnmaddH_frs1) {
-  FloatFrs1Helper(kFnmaddH, OpcodeEnum::kFnmaddH);
+TYPED_TEST(ZfhEncodingTest, FnmaddH_frs1) {
+  this->FloatFrs1Helper(kFnmaddH, TypeParam::OpcodeEnum::kFnmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FnmaddH_frs2) {
-  FloatFrs2Helper(kFnmaddH, OpcodeEnum::kFnmaddH);
+TYPED_TEST(ZfhEncodingTest, FnmaddH_frs2) {
+  this->FloatFrs2Helper(kFnmaddH, TypeParam::OpcodeEnum::kFnmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FnmaddH_frs3) {
-  FloatFrs3Helper(kFnmaddH, OpcodeEnum::kFnmaddH);
+TYPED_TEST(ZfhEncodingTest, FnmaddH_frs3) {
+  this->FloatFrs3Helper(kFnmaddH, TypeParam::OpcodeEnum::kFnmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FnmaddH_rm) {
-  FloatRmHelper(kFnmaddH, OpcodeEnum::kFnmaddH);
+TYPED_TEST(ZfhEncodingTest, FnmaddH_rm) {
+  this->FloatRmHelper(kFnmaddH, TypeParam::OpcodeEnum::kFnmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FnmaddH_frd) {
-  FloatFrdHelper(kFnmaddH, OpcodeEnum::kFnmaddH);
+TYPED_TEST(ZfhEncodingTest, FnmaddH_frd) {
+  this->FloatFrdHelper(kFnmaddH, TypeParam::OpcodeEnum::kFnmaddH);
 }
 
-TEST_F(ZfhEncodingTest, FnmsubH) {
-  enc_->ParseInstruction(kFnmsubH);
-  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kRiscv32Zfh, 0), OpcodeEnum::kFnmsubH);
+TYPED_TEST(ZfhEncodingTest, FnmsubH) {
+  this->enc_->ParseInstruction(kFnmsubH);
+  EXPECT_EQ(this->GetOpcode(), TypeParam::OpcodeEnum::kFnmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FnmsubH_frs1) {
-  FloatFrs1Helper(kFnmsubH, OpcodeEnum::kFnmsubH);
+TYPED_TEST(ZfhEncodingTest, FnmsubH_frs1) {
+  this->FloatFrs1Helper(kFnmsubH, TypeParam::OpcodeEnum::kFnmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FnmsubH_frs2) {
-  FloatFrs2Helper(kFnmsubH, OpcodeEnum::kFnmsubH);
+TYPED_TEST(ZfhEncodingTest, FnmsubH_frs2) {
+  this->FloatFrs2Helper(kFnmsubH, TypeParam::OpcodeEnum::kFnmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FnmsubH_frs3) {
-  FloatFrs3Helper(kFnmsubH, OpcodeEnum::kFnmsubH);
+TYPED_TEST(ZfhEncodingTest, FnmsubH_frs3) {
+  this->FloatFrs3Helper(kFnmsubH, TypeParam::OpcodeEnum::kFnmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FnmsubH_rm) {
-  FloatRmHelper(kFnmsubH, OpcodeEnum::kFnmsubH);
+TYPED_TEST(ZfhEncodingTest, FnmsubH_rm) {
+  this->FloatRmHelper(kFnmsubH, TypeParam::OpcodeEnum::kFnmsubH);
 }
 
-TEST_F(ZfhEncodingTest, FnmsubH_frd) {
-  FloatFrdHelper(kFnmsubH, OpcodeEnum::kFnmsubH);
+TYPED_TEST(ZfhEncodingTest, FnmsubH_frd) {
+  this->FloatFrdHelper(kFnmsubH, TypeParam::OpcodeEnum::kFnmsubH);
 }
 
 }  // namespace