Internal change

PiperOrigin-RevId: 548787275
diff --git a/.bazelrc b/.bazelrc
new file mode 100644
index 0000000..0341edd
--- /dev/null
+++ b/.bazelrc
@@ -0,0 +1,7 @@
+# Build configurations for the project
+build --action_env=BAZEL_CXXOPTS="-std=c++17"
+build --action_env=CC="clang"
+# Disable warnings we don't care about or that generally have a low signal/noise
+# ratio.
+build --copt=-Wno-unused-function
+build --host_copt=-Wno-unused-function
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a32ed4b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+bazel-*
+.vscode
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..25d126c
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,4 @@
+# This is the top level package for Kelvin Sim. This build file creates a package group
+# that is used to keep track of which projects use Kelvin Sim.
+
+package_group(name = "kelvin_sim_users")
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..d40c02d
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,28 @@
+# Setup bazel repository.
+workspace(name = "kelvin_sim")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+# MPACT-RiscV repo
+http_archive(
+    name = "com_google_mpact-riscv",
+    sha256 = "b2b3ce1354d2da48ee195b72b682ecffeb0844b1fbd4f8e83a429d8b21194e61",
+    strip_prefix = "mpact-riscv-a21d14041b9f034519e2f9fa359f2902b433cf23",
+    url = "https://github.com/google/mpact-riscv/archive/a21d14041b9f034519e2f9fa359f2902b433cf23.tar.gz",
+)
+
+# MPACT-Sim repo
+http_archive(
+    name = "com_google_mpact-sim",
+    sha256 = "240e6fa1cba9f26dd5e5343eeff6cc2f8a890cb1ead63c8f7a95323cb88b6593",
+    strip_prefix = "mpact-sim-d3977cd11e560fe19c7ad5ee6b269d806ca6c768",
+    url = "https://github.com/google/mpact-sim/archive/d3977cd11e560fe19c7ad5ee6b269d806ca6c768.tar.gz",
+)
+
+load("@com_google_mpact-sim//:repos.bzl", "mpact_sim_repos")
+
+mpact_sim_repos()
+
+load("@com_google_mpact-sim//:deps.bzl", "mpact_sim_deps")
+
+mpact_sim_deps()
diff --git a/sim/BUILD b/sim/BUILD
new file mode 100644
index 0000000..f428b43
--- /dev/null
+++ b/sim/BUILD
@@ -0,0 +1,152 @@
+# Build rules for Kelvin simulator code.
+load("@com_google_mpact-sim//mpact/sim/decoder:mpact_sim_isa.bzl", "mpact_bin_fmt_decoder", "mpact_isa_decoder")
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+    name = "kelvin_state",
+    srcs = [
+        "kelvin_state.cc",
+    ],
+    hdrs = [
+        "kelvin_state.h",
+    ],
+    copts = [
+        "-O3",
+        "-ffp-model=strict",
+        "-fprotect-parens",
+    ],
+    deps = [
+        "@com_google_absl//absl/functional:any_invocable",
+        "@com_google_absl//absl/log:check",
+        "@com_google_absl//absl/strings",
+        "@com_google_mpact-riscv//riscv:riscv_state",
+    ],
+)
+
+cc_library(
+    name = "kelvin_instructions",
+    srcs = [
+        "kelvin_instructions.cc",
+        "kelvin_vector_instructions.cc",
+        "kelvin_vector_memory_instructions.cc",
+    ],
+    hdrs = [
+        "kelvin_instructions.h",
+        "kelvin_vector_instructions.h",
+        "kelvin_vector_memory_instructions.h",
+    ],
+    copts = ["-O3"],
+    deps = [
+        ":kelvin_state",
+        "@com_google_absl//absl/functional:bind_front",
+        "@com_google_absl//absl/numeric:bits",
+        "@com_google_absl//absl/types:span",
+        "@com_google_mpact-riscv//riscv:riscv_state",
+        "@com_google_mpact-sim//mpact/sim/generic:core",
+        "@com_google_mpact-sim//mpact/sim/generic:instruction",
+    ],
+)
+
+mpact_isa_decoder(
+    name = "kelvin_isa",
+    src = "kelvin.isa",
+    includes = [],
+    isa_name = "Kelvin",
+    deps = [
+        ":kelvin_instructions",
+        "@com_google_absl//absl/functional:bind_front",
+        "@com_google_mpact-riscv//riscv:riscv_g",
+    ],
+)
+
+mpact_bin_fmt_decoder(
+    name = "kelvin_bin_fmt",
+    src = "kelvin.bin_fmt",
+    decoder_name = "Kelvin",
+    includes = [],
+    deps = [
+        ":kelvin_isa",
+    ],
+)
+
+cc_library(
+    name = "kelvin_decoder",
+    srcs = [
+        "decoder.cc",
+        "kelvin_encoding.cc",
+    ],
+    hdrs = [
+        "decoder.h",
+        "kelvin_encoding.h",
+    ],
+    copts = ["-O3"],
+    deps = [
+        ":kelvin_bin_fmt",
+        ":kelvin_isa",
+        ":kelvin_state",
+        "@com_google_absl//absl/container:flat_hash_map",
+        "@com_google_absl//absl/functional:any_invocable",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/types:span",
+        "@com_google_mpact-riscv//riscv:riscv_state",
+        "@com_google_mpact-sim//mpact/sim/generic:arch_state",
+        "@com_google_mpact-sim//mpact/sim/generic:core",
+        "@com_google_mpact-sim//mpact/sim/generic:instruction",
+        "@com_google_mpact-sim//mpact/sim/util/memory",
+    ],
+)
+
+cc_library(
+    name = "kelvin_top",
+    srcs = [
+        "kelvin_top.cc",
+    ],
+    hdrs = [
+        "kelvin_top.h",
+    ],
+    copts = ["-O3"],
+    deps = [
+        ":kelvin_decoder",
+        ":kelvin_isa",
+        ":kelvin_state",
+        "@com_google_absl//absl/flags:flag",
+        "@com_google_absl//absl/functional:bind_front",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/log:check",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/synchronization",
+        "@com_google_mpact-riscv//riscv:riscv_arm_semihost",
+        "@com_google_mpact-riscv//riscv:riscv_breakpoint",
+        "@com_google_mpact-riscv//riscv:riscv_state",
+        "@com_google_mpact-sim//mpact/sim/generic:arch_state",
+        "@com_google_mpact-sim//mpact/sim/generic:component",
+        "@com_google_mpact-sim//mpact/sim/generic:core",
+        "@com_google_mpact-sim//mpact/sim/generic:core_debug_interface",
+        "@com_google_mpact-sim//mpact/sim/generic:decode_cache",
+        "@com_google_mpact-sim//mpact/sim/util/memory",
+    ],
+)
+
+cc_binary(
+    name = "kelvin_sim",
+    srcs = ["kelvin_sim.cc"],
+    copts = ["-O3"],
+    data = [
+        "//sim/test:testfiles/hello_world_rv32imf.elf",
+        "//sim/test:testfiles/rv32i.elf",
+        "//sim/test:testfiles/rv32m.elf",
+        "//sim/test:testfiles/rv32soft_fp.elf",
+    ],
+    deps = [
+        ":kelvin_top",
+        "@com_google_absl//absl/flags:flag",
+        "@com_google_absl//absl/flags:parse",
+        "@com_google_absl//absl/flags:usage",
+        "@com_google_absl//absl/log",
+        "@com_google_mpact-riscv//riscv:debug_command_shell",
+        "@com_google_mpact-sim//mpact/sim/util/program_loader:elf_loader",
+    ],
+)
diff --git a/sim/decoder.cc b/sim/decoder.cc
new file mode 100644
index 0000000..eeb1d43
--- /dev/null
+++ b/sim/decoder.cc
@@ -0,0 +1,73 @@
+#include "sim/decoder.h"
+
+namespace kelvin::sim {
+
+KelvinDecoder::KelvinDecoder(KelvinState *state,
+                             mpact::sim::util::MemoryInterface *memory)
+    : state_(state), memory_(memory) {
+  // Get a handle to the internal error in the program error controller.
+  decode_error_ = state->program_error_controller()->GetProgramError(
+      mpact::sim::generic::ProgramErrorController::kInternalErrorName);
+
+  // Need a data buffer to load instructions from memory. Allocate a single
+  // buffer that can be reused for each instruction word.
+  inst_db_ = state_->db_factory()->Allocate<uint32_t>(1);
+  // Allocate the isa factory class, the top level isa decoder
+  // instance, and the encoding parser.
+  kelvin_isa_factory_ = new KelvinIsaFactory();
+  kelvin_isa_ = new isa32::KelvinInstructionSet(state, kelvin_isa_factory_);
+  kelvin_encoding_ = new isa32::KelvinEncoding(state);
+  decode_error_ = state->program_error_controller()->GetProgramError(
+      mpact::sim::generic::ProgramErrorController::kInternalErrorName);
+}
+
+KelvinDecoder::~KelvinDecoder() {
+  inst_db_->DecRef();
+  delete kelvin_isa_;
+  delete kelvin_isa_factory_;
+  delete kelvin_encoding_;
+}
+
+mpact::sim::generic::Instruction *KelvinDecoder::DecodeInstruction(
+    uint64_t address) {
+  // First check that the address is aligned properly. If not, create and return
+  // an empty instruction object and raise an exception.
+  if (address & 0x1) {
+    auto *inst = new mpact::sim::generic::Instruction(address, state_);
+    inst->set_semantic_function(
+        [](mpact::sim::generic::Instruction *inst) { /* empty */ });
+    inst->set_size(1);
+    inst->SetDisassemblyString("Misaligned instruction address");
+    inst->set_opcode(static_cast<int>(isa32::OpcodeEnum::kNone));
+    state_->Trap(
+        /*is_interrupt*/ false, address,
+        *mpact::sim::riscv::ExceptionCode::kInstructionAddressMisaligned,
+        address ^ 0x1, inst);
+    return inst;
+  }
+
+  // If the address is greater than the max address, raise an exception.
+  if (address > state_->max_physical_address()) {
+    state_->Trap(/*is_interrupt*/ false, address,
+                 *mpact::sim::riscv::ExceptionCode::kInstructionAccessFault,
+                 address, nullptr);
+    auto *inst = new mpact::sim::generic::Instruction(address, state_);
+    inst->set_size(0);
+    inst->SetDisassemblyString("Instruction access fault");
+    inst->set_opcode(static_cast<int>(isa32::OpcodeEnum::kNone));
+    inst->set_semantic_function(
+        [](mpact::sim::generic::Instruction *inst) { /* empty */ });
+    return inst;
+  }
+
+  // Read the instruction word from memory and parse it in the encoding parser.
+  memory_->Load(address, inst_db_, nullptr, nullptr);
+  auto iword = inst_db_->Get<uint32_t>(0);
+  kelvin_encoding_->ParseInstruction(iword);
+
+  // Call the isa decoder to obtain a new instruction object for the instruction
+  // word that was parsed above.
+  auto *instruction = kelvin_isa_->Decode(address, kelvin_encoding_);
+  return instruction;
+}
+}  // namespace kelvin::sim
diff --git a/sim/decoder.h b/sim/decoder.h
new file mode 100644
index 0000000..087fa16
--- /dev/null
+++ b/sim/decoder.h
@@ -0,0 +1,59 @@
+#ifndef SIM_DECODER_H_
+#define SIM_DECODER_H_
+
+#include <memory>
+
+#include "sim/kelvin_decoder.h"
+#include "sim/kelvin_encoding.h"
+#include "sim/kelvin_state.h"
+#include "mpact/sim/generic/arch_state.h"
+#include "mpact/sim/generic/decoder_interface.h"
+#include "mpact/sim/generic/instruction.h"
+#include "mpact/sim/util/memory/memory_interface.h"
+
+namespace kelvin::sim {
+
+// This is the factory class needed by the generated decoder. It is responsible
+// for creating the decoder for each slot instance. Since the RISC-V
+// architecture only has a single slot, it's a pretty simple class.
+class KelvinIsaFactory : public isa32::KelvinInstructionSetFactory {
+ public:
+  std::unique_ptr<isa32::KelvinSlot> CreateKelvinSlot(
+      mpact::sim::generic::ArchState *state) override {
+    return std::make_unique<isa32::KelvinSlot>(state);
+  }
+};
+
+// This class implements the generic DecoderInterface and provides a bridge
+// to the (isa specific) generated decoder classes.
+class KelvinDecoder : public mpact::sim::generic::DecoderInterface {
+ public:
+  using SlotEnum = isa32::SlotEnum;
+  using OpcodeEnum = isa32::OpcodeEnum;
+
+  KelvinDecoder(KelvinState *state, mpact::sim::util::MemoryInterface *memory);
+  KelvinDecoder() = delete;
+  ~KelvinDecoder() override;
+
+  // This will always return a valid instruction that can be executed. In the
+  // case of a decode error, the semantic function in the instruction object
+  // instance will raise an internal simulator error when executed.
+  mpact::sim::generic::Instruction *DecodeInstruction(
+      uint64_t address) override;
+
+  // Getter.
+  isa32::KelvinEncoding *kelvin_encoding() const { return kelvin_encoding_; }
+
+ private:
+  KelvinState *state_;
+  mpact::sim::util::MemoryInterface *memory_;
+  std::unique_ptr<mpact::sim::generic::ProgramError> decode_error_;
+  mpact::sim::generic::DataBuffer *inst_db_;
+  isa32::KelvinEncoding *kelvin_encoding_;
+  KelvinIsaFactory *kelvin_isa_factory_;
+  isa32::KelvinInstructionSet *kelvin_isa_;
+};
+
+}  // namespace kelvin::sim
+
+#endif  // SIM_DECODER_H_
diff --git a/sim/kelvin.bin_fmt b/sim/kelvin.bin_fmt
new file mode 100644
index 0000000..b68959b
--- /dev/null
+++ b/sim/kelvin.bin_fmt
@@ -0,0 +1,1438 @@
+
+// Kelvin instruction decoder.
+decoder Kelvin {
+  namespace kelvin::sim::encoding;
+  opcode_enum = "isa32::OpcodeEnum";
+  includes {
+    #include "sim/kelvin_decoder.h"
+  }
+  KelvinInst;
+  KelvinVectorInst;
+};
+
+format Inst32Format[32] {
+  fields:
+    unsigned bits[25];
+    unsigned opcode[7];
+};
+
+// Risc-V R-Type format.
+format RType[32] : Inst32Format {
+  fields:
+    unsigned func7[7];
+    unsigned rs2[5];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned rd[5];
+    unsigned opcode[7];
+  overlays:
+    unsigned r_uimm5[5] = rs2;
+};
+
+// Risc-V R4-Type format.
+format R4Type[32] : Inst32Format {
+  fields:
+    unsigned rs3[5];
+    unsigned func2[2];
+    unsigned rs2[5];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned rd[5];
+    unsigned opcode[7];
+};
+
+// Risc-V I-Type format.
+format IType[32] : Inst32Format {
+  fields:
+    signed imm12[12];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned rd[5];
+    unsigned opcode[7];
+  overlays:
+    unsigned u_imm12[12] = imm12;
+    unsigned i_uimm5[5] = rs1;
+};
+
+// Risc-V S-Type format.
+format SType[32] : Inst32Format {
+  fields:
+    unsigned imm7[7];
+    unsigned rs2[5];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned imm5[5];
+    unsigned opcode[7];
+  overlays:
+    signed s_imm[12] = imm7, imm5;
+};
+
+// Risc-V B-Type format.
+format BType[32] : Inst32Format {
+  fields:
+    unsigned imm7[7];
+    unsigned rs2[5];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned imm5[5];
+    unsigned opcode[7];
+  overlays:
+    signed b_imm[13] = imm7[6], imm5[0], imm7[5..0], imm5[4..1], 0b0;
+};
+
+// Risc-V U-Type format.
+format UType[32] : Inst32Format {
+  fields:
+    unsigned imm20[20];
+    unsigned rd[5];
+    unsigned opcode[7];
+  overlays:
+    unsigned u_imm[32] = imm20, 0b0000'0000'0000;
+};
+
+// Risc-V J-Type format.
+format JType[32] : Inst32Format {
+  fields:
+    unsigned imm20[20];
+    unsigned rd[5];
+    unsigned opcode[7];
+  overlays:
+    signed j_imm[21] = imm20[19, 7..0, 8, 18..9], 0b0;
+};
+
+// Risc-V Fence format.
+format Fence[32] : Inst32Format {
+  fields:
+    unsigned fm[4];
+    unsigned pred[4];
+    unsigned succ[4];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned rd[5];
+    unsigned opcode[7];
+};
+
+// Risc-V A-Type format.
+format AType[32] : Inst32Format {
+  fields:
+    unsigned func5[5];
+    unsigned aq[1];
+    unsigned rl[1];
+    unsigned rs2[5];
+    unsigned rs1[5];
+    unsigned func3[3];
+    unsigned rd[5];
+    unsigned opcode[7];
+};
+
+// Kelvin 2 args Vector format.
+format KelvinV2ArgsType[32] {
+  fields:
+    unsigned func2[6];
+    unsigned vs2[6];
+    unsigned vs1[6];
+    unsigned sz[2]; // .b==0b00, .h==0b01, .w==0b10
+    unsigned vd[6];
+    unsigned m[1];
+    unsigned func1[3];
+    unsigned form[2]; // .vv==0b00, .vx==0b10, .xx==0b11
+};
+
+// Kelvin system instruction format (cache, getvl).
+format KelvinSystemType[32] : Inst32Format {
+  fields:
+    unsigned func2[4];
+    unsigned m[1];
+    unsigned mode[2];
+    unsigned rs2[5];
+    unsigned rs1[5];
+    unsigned func1[3];
+    unsigned rd[5];
+    unsigned opcode[7];
+};
+
+instruction group KelvinInst[32] : Inst32Format {
+  lui    : UType  : opcode == 0b011'0111;
+  auipc  : UType  : opcode == 0b001'0111;
+  jal    : JType  : rd != 0, opcode == 0b110'1111;
+  j      : JType  : rd == 0, opcode == 0b110'1111;
+  jalr   : IType  : rd != 0, func3 == 0b000, opcode == 0b110'0111;
+  jr     : IType  : rd == 0, func3 == 0b000, opcode == 0b110'0111;
+  beq    : BType  : func3 == 0b000, opcode == 0b110'0011;
+  bne    : BType  : func3 == 0b001, opcode == 0b110'0011;
+  blt    : BType  : func3 == 0b100, opcode == 0b110'0011;
+  bge    : BType  : func3 == 0b101, opcode == 0b110'0011;
+  bltu   : BType  : func3 == 0b110, opcode == 0b110'0011;
+  bgeu   : BType  : func3 == 0b111, opcode == 0b110'0011;
+  lb     : BType  : func3 == 0b000, opcode == 0b000'0011;
+  lh     : BType  : func3 == 0b001, opcode == 0b000'0011;
+  lw     : BType  : func3 == 0b010, opcode == 0b000'0011;
+  lbu    : BType  : func3 == 0b100, opcode == 0b000'0011;
+  lhu    : BType  : func3 == 0b101, opcode == 0b000'0011;
+  sb     : SType  : func3 == 0b000, opcode == 0b010'0011;
+  sh     : SType  : func3 == 0b001, opcode == 0b010'0011;
+  sw     : SType  : func3 == 0b010, opcode == 0b010'0011;
+  addi   : IType  : func3 == 0b000, opcode == 0b001'0011;
+  slti   : IType  : func3 == 0b010, opcode == 0b001'0011;
+  sltiu  : IType  : func3 == 0b011, opcode == 0b001'0011;
+  xori   : IType  : func3 == 0b100, opcode == 0b001'0011;
+  ori    : IType  : func3 == 0b110, opcode == 0b001'0011;
+  andi   : IType  : func3 == 0b111, opcode == 0b001'0011;
+  slli   : RType  : func7 == 0b000'0000, func3==0b001, opcode == 0b001'0011;
+  srli   : RType  : func7 == 0b000'0000, func3==0b101, opcode == 0b001'0011;
+  srai   : RType  : func7 == 0b010'0000, func3==0b101, opcode == 0b001'0011;
+  add    : RType  : func7 == 0b000'0000, func3==0b000, opcode == 0b011'0011;
+  sub    : RType  : func7 == 0b010'0000, func3==0b000, opcode == 0b011'0011;
+  sll    : RType  : func7 == 0b000'0000, func3==0b001, opcode == 0b011'0011;
+  slt    : RType  : func7 == 0b000'0000, func3==0b010, opcode == 0b011'0011;
+  sltu   : RType  : func7 == 0b000'0000, func3==0b011, opcode == 0b011'0011;
+  xor    : RType  : func7 == 0b000'0000, func3==0b100, opcode == 0b011'0011;
+  srl    : RType  : func7 == 0b000'0000, func3==0b101, opcode == 0b011'0011;
+  sra    : RType  : func7 == 0b010'0000, func3==0b101, opcode == 0b011'0011;
+  or     : RType  : func7 == 0b000'0000, func3==0b110, opcode == 0b011'0011;
+  and    : RType  : func7 == 0b000'0000, func3==0b111, opcode == 0b011'0011;
+  fence  : Fence  : func3 == 0b000, opcode == 0b000'1111;
+  ecall  : Inst32Format : bits == 0b0000'0000'0000'00000'000'00000, opcode == 0b111'0011;
+  ebreak : Inst32Format : bits == 0b0000'0000'0001'00000'000'00000, opcode == 0b111'0011;
+  // RiscV32 Instruction fence.
+  fencei : IType  : func3 == 001, opcode == 0b000'1111;
+  // RiscV32 multiply divide.
+  mul    : RType  : func7 == 0b000'0001, func3 == 0b000, opcode == 0b011'0011;
+  mulh   : RType  : func7 == 0b000'0001, func3 == 0b001, opcode == 0b011'0011;
+  mulhsu : RType  : func7 == 0b000'0001, func3 == 0b010, opcode == 0b011'0011;
+  mulhu  : RType  : func7 == 0b000'0001, func3 == 0b011, opcode == 0b011'0011;
+  div    : RType  : func7 == 0b000'0001, func3 == 0b100, opcode == 0b011'0011;
+  divu   : RType  : func7 == 0b000'0001, func3 == 0b101, opcode == 0b011'0011;
+  rem    : RType  : func7 == 0b000'0001, func3 == 0b110, opcode == 0b011'0011;
+  remu   : RType  : func7 == 0b000'0001, func3 == 0b111, opcode == 0b011'0011;
+  // RiscV32 CSR manipulation instructions.
+  csrrw    : IType  : func3 == 0b001, rd != 0,  opcode == 0b111'0011;
+  csrrs    : IType  : func3 == 0b010, rs1 != 0, rd != 0, opcode == 0b111'0011;
+  csrrc    : IType  : func3 == 0b011, rs1 != 0, rd != 0, opcode == 0b111'0011;
+  csrrs_nr : IType  : func3 == 0b010, rs1 != 0, rd == 0, opcode == 0b111'0011;
+  csrrc_nr : IType  : func3 == 0b011, rs1 != 0, rd == 0, opcode == 0b111'0011;
+  csrrw_nr : IType  : func3 == 0b001, rd == 0,  opcode == 0b111'0011;
+  csrrs_nw : IType  : func3 == 0b010, rs1 == 0, opcode == 0b111'0011;
+  csrrc_nw : IType  : func3 == 0b011, rs1 == 0, opcode == 0b111'0011;
+  csrrwi   : IType  : func3 == 0b101, rd != 0,  opcode == 0b111'0011;
+  csrrsi   : IType  : func3 == 0b110, rs1 != 0, rd != 0, opcode == 0b111'0011;
+  csrrci   : IType  : func3 == 0b111, rs1 != 0, rd != 0, opcode == 0b111'0011;
+  csrrsi_nr: IType  : func3 == 0b110, rs1 != 0, rd == 0, opcode == 0b111'0011;
+  csrrci_nr: IType  : func3 == 0b111, rs1 != 0, rd == 0, opcode == 0b111'0011;
+  csrrwi_nr: IType  : func3 == 0b101, rd == 0,  opcode == 0b111'0011;
+  csrrsi_nw: IType  : func3 == 0b110, rs1 == 0, opcode == 0b111'0011;
+  csrrci_nw: IType  : func3 == 0b111, rs1 == 0, opcode == 0b111'0011;
+  // RiscV32 Privileged instructions.
+  uret    : Inst32Format  : bits == 0b000'0000'00010'00000'000'00000, opcode == 0b111'0011;
+  sret    : Inst32Format  : bits == 0b000'1000'00010'00000'000'00000, opcode == 0b111'0011;
+  mret    : Inst32Format  : bits == 0b001'1000'00010'00000'000'00000, opcode == 0b111'0011;
+  wfi     : Inst32Format  : bits == 0b000'1000'00101'00000'000'00000, opcode == 0b111'0011;
+  mpause  : Inst32Format  : bits == 0b000'0100'00000'00000'000'00000, opcode == 0b111'0011;
+  sfence_vma_zz : RType : func7 == 0b000'1001, rs2 == 0, rs1 == 0, func3 == 0, rd == 0, opcode == 0b111'0011;
+  sfence_vma_zn : RType : func7 == 0b000'1001, rs2 != 0, rs1 == 0, func3 == 0, rd == 0, opcode == 0b111'0011;
+  sfence_vma_nz : RType : func7 == 0b000'1001, rs2 == 0, rs1 != 0, func3 == 0, rd == 0, opcode == 0b111'0011;
+  sfence_vma_nn : RType : func7 == 0b000'1001, rs2 != 0, rs1 != 0, func3 == 0, rd == 0, opcode == 0b111'0011;
+  // Kelvin memory flush instructions.
+  flushall : Inst32Format : bits == 0b001'0011'00000'00000'000'00000, opcode == 0b111'0111;
+  flushat  : RType        : func7 == 0b001'0011, rs2 == 0, rs1 != 0, func3 == 0, rd == 0, opcode == 0b111'0111;
+  // Kelvin system instructions.
+  getmaxvl_b   : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b00, rs2 == 0, rs1 == 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getmaxvl_h   : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b01, rs2 == 0, rs1 == 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getmaxvl_w   : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b10, rs2 == 0, rs1 == 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_b_x    : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b00, rs2 == 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_h_x    : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b01, rs2 == 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_w_x    : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b10, rs2 == 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_b_xx   : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b00, rs2 != 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_h_xx   : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b01, rs2 != 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_w_xx   : KelvinSystemType : func2 == 0b0001, m == 0, mode == 0b10, rs2 != 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getmaxvl_b_m : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b00, rs2 == 0, rs1 == 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getmaxvl_h_m : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b01, rs2 == 0, rs1 == 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getmaxvl_w_m : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b10, rs2 == 0, rs1 == 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_b_x_m  : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b00, rs2 == 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_h_x_m  : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b01, rs2 == 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_w_x_m  : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b10, rs2 == 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_b_xx_m : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b00, rs2 != 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_h_xx_m : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b01, rs2 != 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  getvl_w_xx_m : KelvinSystemType : func2 == 0b0001, m == 1, mode == 0b10, rs2 != 0, rs1 != 0, func1 == 0, rd != 0, opcode == 0b111'0111;
+  // Kelvin log instructions.
+  flog         : KelvinSystemType : func2 == 0b0111, m == 1, mode == 0, rs2 == 0, rs1 != 0, func1 == 0, rd == 0, opcode == 0b111'0111;
+  slog         : KelvinSystemType : func2 == 0b0111, m == 1, mode == 0, rs2 == 0, rs1 != 0, func1 == 1, rd == 0, opcode == 0b111'0111;
+  clog         : KelvinSystemType : func2 == 0b0111, m == 1, mode == 0, rs2 == 0, rs1 != 0, func1 == 2, rd == 0, opcode == 0b111'0111;
+  klog         : KelvinSystemType : func2 == 0b0111, m == 1, mode == 0, rs2 == 0, rs1 != 0, func1 == 3, rd == 0, opcode == 0b111'0111;
+};
+
+instruction group KelvinVectorInst[32] : KelvinV2ArgsType {
+  // Kelvin Vector instructions.
+
+  // vadd
+  vadd_b_vv     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vadd_b_vx     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vadd_b_vv_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vadd_b_vx_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vadd_h_vv     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vadd_h_vx     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vadd_h_vv_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vadd_h_vx_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vadd_w_vv     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vadd_w_vx     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vadd_w_vv_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vadd_w_vx_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vsub
+  vsub_b_vv     : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vsub_b_vx     : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vsub_b_vv_m   : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vsub_b_vx_m   : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vsub_h_vv     : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vsub_h_vx     : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vsub_h_vv_m   : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vsub_h_vx_m   : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vsub_w_vv     : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vsub_w_vx     : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vsub_w_vv_m   : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vsub_w_vx_m   : KelvinV2ArgsType : func2 == 0b000'001, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vrsub
+  vrsub_b_vv     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vrsub_b_vx     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vrsub_b_vv_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vrsub_b_vx_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vrsub_h_vv     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vrsub_h_vx     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vrsub_h_vv_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vrsub_h_vx_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vrsub_w_vv     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vrsub_w_vx     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vrsub_w_vv_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vrsub_w_vx_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // veq
+  veq_b_vv       : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  veq_b_vx       : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  veq_b_vv_m     : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  veq_b_vx_m     : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  veq_h_vv       : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  veq_h_vx       : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  veq_h_vv_m     : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  veq_h_vx_m     : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  veq_w_vv       : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  veq_w_vx       : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  veq_w_vv_m     : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  veq_w_vx_m     : KelvinV2ArgsType : func2 == 0b000'110, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vne
+  vne_b_vv      : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vne_b_vx      : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vne_b_vv_m    : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vne_b_vx_m    : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vne_h_vv      : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vne_h_vx      : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vne_h_vv_m    : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vne_h_vx_m    : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vne_w_vv      : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vne_w_vx      : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vne_w_vv_m    : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vne_w_vx_m    : KelvinV2ArgsType : func2 == 0b000'111, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vlt
+  vlt_b_vv       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vlt_b_vx       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vlt_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vlt_b_vx_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vlt_h_vv       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vlt_h_vx       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vlt_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vlt_h_vx_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vlt_w_vv       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vlt_w_vx       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vlt_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vlt_w_vx_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vltu
+  vlt_u_b_vv     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vlt_u_b_vx     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vlt_u_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vlt_u_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vlt_u_h_vv     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vlt_u_h_vx     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vlt_u_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vlt_u_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vlt_u_w_vv     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vlt_u_w_vx     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vlt_u_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vlt_u_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vle
+  vle_b_vv       : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vle_b_vx       : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vle_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vle_b_vx_m     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vle_h_vv       : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vle_h_vx       : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vle_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vle_h_vx_m     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vle_w_vv       : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vle_w_vx       : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vle_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vle_w_vx_m     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vleu
+  vle_u_b_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vle_u_b_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vle_u_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vle_u_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vle_u_h_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vle_u_h_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vle_u_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vle_u_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vle_u_w_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vle_u_w_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vle_u_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vle_u_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vgt
+  vgt_b_vv       : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vgt_b_vx       : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vgt_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vgt_b_vx_m     : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vgt_h_vv       : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vgt_h_vx       : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vgt_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vgt_h_vx_m     : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vgt_w_vv       : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vgt_w_vx       : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vgt_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vgt_w_vx_m     : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vgtu
+  vgt_u_b_vv     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vgt_u_b_vx     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vgt_u_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vgt_u_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vgt_u_h_vv     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vgt_u_h_vx     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vgt_u_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vgt_u_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vgt_u_w_vv     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vgt_u_w_vx     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vgt_u_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vgt_u_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vge
+  vge_b_vv       : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vge_b_vx       : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vge_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vge_b_vx_m     : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vge_h_vv       : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vge_h_vx       : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vge_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vge_h_vx_m     : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vge_w_vv       : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vge_w_vx       : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vge_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vge_w_vx_m     : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vgeu
+  vge_u_b_vv       : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vge_u_b_vx       : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vge_u_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vge_u_b_vx_m     : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vge_u_h_vv       : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vge_u_h_vx       : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vge_u_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vge_u_h_vx_m     : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vge_u_w_vv       : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vge_u_w_vx       : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vge_u_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vge_u_w_vx_m     : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vabsd
+  vabsd_b_vv       : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vabsd_b_vx       : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vabsd_b_vv_m     : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vabsd_b_vx_m     : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vabsd_h_vv       : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vabsd_h_vx       : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vabsd_h_vv_m     : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vabsd_h_vx_m     : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vabsd_w_vv       : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vabsd_w_vx       : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vabsd_w_vv_m     : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vabsd_w_vx_m     : KelvinV2ArgsType : func2 == 0b0'10000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vabsdu
+  vabsd_u_b_vv    : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vabsd_u_b_vx    : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vabsd_u_b_vv_m  : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vabsd_u_b_vx_m  : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vabsd_u_h_vv    : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vabsd_u_h_vx    : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vabsd_u_h_vv_m  : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vabsd_u_h_vx_m  : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vabsd_u_w_vv    : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vabsd_u_w_vx    : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vabsd_u_w_vv_m  : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vabsd_u_w_vx_m  : KelvinV2ArgsType : func2 == 0b0'10001, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vmax
+  vmax_b_vv       : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vmax_b_vx       : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vmax_b_vv_m     : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vmax_b_vx_m     : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vmax_h_vv       : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vmax_h_vx       : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vmax_h_vv_m     : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vmax_h_vx_m     : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vmax_w_vv       : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vmax_w_vx       : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vmax_w_vv_m     : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vmax_w_vx_m     : KelvinV2ArgsType : func2 == 0b0'10010, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vmaxu
+  vmax_u_b_vv    : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vmax_u_b_vx    : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vmax_u_b_vv_m  : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vmax_u_b_vx_m  : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vmax_u_h_vv    : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vmax_u_h_vx    : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vmax_u_h_vv_m  : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vmax_u_h_vx_m  : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vmax_u_w_vv    : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vmax_u_w_vx    : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vmax_u_w_vv_m  : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vmax_u_w_vx_m  : KelvinV2ArgsType : func2 == 0b0'10011, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vmin
+  vmin_b_vv       : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vmin_b_vx       : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vmin_b_vv_m     : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vmin_b_vx_m     : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vmin_h_vv       : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vmin_h_vx       : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vmin_h_vv_m     : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vmin_h_vx_m     : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vmin_w_vv       : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vmin_w_vx       : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vmin_w_vv_m     : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vmin_w_vx_m     : KelvinV2ArgsType : func2 == 0b0'10100, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vminu
+  vmin_u_b_vv    : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vmin_u_b_vx    : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vmin_u_b_vv_m  : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vmin_u_b_vx_m  : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vmin_u_h_vv    : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vmin_u_h_vx    : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vmin_u_h_vv_m  : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vmin_u_h_vx_m  : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vmin_u_w_vv    : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vmin_u_w_vx    : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vmin_u_w_vv_m  : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vmin_u_w_vx_m  : KelvinV2ArgsType : func2 == 0b0'10101, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  // vadd3
+  vadd3_b_vv       : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b00;
+  vadd3_b_vx       : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b00, m == 0b00, func1 == 0b000, form == 0b10;
+  vadd3_b_vv_m     : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b00;
+  vadd3_b_vx_m     : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b00, m == 0b01, func1 == 0b000, form == 0b10;
+  vadd3_h_vv       : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b00;
+  vadd3_h_vx       : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b01, m == 0b00, func1 == 0b000, form == 0b10;
+  vadd3_h_vv_m     : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b00;
+  vadd3_h_vx_m     : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b01, m == 0b01, func1 == 0b000, form == 0b10;
+  vadd3_w_vv       : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b00;
+  vadd3_w_vx       : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b10, m == 0b00, func1 == 0b000, form == 0b10;
+  vadd3_w_vv_m     : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b00;
+  vadd3_w_vx_m     : KelvinV2ArgsType : func2 == 0b0'11000, sz == 0b10, m == 0b01, func1 == 0b000, form == 0b10;
+
+  //vadds
+  vadds_b_vv     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vadds_b_vx     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vadds_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vadds_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vadds_h_vv     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vadds_h_vx     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vadds_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vadds_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vadds_w_vv     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vadds_w_vx     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vadds_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vadds_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  // vaddsu
+  vadds_u_b_vv   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vadds_u_b_vx   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vadds_u_b_vv_m : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vadds_u_b_vx_m : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vadds_u_h_vv   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vadds_u_h_vx   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vadds_u_h_vv_m : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vadds_u_h_vx_m : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vadds_u_w_vv   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vadds_u_w_vx   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vadds_u_w_vv_m : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vadds_u_w_vx_m : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+ //vsubs
+  vsubs_b_vv     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubs_b_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubs_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubs_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vsubs_h_vv     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubs_h_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubs_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubs_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vsubs_w_vv     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubs_w_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubs_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubs_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  // vsubsu
+  vsubs_u_b_vv   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubs_u_b_vx   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubs_u_b_vv_m : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubs_u_b_vx_m : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vsubs_u_h_vv   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubs_u_h_vx   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubs_u_h_vv_m : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubs_u_h_vx_m : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vsubs_u_w_vv   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubs_u_w_vx   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubs_u_w_vv_m : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubs_u_w_vx_m : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vaddw
+  vaddw_h_vv     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vaddw_h_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vaddw_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vaddw_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vaddw_w_vv     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vaddw_w_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vaddw_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vaddw_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vaddwu
+  vaddw_h_u_vv     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vaddw_h_u_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vaddw_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vaddw_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vaddw_w_u_vv     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vaddw_w_u_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vaddw_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vaddw_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vsubw
+  vsubw_h_vv     : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubw_h_vx     : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubw_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubw_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vsubw_w_vv     : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubw_w_vx     : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubw_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubw_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vsubwu
+  vsubw_h_u_vv     : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubw_h_u_vx     : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubw_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubw_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vsubw_w_u_vv     : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vsubw_w_u_vx     : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vsubw_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vsubw_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vacc
+  vacc_h_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vacc_h_vx     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vacc_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vacc_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vacc_w_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vacc_w_vx     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vacc_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vacc_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vaccu
+  vacc_h_u_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vacc_h_u_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vacc_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vacc_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vacc_w_u_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vacc_w_u_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vacc_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vacc_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vpadd
+  vpadd_h_v     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vpadd_h_v_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vpadd_w_v     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vpadd_w_v_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vpaddu
+  vpadd_h_u_v     : KelvinV2ArgsType : func2 == 0b00'1101, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vpadd_h_u_v_m   : KelvinV2ArgsType : func2 == 0b00'1101, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vpadd_w_u_v     : KelvinV2ArgsType : func2 == 0b00'1101, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vpadd_w_u_v_m   : KelvinV2ArgsType : func2 == 0b00'1101, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vpsub
+  vpsub_h_v     : KelvinV2ArgsType : func2 == 0b00'1110, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vpsub_h_v_m   : KelvinV2ArgsType : func2 == 0b00'1110, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vpsub_w_v     : KelvinV2ArgsType : func2 == 0b00'1110, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vpsub_w_v_m   : KelvinV2ArgsType : func2 == 0b00'1110, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vpsubu
+  vpsub_h_u_v     : KelvinV2ArgsType : func2 == 0b00'1111, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vpsub_h_u_v_m   : KelvinV2ArgsType : func2 == 0b00'1111, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vpsub_w_u_v     : KelvinV2ArgsType : func2 == 0b00'1111, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vpsub_w_u_v_m   : KelvinV2ArgsType : func2 == 0b00'1111, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhadd
+  vhadd_b_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_b_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_h_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_h_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_w_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_w_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhadd.r
+  vhadd_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_h_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_h_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_h_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_w_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_w_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_w_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_w_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhadd.u
+  vhadd_b_u_vv     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_b_u_vx     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_b_u_vv_m   : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_b_u_vx_m   : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_h_u_vv     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_h_u_vx     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_w_u_vv     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_w_u_vx     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhadd.ur
+  vhadd_b_ur_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_b_ur_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_b_ur_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_b_ur_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_h_ur_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_h_ur_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_h_ur_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_h_ur_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhadd_w_ur_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhadd_w_ur_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhadd_w_ur_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhadd_w_ur_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhsub
+  vhsub_b_vv     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_b_vx     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_h_vv     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_h_vx     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_w_vv     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_w_vx     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhsub.r
+  vhsub_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_h_r_vv     : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_h_r_vx     : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_h_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_w_r_vv     : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_w_r_vx     : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_w_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_w_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0110, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhsub.u
+  vhsub_b_u_vv     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_b_u_vx     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_b_u_vv_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_b_u_vx_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_h_u_vv     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_h_u_vx     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_w_u_vv     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_w_u_vx     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vhsub.ur
+  vhsub_b_ur_vv     : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_b_ur_vx     : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b00, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_b_ur_vv_m   : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_b_ur_vx_m   : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b00, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_h_ur_vv     : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_h_ur_vx     : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b01, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_h_ur_vv_m   : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_h_ur_vx_m   : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b01, m == 0b01, func1 == 0b100, form == 0b10;
+  vhsub_w_ur_vv     : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b00;
+  vhsub_w_ur_vx     : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b10, m == 0b00, func1 == 0b100, form == 0b10;
+  vhsub_w_ur_vv_m   : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b00;
+  vhsub_w_ur_vx_m   : KelvinV2ArgsType : func2 == 0b01'0111, sz == 0b10, m == 0b01, func1 == 0b100, form == 0b10;
+
+  //vand
+  vand_vv       : KelvinV2ArgsType : func2 == 0b00'0000, m == 0b00, func1 == 0b001, form == 0b00;
+  vand_vv_m     : KelvinV2ArgsType : func2 == 0b00'0000, m == 0b01, func1 == 0b001, form == 0b00;
+  vand_b_vx     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b00, func1 == 0b001, form == 0b10;
+  vand_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b01, func1 == 0b001, form == 0b10;
+  vand_h_vx     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b00, func1 == 0b001, form == 0b10;
+  vand_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b01, func1 == 0b001, form == 0b10;
+  vand_w_vx     : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b00, func1 == 0b001, form == 0b10;
+  vand_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vor
+  vor_vv        : KelvinV2ArgsType : func2 == 0b00'0001, m == 0b00, func1 == 0b001, form == 0b00;
+  vor_vv_m      : KelvinV2ArgsType : func2 == 0b00'0001, m == 0b01, func1 == 0b001, form == 0b00;
+  vor_b_vx      : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b00, func1 == 0b001, form == 0b10;
+  vor_b_vx_m    : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b01, func1 == 0b001, form == 0b10;
+  vor_h_vx      : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b00, func1 == 0b001, form == 0b10;
+  vor_h_vx_m    : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b01, func1 == 0b001, form == 0b10;
+  vor_w_vx      : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b00, func1 == 0b001, form == 0b10;
+  vor_w_vx_m    : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vxor
+  vxor_vv       : KelvinV2ArgsType : func2 == 0b00'0010, m == 0b00, func1 == 0b001, form == 0b00;
+  vxor_vv_m     : KelvinV2ArgsType : func2 == 0b00'0010, m == 0b01, func1 == 0b001, form == 0b00;
+  vxor_b_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b00, func1 == 0b001, form == 0b10;
+  vxor_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b01, func1 == 0b001, form == 0b10;
+  vxor_h_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b00, func1 == 0b001, form == 0b10;
+  vxor_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b01, func1 == 0b001, form == 0b10;
+  vxor_w_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b00, func1 == 0b001, form == 0b10;
+  vxor_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vrev
+  vrev_b_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b00, m == 0b00, func1 == 0b001, form == 0b10;
+  vrev_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b00, m == 0b01, func1 == 0b001, form == 0b10;
+  vrev_h_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b00, func1 == 0b001, form == 0b10;
+  vrev_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b01, func1 == 0b001, form == 0b10;
+  vrev_w_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b00, func1 == 0b001, form == 0b10;
+  vrev_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vror
+  vror_b_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b00, m == 0b00, func1 == 0b001, form == 0b10;
+  vror_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b00, m == 0b01, func1 == 0b001, form == 0b10;
+  vror_h_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b00, func1 == 0b001, form == 0b10;
+  vror_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b01, func1 == 0b001, form == 0b10;
+  vror_w_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b00, func1 == 0b001, form == 0b10;
+  vror_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vmvp
+  vmvp_vv       : KelvinV2ArgsType : func2 == 0b00'1101, m == 0b00, func1 == 0b001, form == 0b00;
+  vmvp_vv_m     : KelvinV2ArgsType : func2 == 0b00'1101, m == 0b01, func1 == 0b001, form == 0b00;
+  vmvp_b_vx     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b00, func1 == 0b001, form == 0b10;
+  vmvp_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b01, func1 == 0b001, form == 0b10;
+  vmvp_h_vx     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b00, func1 == 0b001, form == 0b10;
+  vmvp_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b01, func1 == 0b001, form == 0b10;
+  vmvp_w_vx     : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b00, func1 == 0b001, form == 0b10;
+  vmvp_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vsll
+  vsll_b_vv     : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsll_b_vx     : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsll_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsll_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsll_h_vv     : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsll_h_vx     : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsll_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsll_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+  vsll_w_vv     : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vsll_w_vx     : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b10;
+  vsll_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+  vsll_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vsra
+  vsra_b_vv     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsra_b_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsra_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsra_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsra_h_vv     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsra_h_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsra_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsra_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+  vsra_w_vv     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vsra_w_vx     : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b10;
+  vsra_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+  vsra_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vsrl
+  vsrl_b_vv     : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrl_b_vx     : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrl_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrl_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsrl_h_vv     : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrl_h_vx     : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrl_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrl_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+  vsrl_w_vv     : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrl_w_vx     : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrl_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrl_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vsha
+  vsha_b_vv       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsha_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsha_h_vv       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsha_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsha_w_vv       : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vsha_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+  vsha_b_r_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsha_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsha_h_r_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsha_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsha_w_r_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vsha_w_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+
+  //vshl
+  vshl_b_vv       : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vshl_b_vv_m     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vshl_h_vv       : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vshl_h_vv_m     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vshl_w_vv       : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vshl_w_vv_m     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+  vshl_b_r_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vshl_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vshl_h_r_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vshl_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vshl_w_r_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b010, form == 0b00;
+  vshl_w_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b010, form == 0b00;
+
+  //vnot
+  vnot_v          : KelvinV2ArgsType : func2 == 0b00'0011, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vnot_v_m        : KelvinV2ArgsType : func2 == 0b00'0011, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vclb
+  vclb_b_v        : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vclb_b_v_m      : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+  vclb_h_v        : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vclb_h_v_m      : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+  vclb_w_v        : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vclb_w_v_m      : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vclz
+  vclz_b_v        : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vclz_b_v_m      : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+  vclz_h_v        : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vclz_h_v_m      : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+  vclz_w_v        : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vclz_w_v_m      : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vcpop
+  vcpop_b_v        : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vcpop_b_v_m      : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+  vcpop_h_v        : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vcpop_h_v_m      : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+  vcpop_w_v        : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vcpop_w_v_m      : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vmv
+  vmv_v          : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, m == 0b00, func1 == 0b001, form == 0b10;
+  vmv_v_m        : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, m == 0b01, func1 == 0b001, form == 0b10;
+
+  //vsrans
+  vsrans_b_vv       : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrans_b_vx       : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrans_b_vv_m     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrans_b_vx_m     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsrans_h_vv       : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrans_h_vx       : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrans_h_vv_m     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrans_h_vx_m     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+  vsrans_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrans_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrans_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrans_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsrans_h_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsrans_h_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsrans_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsrans_h_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vsransu
+  vsransu_b_vv       : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsransu_b_vx       : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsransu_b_vv_m     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsransu_b_vx_m     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsransu_h_vv       : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsransu_h_vx       : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsransu_h_vv_m     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsransu_h_vx_m     : KelvinV2ArgsType : func2 == 0b01'0001, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+  vsransu_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsransu_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsransu_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsransu_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsransu_h_r_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b00;
+  vsransu_h_r_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b00, func1 == 0b010, form == 0b10;
+  vsransu_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b00;
+  vsransu_h_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vsraqs
+  vsraqs_b_vv       : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsraqs_b_vx       : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsraqs_b_vv_m     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsraqs_b_vx_m     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsraqs_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsraqs_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsraqs_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsraqs_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vsraqsu
+  vsraqsu_b_vv       : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsraqsu_b_vx       : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsraqsu_b_vv_m     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsraqsu_b_vx_m     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+  vsraqsu_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'1011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b00;
+  vsraqsu_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'1011, sz == 0b00, m == 0b00, func1 == 0b010, form == 0b10;
+  vsraqsu_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'1011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b00;
+  vsraqsu_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'1011, sz == 0b00, m == 0b01, func1 == 0b010, form == 0b10;
+
+  //vmul
+  vmul_b_vv     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmul_b_vx     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmul_b_vv_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmul_b_vx_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmul_h_vv     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmul_h_vx     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmul_h_vv_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmul_h_vx_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmul_w_vv     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmul_w_vx     : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmul_w_vv_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmul_w_vx_m   : KelvinV2ArgsType : func2 == 0b000'000, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmuls
+  vmuls_b_vv     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmuls_b_vx     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmuls_b_vv_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmuls_b_vx_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmuls_h_vv     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmuls_h_vx     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmuls_h_vv_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmuls_h_vx_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmuls_w_vv     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmuls_w_vx     : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmuls_w_vv_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmuls_w_vx_m   : KelvinV2ArgsType : func2 == 0b000'010, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulsu
+  vmulsu_b_vv     : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulsu_b_vx     : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulsu_b_vv_m   : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulsu_b_vx_m   : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulsu_h_vv     : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulsu_h_vx     : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulsu_h_vv_m   : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulsu_h_vx_m   : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulsu_w_vv     : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulsu_w_vx     : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulsu_w_vv_m   : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulsu_w_vx_m   : KelvinV2ArgsType : func2 == 0b000'011, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulw
+  vmulw_h_vv     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulw_h_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulw_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulw_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulw_w_vv     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulw_w_vx     : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulw_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulw_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulwu
+  vmulw_h_u_vv     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulw_h_u_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulw_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulw_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulw_w_u_vv     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulw_w_u_vx     : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulw_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulw_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulh
+  vmulh_b_vv     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_b_vx     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_b_vv_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_b_vx_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_h_vv     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_h_vx     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_h_vv_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_h_vx_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_w_vv     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_w_vx     : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_w_vv_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_w_vx_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulh.r
+  vmulh_b_r_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_b_r_vx     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_h_r_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_h_r_vx     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_h_r_vx_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_w_r_vv     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_w_r_vx     : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_w_r_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_w_r_vx_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulh.u
+  vmulh_b_u_vv     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_b_u_vx     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_b_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_b_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_h_u_vv     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_h_u_vx     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_h_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_h_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_w_u_vv     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_w_u_vx     : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_w_u_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_w_u_vx_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmulh.ur
+  vmulh_b_ur_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_b_ur_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_b_ur_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_b_ur_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_h_ur_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_h_ur_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_h_ur_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_h_ur_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmulh_w_ur_vv     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmulh_w_ur_vx     : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmulh_w_ur_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmulh_w_ur_vx_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vdmulh
+  vdmulh_b_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_b_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vdmulh_h_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_h_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vdmulh_w_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_w_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vdmulh.r
+  vdmulh_b_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_b_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_b_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_b_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vdmulh_h_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_h_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_h_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_h_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vdmulh_w_r_vv     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_w_r_vx     : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_w_r_vv_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_w_r_vx_m   : KelvinV2ArgsType : func2 == 0b01'0010, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vdmulh.rn
+  vdmulh_b_rn_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_b_rn_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_b_rn_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_b_rn_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vdmulh_h_rn_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_h_rn_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_h_rn_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_h_rn_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vdmulh_w_rn_vv     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vdmulh_w_rn_vx     : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vdmulh_w_rn_vv_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vdmulh_w_rn_vx_m   : KelvinV2ArgsType : func2 == 0b01'0011, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmacc
+  vmacc_b_vv     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmacc_b_vx     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmacc_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmacc_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmacc_h_vv     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmacc_h_vx     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmacc_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmacc_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmacc_w_vv     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmacc_w_vx     : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmacc_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmacc_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'0100, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vmadd
+  vmadd_b_vv     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b00;
+  vmadd_b_vx     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b00, func1 == 0b011, form == 0b10;
+  vmadd_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b00;
+  vmadd_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b00, m == 0b01, func1 == 0b011, form == 0b10;
+  vmadd_h_vv     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b00;
+  vmadd_h_vx     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b00, func1 == 0b011, form == 0b10;
+  vmadd_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b00;
+  vmadd_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b01, m == 0b01, func1 == 0b011, form == 0b10;
+  vmadd_w_vv     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b00;
+  vmadd_w_vx     : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b00, func1 == 0b011, form == 0b10;
+  vmadd_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b00;
+  vmadd_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'0101, sz == 0b10, m == 0b01, func1 == 0b011, form == 0b10;
+
+  //vslidevn
+  vslidevn_b_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_b_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_b_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_b_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_h_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_h_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_h_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_h_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_w_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'0000, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_w_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'0001, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_w_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'0010, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevn_w_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'0011, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+
+  //vslidehn
+  vslidehn_b_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_b_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_b_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_b_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_h_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_h_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_h_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_h_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_w_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'0100, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_w_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'0101, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_w_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'0110, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehn_w_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'0111, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+
+  //vslidevp
+  vslidevp_b_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_b_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_b_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_b_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_h_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_h_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_h_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_h_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_w_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'1000, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_w_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'1001, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_w_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'1010, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidevp_w_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'1011, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+
+  //vslidehp
+  vslidehp_b_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_b_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_b_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_b_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_h_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_h_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_h_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_h_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_w_1_vv_m   : KelvinV2ArgsType : func2 == 0b00'1100, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_w_2_vv_m   : KelvinV2ArgsType : func2 == 0b00'1101, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_w_3_vv_m   : KelvinV2ArgsType : func2 == 0b00'1110, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vslidehp_w_4_vv_m   : KelvinV2ArgsType : func2 == 0b00'1111, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+
+  //vsel
+  vsel_b_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b00;
+  vsel_b_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b10;
+  vsel_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vsel_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b10;
+  vsel_h_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b00;
+  vsel_h_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b10;
+  vsel_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vsel_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b10;
+  vsel_w_vv     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b00;
+  vsel_w_vx     : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b10;
+  vsel_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vsel_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'0000, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b10;
+
+  //vevn
+  vevn_b_vv     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b00;
+  vevn_b_vx     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b10;
+  vevn_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vevn_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b10;
+  vevn_h_vv     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b00;
+  vevn_h_vx     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b10;
+  vevn_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vevn_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b10;
+  vevn_w_vv     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b00;
+  vevn_w_vx     : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b10;
+  vevn_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vevn_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'1000, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b10;
+
+  //vodd
+  vodd_b_vv     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b00;
+  vodd_b_vx     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b10;
+  vodd_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vodd_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b10;
+  vodd_h_vv     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b00;
+  vodd_h_vx     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b10;
+  vodd_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vodd_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b10;
+  vodd_w_vv     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b00;
+  vodd_w_vx     : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b10;
+  vodd_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vodd_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'1001, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b10;
+
+  //vevnodd
+  vevnodd_b_vv     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b00;
+  vevnodd_b_vx     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b10;
+  vevnodd_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vevnodd_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b10;
+  vevnodd_h_vv     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b00;
+  vevnodd_h_vx     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b10;
+  vevnodd_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vevnodd_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b10;
+  vevnodd_w_vv     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b00;
+  vevnodd_w_vx     : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b10;
+  vevnodd_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vevnodd_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'1010, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b10;
+
+  //vzip
+  vzip_b_vv     : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b00;
+  vzip_b_vx     : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b00, m == 0b00, func1 == 0b110, form == 0b10;
+  vzip_b_vv_m   : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b00;
+  vzip_b_vx_m   : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b00, m == 0b01, func1 == 0b110, form == 0b10;
+  vzip_h_vv     : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b00;
+  vzip_h_vx     : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b01, m == 0b00, func1 == 0b110, form == 0b10;
+  vzip_h_vv_m   : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b00;
+  vzip_h_vx_m   : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b01, m == 0b01, func1 == 0b110, form == 0b10;
+  vzip_w_vv     : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b00;
+  vzip_w_vx     : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b10, m == 0b00, func1 == 0b110, form == 0b10;
+  vzip_w_vv_m   : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b00;
+  vzip_w_vx_m   : KelvinV2ArgsType : func2 == 0b01'1100, sz == 0b10, m == 0b01, func1 == 0b110, form == 0b10;
+
+  //vld
+  vld_b_x       : KelvinV2ArgsType : func2 == 0b00'0000, vs2 == 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_x       : KelvinV2ArgsType : func2 == 0b00'0000, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_x       : KelvinV2ArgsType : func2 == 0b00'0000, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_p_x     : KelvinV2ArgsType : func2 == 0b00'0100, vs2 == 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_p_x     : KelvinV2ArgsType : func2 == 0b00'0100, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_p_x     : KelvinV2ArgsType : func2 == 0b00'0100, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_x_m     : KelvinV2ArgsType : func2 == 0b00'0000, vs2 == 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_x_m     : KelvinV2ArgsType : func2 == 0b00'0000, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_x_m     : KelvinV2ArgsType : func2 == 0b00'0000, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_p_x_m   : KelvinV2ArgsType : func2 == 0b00'0100, vs2 == 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_p_x_m   : KelvinV2ArgsType : func2 == 0b00'0100, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_p_x_m   : KelvinV2ArgsType : func2 == 0b00'0100, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_p_xx     : KelvinV2ArgsType : func2 == 0b00'0100, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_p_xx     : KelvinV2ArgsType : func2 == 0b00'0100, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_p_xx     : KelvinV2ArgsType : func2 == 0b00'0100, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_p_xx_m   : KelvinV2ArgsType : func2 == 0b00'0100, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_p_xx_m   : KelvinV2ArgsType : func2 == 0b00'0100, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_p_xx_m   : KelvinV2ArgsType : func2 == 0b00'0100, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_l_xx      : KelvinV2ArgsType : func2 == 0b00'0001, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_l_xx      : KelvinV2ArgsType : func2 == 0b00'0001, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_l_xx      : KelvinV2ArgsType : func2 == 0b00'0001, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_lp_xx     : KelvinV2ArgsType : func2 == 0b00'0101, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_lp_xx     : KelvinV2ArgsType : func2 == 0b00'0101, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_lp_xx     : KelvinV2ArgsType : func2 == 0b00'0101, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_l_xx_m    : KelvinV2ArgsType : func2 == 0b00'0001, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_l_xx_m    : KelvinV2ArgsType : func2 == 0b00'0001, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_l_xx_m    : KelvinV2ArgsType : func2 == 0b00'0001, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_lp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0101, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_lp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0101, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_lp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0101, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_s_xx      : KelvinV2ArgsType : func2 == 0b00'0010, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_s_xx      : KelvinV2ArgsType : func2 == 0b00'0010, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_s_xx      : KelvinV2ArgsType : func2 == 0b00'0010, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_sp_xx     : KelvinV2ArgsType : func2 == 0b00'0110, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_sp_xx     : KelvinV2ArgsType : func2 == 0b00'0110, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_sp_xx     : KelvinV2ArgsType : func2 == 0b00'0110, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_s_xx_m    : KelvinV2ArgsType : func2 == 0b00'0010, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_s_xx_m    : KelvinV2ArgsType : func2 == 0b00'0010, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_s_xx_m    : KelvinV2ArgsType : func2 == 0b00'0010, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_sp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0110, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_sp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0110, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_sp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0110, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_b_tp_xx     : KelvinV2ArgsType : func2 == 0b00'0111, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_h_tp_xx     : KelvinV2ArgsType : func2 == 0b00'0111, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_w_tp_xx     : KelvinV2ArgsType : func2 == 0b00'0111, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vld_b_tp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0111, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_h_tp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0111, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vld_w_tp_xx_m   : KelvinV2ArgsType : func2 == 0b00'0111, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+
+  // vst, note the `vs2`s below are actually xs2, and `vd` is actually the source vector register.
+  vst_b_x       : KelvinV2ArgsType : func2 == 0b00'1000, vs2 == 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_x       : KelvinV2ArgsType : func2 == 0b00'1000, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_x       : KelvinV2ArgsType : func2 == 0b00'1000, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_p_x     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_p_x     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_p_x     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_x_m     : KelvinV2ArgsType : func2 == 0b00'1000, vs2 == 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_x_m     : KelvinV2ArgsType : func2 == 0b00'1000, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_x_m     : KelvinV2ArgsType : func2 == 0b00'1000, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_p_x_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_p_x_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_p_x_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 == 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_p_xx     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_p_xx     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_p_xx     : KelvinV2ArgsType : func2 == 0b00'1100, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_p_xx_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_p_xx_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_p_xx_m   : KelvinV2ArgsType : func2 == 0b00'1100, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_l_xx      : KelvinV2ArgsType : func2 == 0b00'1001, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_l_xx      : KelvinV2ArgsType : func2 == 0b00'1001, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_l_xx      : KelvinV2ArgsType : func2 == 0b00'1001, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_lp_xx     : KelvinV2ArgsType : func2 == 0b00'1101, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_lp_xx     : KelvinV2ArgsType : func2 == 0b00'1101, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_lp_xx     : KelvinV2ArgsType : func2 == 0b00'1101, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_l_xx_m    : KelvinV2ArgsType : func2 == 0b00'1001, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_l_xx_m    : KelvinV2ArgsType : func2 == 0b00'1001, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_l_xx_m    : KelvinV2ArgsType : func2 == 0b00'1001, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_lp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1101, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_lp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1101, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_lp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1101, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_s_xx      : KelvinV2ArgsType : func2 == 0b00'1010, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_s_xx      : KelvinV2ArgsType : func2 == 0b00'1010, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_s_xx      : KelvinV2ArgsType : func2 == 0b00'1010, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_sp_xx     : KelvinV2ArgsType : func2 == 0b00'1110, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_sp_xx     : KelvinV2ArgsType : func2 == 0b00'1110, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_sp_xx     : KelvinV2ArgsType : func2 == 0b00'1110, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_s_xx_m    : KelvinV2ArgsType : func2 == 0b00'1010, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_s_xx_m    : KelvinV2ArgsType : func2 == 0b00'1010, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_s_xx_m    : KelvinV2ArgsType : func2 == 0b00'1010, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_sp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1110, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_sp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1110, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_sp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1110, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_b_tp_xx     : KelvinV2ArgsType : func2 == 0b00'1111, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_h_tp_xx     : KelvinV2ArgsType : func2 == 0b00'1111, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_w_tp_xx     : KelvinV2ArgsType : func2 == 0b00'1111, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vst_b_tp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1111, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_h_tp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1111, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vst_w_tp_xx_m   : KelvinV2ArgsType : func2 == 0b00'1111, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vstq_b_s_xx     : KelvinV2ArgsType : func2 == 0b01'1010, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vstq_h_s_xx     : KelvinV2ArgsType : func2 == 0b01'1010, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vstq_w_s_xx     : KelvinV2ArgsType : func2 == 0b01'1010, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vstq_b_sp_xx    : KelvinV2ArgsType : func2 == 0b01'1110, vs2 != 0, sz == 0b00, m == 0b00, func1 == 0b111, form == 0b11;
+  vstq_h_sp_xx    : KelvinV2ArgsType : func2 == 0b01'1110, vs2 != 0, sz == 0b01, m == 0b00, func1 == 0b111, form == 0b11;
+  vstq_w_sp_xx    : KelvinV2ArgsType : func2 == 0b01'1110, vs2 != 0, sz == 0b10, m == 0b00, func1 == 0b111, form == 0b11;
+  vstq_b_s_xx_m   : KelvinV2ArgsType : func2 == 0b01'1010, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vstq_h_s_xx_m   : KelvinV2ArgsType : func2 == 0b01'1010, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vstq_w_s_xx_m   : KelvinV2ArgsType : func2 == 0b01'1010, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+  vstq_b_sp_xx_m  : KelvinV2ArgsType : func2 == 0b01'1110, vs2 != 0, sz == 0b00, m == 0b01, func1 == 0b111, form == 0b11;
+  vstq_h_sp_xx_m  : KelvinV2ArgsType : func2 == 0b01'1110, vs2 != 0, sz == 0b01, m == 0b01, func1 == 0b111, form == 0b11;
+  vstq_w_sp_xx_m  : KelvinV2ArgsType : func2 == 0b01'1110, vs2 != 0, sz == 0b10, m == 0b01, func1 == 0b111, form == 0b11;
+};
diff --git a/sim/kelvin.isa b/sim/kelvin.isa
new file mode 100644
index 0000000..764d413
--- /dev/null
+++ b/sim/kelvin.isa
@@ -0,0 +1,3721 @@
+// This file define the kelvin isa for mpact-sim. For more info on mpact-sim isa
+// format, check: go/mpact-sim-codelabs-riscv-instruction-decoder
+
+// First disasm field is 18 char wide and left justified.
+disasm widths = {-18};
+
+int global_latency = 0;
+
+isa Kelvin {
+  namespace kelvin::sim::isa32;
+  slots { kelvin; }
+}
+
+// Basic integer ALU instructions, part of the RiscV 32i subset.
+slot riscv32i {
+  includes {
+    #include "riscv/riscv_i_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  resources TwoOp = { next_pc, rs1 : rd[..rd]};
+  resources ThreeOp = { next_pc, rs1, rs2 : rd[..rd]};
+  opcodes {
+    addi{: rs1, I_imm12 : rd},
+      resources: TwoOp,
+      disasm: "addi", "%rd, %rs1, %I_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIAdd";
+    slti{: rs1, I_imm12 : rd},
+      resources: TwoOp,
+      disasm: "slti", "%rd, %rs1, %I_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISlt";
+    sltiu{: rs1, I_imm12 : rd},
+      resources: TwoOp,
+      disasm: "sltiu", "%rd, %rs1, %I_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISltu";
+    andi{: rs1, I_imm12 : rd},
+      resources: TwoOp,
+      disasm: "andi", "%rd, %rs1, %I_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIAnd";
+    ori{: rs1, I_imm12 : rd},
+      resources: TwoOp,
+      disasm: "ori", "%rd, %rs1, %I_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIOr";
+    xori{: rs1, I_imm12 : rd},
+      resources: TwoOp,
+      disasm: "xori", "%rd, %rs1, %I_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIXor";
+    slli{: rs1, I_uimm5 : rd},
+      resources: TwoOp,
+      disasm: "slli", "%rd, %rs1, 0x%(I_uimm5:x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISll";
+    srli{: rs1, I_uimm5 : rd},
+      resources: TwoOp,
+      disasm: "srli", "%rd  %rs1, 0x%(I_uimm5:x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISrl";
+    srai{: rs1, I_uimm5 : rd},
+      resources: TwoOp,
+      disasm: "srai", "%rd, %rs1, 0x%(I_uimm5:x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISra";
+    lui{: U_imm20 : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "lui", "%rd, 0x%(U_imm20:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVILui";
+    auipc{: U_imm20 : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "auipc", "%rd, 0x%(U_imm20:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIAuipc";
+    add{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "add", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIAdd";
+    slt{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "slt", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISlt";
+    sltu{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "sltu", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISltu";
+    and{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "and", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIAnd";
+    or{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "or", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIOr";
+    xor{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "xor", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIXor";
+    sll{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "sll", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISll";
+    srl{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "srl", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISrl";
+    sub{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "sub", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISub";
+    sra{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "sra", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISra";
+    nop{},
+      disasm: "nop",
+      semfunc: "&mpact::sim::riscv::RiscVINop";
+    hint{},
+      disasm: "hint",
+      semfunc: "&mpact::sim::riscv::RiscVINop";
+    jal{: J_imm20 : next_pc, rd},
+      resources: { next_pc : next_pc[0..], rd[0..]},
+      disasm: "jal", "%rd, %(@+J_imm20:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIJal";
+    jalr{: rs1, J_imm12 : next_pc, rd},
+      resources: { next_pc, rs1 : next_pc[0..], rd[0..]},
+      disasm: "jalr", "%rd, %rs1, %J_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIJalr";
+    j{: J_imm20 : next_pc, rd},
+      resources: { next_pc : next_pc[0..], rd[0..]},
+      disasm: "j", "%(@+J_imm20:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIJal";
+    jr{: rs1, J_imm12 : next_pc, rd},
+      resources: { next_pc, rs1 : next_pc[0..], rd[0..]},
+      disasm: "jr", "%rs1, %J_imm12",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIJalr";
+    beq{: rs1, rs2, B_imm12 : next_pc},
+      resources: { next_pc, rs1, rs2 : next_pc[0..]},
+      disasm: "beq", "%rs1, %rs2, %(@+B_imm12:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIBeq";
+    bne{: rs1, rs2, B_imm12 : next_pc},
+      resources: { next_pc, rs1, rs2 : next_pc[0..]},
+      disasm: "bne", "%rs1, %rs2, %(@+B_imm12:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIBne";
+    blt{: rs1, rs2, B_imm12 : next_pc},
+      resources: { next_pc, rs1, rs2 : next_pc[0..]},
+      disasm: "blt", "%rs1, %rs2, %(@+B_imm12:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIBlt";
+    bltu{: rs1, rs2, B_imm12 : next_pc},
+      resources: { next_pc, rs1, rs2 : next_pc[0..]},
+      disasm: "bltu", "%rs1, %rs2, %(@+B_imm12:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIBltu";
+    bge{: rs1, rs2, B_imm12 : next_pc},
+      resources: { next_pc, rs1, rs2 : next_pc[0..]},
+      disasm: "bge", "%rs1, %rs2, %(@+B_imm12:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIBge";
+    bgeu{: rs1, rs2, B_imm12 : next_pc},
+      resources: { next_pc, rs1, rs2 : next_pc[0..]},
+      disasm: "bgeu", "%rs1, %rs2, %(@+B_imm12:08x)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVIBgeu";
+    lw{(: rs1, I_imm12), (: : rd)},
+      resources: { next_pc, rs1 : rd[0..]},
+      disasm: "lw", "%rd, %I_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVILw", "&mpact::sim::riscv::RV32::RiscVILwChild";
+    lh{(: rs1, I_imm12 :), (: : rd)},
+      resources: { next_pc, rs1 : rd[0..]},
+      disasm: "lh", "%rd, %I_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVILh", "&mpact::sim::riscv::RV32::RiscVILhChild";
+    lhu{(: rs1, I_imm12 :), (: : rd)},
+      resources: { next_pc, rs1 : rd[0..]},
+      disasm: "lhu", "%rd, %I_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVILhu", "&mpact::sim::riscv::RV32::RiscVILhuChild";
+    lb{(: rs1, I_imm12 :), (: : rd)},
+      resources: { next_pc, rs1 : rd[0..]},
+      disasm: "lb", "%rd, %I_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVILb", "&mpact::sim::riscv::RV32::RiscVILbChild";
+    lbu{(: rs1, I_imm12 :), (: : rd)},
+      resources: { next_pc, rs1 : rd[0..]},
+      disasm: "lbu", "%rd, %I_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVILbu", "&mpact::sim::riscv::RV32::RiscVILbuChild";
+    sw{: rs1, S_imm12, rs2 : },
+      resources: { next_pc, rs1, rs2 : },
+      disasm: "sw", "%rs2, %S_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISw";
+    sh{: rs1, S_imm12, rs2 : },
+      resources: { next_pc, rs1, rs2 : },
+      disasm: "sh", "%rs2, %S_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISh";
+    sb{: rs1, S_imm12, rs2 : },
+      resources: { next_pc, rs1, rs2 : },
+      disasm: "sb", "%rs2, %S_imm12(%rs1)",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVISb";
+    fence{: I_imm12 : },
+      disasm: "fence",
+      semfunc: "&mpact::sim::riscv::RiscVIFence";
+    ecall{},
+      disasm: "ecall",
+      semfunc: "&mpact::sim::riscv::RiscVIEcall";
+    ebreak{},
+      disasm: "ebreak",
+      semfunc: "&mpact::sim::riscv::RiscVIEbreak";
+  }
+}
+
+// RiscV32 multiply/divide instructions.
+slot riscv32m {
+  includes {
+    #include "riscv/riscv_m_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  resources ThreeOp = { next_pc, rs1, rs2 : rd[..rd]};
+  opcodes {
+    mul{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "mul", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MMul";
+    mulh{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "mulh", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MMulh";
+    mulhu{: rs1, rs2: rd},
+      resources: ThreeOp,
+      disasm: "mulhu", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MMulhu";
+    mulhsu{: rs1, rs2: rd},
+      resources: ThreeOp,
+      disasm: "mulhsu", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MMulhsu";
+    div{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "div", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MDiv";
+    divu{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "divu", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MDivu";
+    rem{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "rem", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MRem";
+    remu{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "remu", "%rd, %rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RV32::MRemu";
+  }
+}
+
+// RiscV32 CSR manipulation instructions.
+slot zicsr {
+  includes {
+    #include "riscv/riscv_zicsr_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  opcodes {
+    csrrw{: rs1, csr : rd, csr},
+      resources: { next_pc, rs1, csr : rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrw",
+      disasm: "csrw", "%rd, %csr, %rs1";
+    csrrs{: rs1, csr : rd, csr},
+      resources: { next_pc, rs1, csr : rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrs",
+      disasm: "csrs", "%rd, %csr, %rs1";
+    csrrc{: rs1, csr : rd, csr},
+      resources: { next_pc, rs1, csr : rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrc",
+      disasm: "csrc", "%rd, %csr, %rs1";
+    csrrs_nr{: rs1, csr : rd, csr},
+      resources: { next_pc, rs1, csr : rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrs",
+      disasm: "csrs", "%csr, %rs1";
+    csrrc_nr{: rs1, csr : rd, csr},
+      resources: { next_pc, rs1, csr : rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrc",
+      disasm: "csrc", "%csr, %rs1";
+    csrrw_nr{: rs1, csr : csr},
+      resources: { next_pc, rs1: csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrwNr", // rd == 0 (x0).
+      disasm: "csrw", "%csr, %rs1";
+    csrrs_nw{: csr : rd},
+      resources: { next_pc, csr: rd[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrNw", // rs1 == 0 (x0).
+      disasm: "csrs", "%rd, %csr";
+    csrrc_nw{: csr : rd},
+      resources: { next_pc, csr: rd[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrNw", // rs1 == 0 (x0).
+      disasm: "csrc", "%rd, %csr";
+    csrrwi{: CSR_uimm5, csr : rd, csr},
+      resources: { next_pc, csr: rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrw",
+      disasm: "csrwi", "%rd, %csr, %CSR_uimm5";
+    csrrsi{: CSR_uimm5, csr : rd, csr},
+      resources: { next_pc, csr: rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrs",
+      disasm: "csrsi", "%rd, %csr, %CSR_uimm5";
+    csrrci{: CSR_uimm5, csr : rd, csr},
+      resources: { next_pc, csr: rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrc",
+      disasm: "csrci", "%rd, %csr, %CSR_uimm5";
+    csrrsi_nr{: CSR_uimm5, csr : rd, csr},
+      resources: { next_pc, csr: rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrs",
+      disasm: "csrsi", "%csr, %CSR_uimm5";
+    csrrci_nr{: CSR_uimm5, csr : rd, csr},
+      resources: { next_pc, csr: rd[0..], csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrc",
+      disasm: "csrci", "%csr, %CSR_uimm5";
+    csrrwi_nr{: CSR_uimm5, csr : csr},
+      resources: { next_pc : csr[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrwNr",  // rd == 0 (x0).
+      disasm: "csrrwi", "%csr, %CSR_uimm5";
+    csrrsi_nw{: csr : rd},
+      resources: { next_pc, csr : rd[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrNw", // uimm5 == 0.
+      disasm: "csrsi", "%rd, %csr, 0";
+    csrrci_nw{: csr : rd},
+      resources: { next_pc, csr : rd[0..]},
+      semfunc: "&mpact::sim::riscv::RV32::RiscVZiCsrrNw", // uimm5 == 0.
+      disasm: "csrwi", "%rd, %csr, 0";
+  }
+}
+
+// Instruction fence.
+slot zfencei {
+  includes {
+    #include "riscv/riscv_zfencei_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  opcodes {
+    fencei{: I_imm12 : },
+      disasm: "fence.i",
+      semfunc: "&mpact::sim::riscv::RiscVZFencei";
+  }
+}
+
+// Privileged instructions.
+slot privileged {
+  includes {
+    #include "riscv/riscv_priv_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  opcodes {
+    uret{: : next_pc},
+      disasm: "uret",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVPrivURet";
+    sret{: : next_pc},
+      disasm: "sret",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVPrivSRet";
+    mret{: : next_pc},
+      disasm: "mret",
+      semfunc: "&mpact::sim::riscv::RV32::RiscVPrivMRet";
+    wfi{},
+      disasm: "wfi",
+      semfunc: "&mpact::sim::riscv::RiscVPrivWfi";
+    mpause{},
+      disasm: "mpause",
+      // mpause is the software breakpoint to terminate the program.
+      semfunc: "&KelvinIMpause";
+    // The sfence instruction has 4 behaviors depending on if rs1 and/or rs2
+    // are 0. These behaviors are split into 4 instructions.
+    sfence_vma_zz{: rs1, rs2},
+      resources: {},
+      disasm: "sfence.vma", "%rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RiscVPrivSFenceVmaZZ";
+    sfence_vma_zn{: rs1, rs2},
+      resources: {rs2},
+      disasm: "sfence.vma", "%rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RiscVPrivSFenceVmaZN";
+    sfence_vma_nz{: rs1, rs2},
+      resources: { rs1 },
+      disasm: "sfence.vma", "%rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RiscVPrivSFenceVmaNZ";
+    sfence_vma_nn{: rs1, rs2},
+      resources: {rs1, rs2},
+      disasm: "sfence.vma", "%rs1, %rs2",
+      semfunc: "&mpact::sim::riscv::RiscVPrivSFenceVmaNN";
+    // Skipping hypervisor memory management instructions for now.
+  }
+}
+
+// Kelvin simd instructions:
+// https://spacebeaker.googlesource.com/shodan/experimental-kelvin/+/refs/heads/master/docs/arch/isa.md
+slot kelvin_arith {
+  includes {
+    #include "sim/kelvin_instructions.h"
+    #include "sim/kelvin_vector_instructions.h"
+    #include "sim/kelvin_vector_memory_instructions.h"
+    #include "absl/functional/bind_front.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  opcodes {
+    // vadd
+    vadd_b_vv{: vs1, vs2 : vd},
+    disasm: "vadd.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadd_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vadd.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadd_h_vv{: vs1, vs2 : vd},
+    disasm: "vadd.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadd_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vadd.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadd_w_vv{: vs1, vs2 : vd},
+    disasm: "vadd.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadd_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vadd.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadd_b_vx{: vs1, vs2 : vd},
+    disasm: "vadd.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadd_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vadd.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadd_h_vx{: vs1, vs2 : vd},
+    disasm: "vadd.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadd_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vadd.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadd_w_vx{: vs1, vs2 : vd},
+    disasm: "vadd.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadd_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vadd.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vsub
+    vsub_b_vv{: vs1, vs2 : vd},
+    disasm: "vsub.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsub_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vsub.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsub_h_vv{: vs1, vs2 : vd},
+    disasm: "vsub.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsub_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vsub.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsub_w_vv{: vs1, vs2 : vd},
+    disasm: "vsub.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsub_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vsub.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsub_b_vx{: vs1, vs2 : vd},
+    disasm: "vsub.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsub_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vsub.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsub_h_vx{: vs1, vs2 : vd},
+    disasm: "vsub.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsub_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vsub.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsub_w_vx{: vs1, vs2 : vd},
+    disasm: "vsub.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsub_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vsub.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSub<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vrsub
+    vrsub_b_vv{: vs1, vs2 : vd},
+    disasm: "vrsub.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vrsub_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vrsub.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vrsub_h_vv{: vs1, vs2 : vd},
+    disasm: "vrsub.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vrsub_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vrsub.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vrsub_w_vv{: vs1, vs2 : vd},
+    disasm: "vrsub.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vrsub_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vrsub.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vrsub_b_vx{: vs1, vs2 : vd},
+    disasm: "vrsub.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vrsub_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vrsub.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vrsub_h_vx{: vs1, vs2 : vd},
+    disasm: "vrsub.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vrsub_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vrsub.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vrsub_w_vx{: vs1, vs2 : vd},
+    disasm: "vrsub.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vrsub_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vrsub.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVRSub<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // veq
+    veq_b_vv{: vs1, vs2 : vd},
+    disasm: "veq.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    veq_b_vv_m{: vs1, vs2 : vd},
+    disasm: "veq.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    veq_h_vv{: vs1, vs2 : vd},
+    disasm: "veq.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    veq_h_vv_m{: vs1, vs2 : vd},
+    disasm: "veq.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    veq_w_vv{: vs1, vs2 : vd},
+    disasm: "veq.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    veq_w_vv_m{: vs1, vs2 : vd},
+    disasm: "veq.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    veq_b_vx{: vs1, vs2 : vd},
+    disasm: "veq.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    veq_b_vx_m{: vs1, vs2 : vd},
+    disasm: "veq.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    veq_h_vx{: vs1, vs2 : vd},
+    disasm: "veq.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    veq_h_vx_m{: vs1, vs2 : vd},
+    disasm: "veq.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    veq_w_vx{: vs1, vs2 : vd},
+    disasm: "veq.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    veq_w_vx_m{: vs1, vs2 : vd},
+    disasm: "veq.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVEq<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vne
+    vne_b_vv{: vs1, vs2 : vd},
+    disasm: "vne.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vne_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vne.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vne_h_vv{: vs1, vs2 : vd},
+    disasm: "vne.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vne_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vne.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vne_w_vv{: vs1, vs2 : vd},
+    disasm: "vne.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vne_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vne.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vne_b_vx{: vs1, vs2 : vd},
+    disasm: "vne.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vne_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vne.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vne_h_vx{: vs1, vs2 : vd},
+    disasm: "vne.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vne_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vne.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vne_w_vx{: vs1, vs2 : vd},
+    disasm: "vne.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vne_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vne.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVNe<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vlt
+    vlt_b_vv{: vs1, vs2 : vd},
+    disasm: "vlt.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vlt_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vlt.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vlt_h_vv{: vs1, vs2 : vd},
+    disasm: "vlt.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vlt_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vlt.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vlt_w_vv{: vs1, vs2 : vd},
+    disasm: "vlt.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vlt_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vlt.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vlt_b_vx{: vs1, vs2 : vd},
+    disasm: "vlt.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vlt_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vlt.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vlt_h_vx{: vs1, vs2 : vd},
+    disasm: "vlt.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vlt_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vlt.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vlt_w_vx{: vs1, vs2 : vd},
+    disasm: "vlt.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vlt_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vlt.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vltu
+    vlt_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vlt.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vlt_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vlt.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vlt_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vlt.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vlt_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vlt.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vlt_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vlt.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vlt_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vlt.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vlt_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vlt.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vlt_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vlt.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vlt_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vlt.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vlt_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vlt.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vlt_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vlt.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vlt_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vlt.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVLt<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vle
+    vle_b_vv{: vs1, vs2 : vd},
+    disasm: "vle.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vle_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vle.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vle_h_vv{: vs1, vs2 : vd},
+    disasm: "vle.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vle_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vle.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vle_w_vv{: vs1, vs2 : vd},
+    disasm: "vle.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vle_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vle.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vle_b_vx{: vs1, vs2 : vd},
+    disasm: "vle.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vle_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vle.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vle_h_vx{: vs1, vs2 : vd},
+    disasm: "vle.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vle_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vle.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vle_w_vx{: vs1, vs2 : vd},
+    disasm: "vle.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vle_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vle.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vleu
+    vle_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vle.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vle_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vle.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vle_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vle.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vle_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vle.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vle_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vle.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vle_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vle.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vle_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vle.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vle_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vle.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vle_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vle.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vle_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vle.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vle_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vle.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vle_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vle.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVLe<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vgt
+    vgt_b_vv{: vs1, vs2 : vd},
+    disasm: "vgt.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vgt_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vgt.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vgt_h_vv{: vs1, vs2 : vd},
+    disasm: "vgt.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vgt_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vgt.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vgt_w_vv{: vs1, vs2 : vd},
+    disasm: "vgt.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vgt_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vgt.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vgt_b_vx{: vs1, vs2 : vd},
+    disasm: "vgt.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vgt_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vgt.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vgt_h_vx{: vs1, vs2 : vd},
+    disasm: "vgt.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vgt_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vgt.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vgt_w_vx{: vs1, vs2 : vd},
+    disasm: "vgt.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vgt_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vgt.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vgtu
+    vgt_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vgt.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vgt_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vgt.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vgt_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vgt.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vgt_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vgt.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vgt_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vgt.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vgt_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vgt.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vgt_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vgt.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vgt_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vgt.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vgt_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vgt.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vgt_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vgt.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vgt_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vgt.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vgt_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vgt.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVGt<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vge
+    vge_b_vv{: vs1, vs2 : vd},
+    disasm: "vge.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vge_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vge.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vge_h_vv{: vs1, vs2 : vd},
+    disasm: "vge.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vge_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vge.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vge_w_vv{: vs1, vs2 : vd},
+    disasm: "vge.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vge_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vge.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vge_b_vx{: vs1, vs2 : vd},
+    disasm: "vge.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vge_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vge.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vge_h_vx{: vs1, vs2 : vd},
+    disasm: "vge.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vge_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vge.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vge_w_vx{: vs1, vs2 : vd},
+    disasm: "vge.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vge_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vge.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vgeu
+    vge_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vge.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vge_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vge.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vge_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vge.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vge_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vge.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vge_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vge.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vge_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vge.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vge_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vge.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vge_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vge.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vge_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vge.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vge_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vge.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vge_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vge.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vge_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vge.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVGe<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vabsd
+    vabsd_b_vv{: vs1, vs2 : vd},
+    disasm: "vabsd.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vabsd_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vabsd.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vabsd_h_vv{: vs1, vs2 : vd},
+    disasm: "vabsd.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vabsd_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vabsd.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vabsd_w_vv{: vs1, vs2 : vd},
+    disasm: "vabsd.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vabsd_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vabsd.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vabsd_b_vx{: vs1, vs2 : vd},
+    disasm: "vabsd.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vabsd_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vabsd.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vabsd_h_vx{: vs1, vs2 : vd},
+    disasm: "vabsd.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vabsd_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vabsd.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vabsd_w_vx{: vs1, vs2 : vd},
+    disasm: "vabsd.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vabsd_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vabsd.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vabsdu
+    vabsd_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vabsd.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vabsd_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vabsd.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vabsd_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vabsd.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vabsd_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vabsd.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vabsd_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vabsd.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vabsd_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vabsd.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vabsd_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vabsd.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vabsd_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vabsd.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vabsd_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vabsd.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vabsd_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vabsd.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vabsd_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vabsd.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vabsd_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vabsd.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVAbsd<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vmax
+    vmax_b_vv{: vs1, vs2 : vd},
+    disasm: "vmax.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmax_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vmax.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmax_h_vv{: vs1, vs2 : vd},
+    disasm: "vmax.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmax_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vmax.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmax_w_vv{: vs1, vs2 : vd},
+    disasm: "vmax.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmax_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vmax.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmax_b_vx{: vs1, vs2 : vd},
+    disasm: "vmax.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmax_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vmax.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmax_h_vx{: vs1, vs2 : vd},
+    disasm: "vmax.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmax_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vmax.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmax_w_vx{: vs1, vs2 : vd},
+    disasm: "vmax.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmax_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vmax.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vmaxu
+    vmax_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vmax.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmax_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vmax.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmax_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vmax.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmax_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vmax.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmax_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vmax.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmax_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vmax.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmax_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vmax.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmax_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vmax.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmax_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vmax.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmax_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vmax.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmax_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vmax.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmax_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vmax.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVMax<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vmin
+    vmin_b_vv{: vs1, vs2 : vd},
+    disasm: "vmin.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmin_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vmin.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmin_h_vv{: vs1, vs2 : vd},
+    disasm: "vmin.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmin_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vmin.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmin_w_vv{: vs1, vs2 : vd},
+    disasm: "vmin.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmin_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vmin.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmin_b_vx{: vs1, vs2 : vd},
+    disasm: "vmin.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmin_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vmin.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmin_h_vx{: vs1, vs2 : vd},
+    disasm: "vmin.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmin_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vmin.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmin_w_vx{: vs1, vs2 : vd},
+    disasm: "vmin.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmin_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vmin.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vminu
+    vmin_u_b_vv{: vs1, vs2 : vd},
+    disasm: "vmin.b.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmin_u_b_vv_m{: vs1, vs2 : vd},
+    disasm: "vmin.b.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmin_u_h_vv{: vs1, vs2 : vd},
+    disasm: "vmin.h.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmin_u_h_vv_m{: vs1, vs2 : vd},
+    disasm: "vmin.h.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmin_u_w_vv{: vs1, vs2 : vd},
+    disasm: "vmin.w.u.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmin_u_w_vv_m{: vs1, vs2 : vd},
+    disasm: "vmin.w.u.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmin_u_b_vx{: vs1, vs2 : vd},
+    disasm: "vmin.b.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmin_u_b_vx_m{: vs1, vs2 : vd},
+    disasm: "vmin.b.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmin_u_h_vx{: vs1, vs2 : vd},
+    disasm: "vmin.h.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmin_u_h_vx_m{: vs1, vs2 : vd},
+    disasm: "vmin.h.u.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmin_u_w_vx{: vs1, vs2 : vd},
+    disasm: "vmin.w.u.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmin_u_w_vx_m{: vs1, vs2 : vd},
+    disasm: "vmin.w.u.vx.m", "%vd, %vs1,V %vs2",
+    semfunc: "absl::bind_front(&KelvinVMin<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    // vadd3
+    vadd3_b_vv{: vs1, vs2, vd : vd},
+    disasm: "vadd3.b.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadd3_b_vv_m{: vs1, vs2, vd : vd},
+    disasm: "vadd3.b.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadd3_h_vv{: vs1, vs2, vd : vd},
+    disasm: "vadd3.h.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadd3_h_vv_m{: vs1, vs2, vd : vd},
+    disasm: "vadd3.h.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadd3_w_vv{: vs1, vs2, vd : vd},
+    disasm: "vadd3.w.vv", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadd3_w_vv_m{: vs1, vs2, vd : vd},
+    disasm: "vadd3.w.vv.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadd3_b_vx{: vs1, vs2, vd : vd},
+    disasm: "vadd3.b.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadd3_b_vx_m{: vs1, vs2, vd : vd},
+    disasm: "vadd3.b.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadd3_h_vx{: vs1, vs2, vd : vd},
+    disasm: "vadd3.h.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadd3_h_vx_m{: vs1, vs2, vd : vd},
+    disasm: "vadd3.h.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadd3_w_vx{: vs1, vs2, vd : vd},
+    disasm: "vadd3.w.vx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadd3_w_vx_m{: vs1, vs2, vd : vd},
+    disasm: "vadd3.w.vx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVAdd3<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vadds
+    vadds_b_vv{: vs1, vs2 : vd},
+      disasm: "vadds.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadds_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vadds.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadds_h_vv{: vs1, vs2 : vd},
+      disasm: "vadds.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadds_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vadds.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadds_w_vv{: vs1, vs2 : vd},
+      disasm: "vadds.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadds_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vadds.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadds_b_vx{: vs1, vs2 : vd},
+      disasm: "vadds.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadds_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vadds.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadds_h_vx{: vs1, vs2 : vd},
+      disasm: "vadds.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadds_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vadds.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadds_w_vx{: vs1, vs2 : vd},
+      disasm: "vadds.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadds_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vadds.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAdds<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vaddsu
+    vadds_u_b_vv{: vs1, vs2 : vd},
+      disasm: "vadds.b.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadds_u_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vadds.b.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadds_u_h_vv{: vs1, vs2 : vd},
+      disasm: "vadds.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadds_u_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vadds.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadds_u_w_vv{: vs1, vs2 : vd},
+      disasm: "vadds.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vadds_u_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vadds.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vadds_u_b_vx{: vs1, vs2 : vd},
+      disasm: "vadds.b.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadds_u_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vadds.b.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadds_u_h_vx{: vs1, vs2 : vd},
+      disasm: "vadds.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadds_u_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vadds.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vadds_u_w_vx{: vs1, vs2 : vd},
+      disasm: "vadds.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vadds_u_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vadds.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddsu<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsubs
+    vsubs_b_vv{: vs1, vs2 : vd},
+      disasm: "vsubs.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubs_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubs.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubs_h_vv{: vs1, vs2 : vd},
+      disasm: "vsubs.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubs_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubs.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubs_w_vv{: vs1, vs2 : vd},
+      disasm: "vsubs.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubs_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubs.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubs_b_vx{: vs1, vs2 : vd},
+      disasm: "vsubs.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubs_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubs.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsubs_h_vx{: vs1, vs2 : vd},
+      disasm: "vsubs.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubs_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubs.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsubs_w_vx{: vs1, vs2 : vd},
+      disasm: "vsubs.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubs_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubs.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubs<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsubsu
+    vsubs_u_b_vv{: vs1, vs2 : vd},
+      disasm: "vsubs.b.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubs_u_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubs.b.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubs_u_h_vv{: vs1, vs2 : vd},
+      disasm: "vsubs.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubs_u_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubs.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubs_u_w_vv{: vs1, vs2 : vd},
+      disasm: "vsubs.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubs_u_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubs.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubs_u_b_vx{: vs1, vs2 : vd},
+      disasm: "vsubs.b.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubs_u_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubs.b.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsubs_u_h_vx{: vs1, vs2 : vd},
+      disasm: "vsubs.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubs_u_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubs.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsubs_u_w_vx{: vs1, vs2 : vd},
+      disasm: "vsubs.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubs_u_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubs.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubsu<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vaddw
+    vaddw_h_vv{: vs1, vs2 : vd},
+      disasm: "vaddw.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vaddw_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vaddw.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vaddw_w_vv{: vs1, vs2 : vd},
+      disasm: "vaddw.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vaddw_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vaddw.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vaddw_h_vx{: vs1, vs2 : vd},
+      disasm: "vaddw.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vaddw_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vaddw.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vaddw_w_vx{: vs1, vs2 : vd},
+      disasm: "vaddw.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vaddw_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vaddw.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vaddwu
+    vaddw_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vaddw.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vaddw_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vaddw.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vaddw_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vaddw.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vaddw_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vaddw.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vaddw_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vaddw.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vaddw_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vaddw.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vaddw_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vaddw.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vaddw_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vaddw.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAddw<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsubw
+    vsubw_h_vv{: vs1, vs2 : vd},
+      disasm: "vsubw.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubw_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubw.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubw_w_vv{: vs1, vs2 : vd},
+      disasm: "vsubw.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubw_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubw.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubw_h_vx{: vs1, vs2 : vd},
+      disasm: "vsubw.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubw_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubw.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsubw_w_vx{: vs1, vs2 : vd},
+      disasm: "vsubw.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubw_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubw.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsubwu
+    vsubw_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vsubw.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubw_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubw.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubw_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vsubw.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsubw_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vsubw.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsubw_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vsubw.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubw_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubw.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsubw_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vsubw.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsubw_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vsubw.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSubw<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+   //vacc
+    vacc_h_vv{: vs1, vs2 : vd},
+      disasm: "vacc.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vacc_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vacc.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vacc_w_vv{: vs1, vs2 : vd},
+      disasm: "vacc.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vacc_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vacc.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vacc_h_vx{: vs1, vs2 : vd},
+      disasm: "vacc.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vacc_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vacc.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vacc_w_vx{: vs1, vs2 : vd},
+      disasm: "vacc.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vacc_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vacc.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vaccu
+    vacc_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vacc.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vacc_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vacc.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vacc_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vacc.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vacc_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vacc.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vacc_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vacc.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vacc_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vacc.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vacc_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vacc.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vacc_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vacc.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAcc<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+   //vpadd
+    vpadd_h_v{: vs1 : vd},
+      disasm: "vpadd.h.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int16_t, int8_t>, /*strip_mine*/ false)";
+    vpadd_h_v_m{: vs1 : vd},
+      disasm: "vpadd.h.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int16_t, int8_t>, /*strip_mine*/ true)";
+    vpadd_w_v{: vs1 : vd},
+      disasm: "vpadd.w.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int32_t, int16_t>, /*strip_mine*/ false)";
+    vpadd_w_v_m{: vs1 : vd},
+      disasm: "vpadd.w.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int32_t, int16_t>, /*strip_mine*/ true)";
+
+   //vpaddu
+    vpadd_h_u_v{: vs1 : vd},
+      disasm: "vpadd.h.u.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int16_t, int8_t>, /*strip_mine*/ false)";
+    vpadd_h_u_v_m{: vs1 : vd},
+      disasm: "vpadd.h.u.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int16_t, int8_t>, /*strip_mine*/ true)";
+    vpadd_w_u_v{: vs1 : vd},
+      disasm: "vpadd.w.u.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int32_t, int16_t>, /*strip_mine*/ false)";
+    vpadd_w_u_v_m{: vs1 : vd},
+      disasm: "vpadd.w.u.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPadd<int32_t, int16_t>, /*strip_mine*/ true)";
+
+   //vpsub
+    vpsub_h_v{: vs1 : vd},
+      disasm: "vpsub.h.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int16_t, int8_t>, /*strip_mine*/ false)";
+    vpsub_h_v_m{: vs1 : vd},
+      disasm: "vpsub.h.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int16_t, int8_t>, /*strip_mine*/ true)";
+    vpsub_w_v{: vs1 : vd},
+      disasm: "vpsub.w.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int32_t, int16_t>, /*strip_mine*/ false)";
+    vpsub_w_v_m{: vs1 : vd},
+      disasm: "vpsub.w.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int32_t, int16_t>, /*strip_mine*/ true)";
+
+    //vpsubu
+    vpsub_h_u_v{: vs1 : vd},
+      disasm: "vpsub.h.u.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int16_t, int8_t>, /*strip_mine*/ false)";
+    vpsub_h_u_v_m{: vs1 : vd},
+      disasm: "vpsub.h.u.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int16_t, int8_t>, /*strip_mine*/ true)";
+    vpsub_w_u_v{: vs1 : vd},
+      disasm: "vpsub.w.u.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int32_t, int16_t>, /*strip_mine*/ false)";
+    vpsub_w_u_v_m{: vs1 : vd},
+      disasm: "vpsub.w.u.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVPsub<int32_t, int16_t>, /*strip_mine*/ true)";
+
+    //vhadd
+    vhadd_b_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhadd_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhadd_h_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhadd_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhadd_w_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhadd_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhadd_b_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhadd_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhadd_h_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhadd_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhadd_w_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhadd_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+
+    //vhadd.r
+    vhadd_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhadd_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhadd_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhadd_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhadd_w_r_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.w.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhadd_w_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhadd_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhadd_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhadd_h_r_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.h.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhadd_h_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhadd_w_r_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.w.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhadd_w_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+
+    //vhadd.u
+    vhadd_b_u_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.b.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhadd_b_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhadd_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhadd_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhadd_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhadd_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhadd_b_u_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.b.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhadd_b_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhadd_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhadd_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhadd_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhadd_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+
+    //vhadd.ru
+    vhadd_b_ur_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.b.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhadd_b_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhadd_h_ur_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.h.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhadd_h_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhadd_w_ur_vv{: vs1, vs2 : vd},
+      disasm: "vhadd.w.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhadd_w_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhadd_b_ur_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.b.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhadd_b_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.b.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhadd_h_ur_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.h.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhadd_h_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.h.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhadd_w_ur_vx{: vs1, vs2 : vd},
+      disasm: "vhadd.w.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhadd_w_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vhadd.w.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHadd<uint32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+
+    //vhsub
+    vhsub_b_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhsub_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhsub_h_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhsub_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhsub_w_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhsub_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhsub_b_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhsub_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhsub_h_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhsub_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhsub_w_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhsub_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+
+    //vhsub.r
+    vhsub_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhsub_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhsub_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhsub_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhsub_w_r_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.w.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhsub_w_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhsub_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhsub_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhsub_h_r_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.h.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhsub_h_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhsub_w_r_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.w.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhsub_w_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+
+    //vhsub.u
+    vhsub_b_u_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.b.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhsub_b_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhsub_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhsub_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhsub_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vhsub_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vhsub_b_u_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.b.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhsub_b_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhsub_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhsub_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vhsub_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vhsub_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+
+    //vhsub.ru
+    vhsub_b_ur_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.b.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhsub_b_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhsub_h_ur_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.h.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhsub_h_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhsub_w_ur_vv{: vs1, vs2 : vd},
+      disasm: "vhsub.w.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vhsub_w_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vhsub_b_ur_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.b.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhsub_b_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.b.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhsub_h_ur_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.h.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhsub_h_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.h.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vhsub_w_ur_vx{: vs1, vs2 : vd},
+      disasm: "vhsub.w.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vhsub_w_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vhsub.w.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVHsub<uint32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+
+    //vand
+    vand_vv{: vs1, vs2 : vd},
+      disasm: "vand.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vand_vv_m{: vs1, vs2 : vd},
+      disasm: "vand.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vand_b_vx{: vs1, vs2 : vd},
+      disasm: "vand.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vand_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vand.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vand_h_vx{: vs1, vs2 : vd},
+      disasm: "vand.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vand_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vand.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vand_w_vx{: vs1, vs2 : vd},
+      disasm: "vand.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vand_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vand.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVAnd<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vor
+    vor_vv{: vs1, vs2 : vd},
+      disasm: "vor.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vor_vv_m{: vs1, vs2 : vd},
+      disasm: "vor.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vor_b_vx{: vs1, vs2 : vd},
+      disasm: "vor.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vor_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vor.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vor_h_vx{: vs1, vs2 : vd},
+      disasm: "vor.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vor_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vor.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vor_w_vx{: vs1, vs2 : vd},
+      disasm: "vor.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vor_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vor.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOr<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vxor
+    vxor_vv{: vs1, vs2 : vd},
+      disasm: "vxor.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vxor_vv_m{: vs1, vs2 : vd},
+      disasm: "vxor.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vxor_b_vx{: vs1, vs2 : vd},
+      disasm: "vxor.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vxor_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vxor.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vxor_h_vx{: vs1, vs2 : vd},
+      disasm: "vxor.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vxor_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vxor.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vxor_w_vx{: vs1, vs2 : vd},
+      disasm: "vxor.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vxor_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vxor.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVXor<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vrev
+    vrev_b_vx{: vs1, vs2 : vd},
+      disasm: "vrev.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRev<uint8_t>, /*strip_mine*/ false)";
+    vrev_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vrev.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRev<uint8_t>, /*strip_mine*/ true)";
+    vrev_h_vx{: vs1, vs2 : vd},
+      disasm: "vrev.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRev<uint16_t>, /*strip_mine*/ false)";
+    vrev_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vrev.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRev<uint16_t>, /*strip_mine*/ true)";
+    vrev_w_vx{: vs1, vs2 : vd},
+      disasm: "vrev.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRev<uint32_t>, /*strip_mine*/ false)";
+    vrev_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vrev.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRev<uint32_t>, /*strip_mine*/ true)";
+
+    //vror
+    vror_b_vx{: vs1, vs2 : vd},
+      disasm: "vror.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRor<uint8_t>, /*strip_mine*/ false)";
+    vror_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vror.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRor<uint8_t>, /*strip_mine*/ true)";
+    vror_h_vx{: vs1, vs2 : vd},
+      disasm: "vror.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRor<uint16_t>, /*strip_mine*/ false)";
+    vror_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vror.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRor<uint16_t>, /*strip_mine*/ true)";
+    vror_w_vx{: vs1, vs2 : vd},
+      disasm: "vror.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRor<uint32_t>, /*strip_mine*/ false)";
+    vror_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vror.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVRor<uint32_t>, /*strip_mine*/ true)";
+
+    //vmvp
+    vmvp_vv{: vs1, vs2 : vd},
+      disasm: "vmvp.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmvp_vv_m{: vs1, vs2 : vd},
+      disasm: "vmvp.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmvp_b_vx{: vs1, vs2 : vd},
+      disasm: "vmvp.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmvp_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmvp.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmvp_h_vx{: vs1, vs2 : vd},
+      disasm: "vmvp.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmvp_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmvp.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmvp_w_vx{: vs1, vs2 : vd},
+      disasm: "vmvp.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmvp_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmvp.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMvp<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsll
+    vsll_b_vv{: vs1, vs2 : vd},
+      disasm: "vsll.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsll_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsll.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsll_h_vv{: vs1, vs2 : vd},
+      disasm: "vsll.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsll_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsll.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsll_w_vv{: vs1, vs2 : vd},
+      disasm: "vsll.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsll_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsll.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsll_b_vx{: vs1, vs2 : vd},
+      disasm: "vsll.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsll_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsll.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsll_h_vx{: vs1, vs2 : vd},
+      disasm: "vsll.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsll_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsll.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsll_w_vx{: vs1, vs2 : vd},
+      disasm: "vsll.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsll_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vsll.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSll<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsra
+    vsra_b_vv{: vs1, vs2 : vd},
+      disasm: "vsra.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsra_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsra.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsra_h_vv{: vs1, vs2 : vd},
+      disasm: "vsra.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsra_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsra.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsra_w_vv{: vs1, vs2 : vd},
+      disasm: "vsra.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsra_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsra.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsra_b_vx{: vs1, vs2 : vd},
+      disasm: "vsra.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsra_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsra.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsra_h_vx{: vs1, vs2 : vd},
+      disasm: "vsra.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsra_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsra.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsra_w_vx{: vs1, vs2 : vd},
+      disasm: "vsra.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsra_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vsra.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSra<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsrl
+    vsrl_b_vv{: vs1, vs2 : vd},
+      disasm: "vsrl.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrl_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrl.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrl_h_vv{: vs1, vs2 : vd},
+      disasm: "vsrl.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrl_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrl.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrl_w_vv{: vs1, vs2 : vd},
+      disasm: "vsrl.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrl_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrl.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrl_b_vx{: vs1, vs2 : vd},
+      disasm: "vsrl.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrl_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrl.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsrl_h_vx{: vs1, vs2 : vd},
+      disasm: "vsrl.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrl_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrl.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsrl_w_vx{: vs1, vs2 : vd},
+      disasm: "vsrl.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrl_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrl.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrl<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsha
+    vsha_b_vv{: vs1, vs2 : vd},
+      disasm: "vsha.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int8_t>, /* round */ false, /*strip_mine*/ false)";
+    vsha_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsha.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int8_t>, /* round */ false, /*strip_mine*/ true)";
+    vsha_h_vv{: vs1, vs2 : vd},
+      disasm: "vsha.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int16_t>, /* round */ false, /*strip_mine*/ false)";
+    vsha_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsha.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int16_t>, /* round */ false, /*strip_mine*/ true)";
+    vsha_w_vv{: vs1, vs2 : vd},
+      disasm: "vsha.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int32_t>, /* round */ false, /*strip_mine*/ false)";
+    vsha_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vsha.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int32_t>, /* round */ false, /*strip_mine*/ true)";
+    vsha_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vsha.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int8_t>, /* round */ true, /*strip_mine*/ false)";
+    vsha_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsha.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int8_t>, /* round */ true, /*strip_mine*/ true)";
+    vsha_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vsha.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int16_t>, /* round */ true, /*strip_mine*/ false)";
+    vsha_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsha.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int16_t>, /* round */ true, /*strip_mine*/ true)";
+    vsha_w_r_vv{: vs1, vs2 : vd},
+      disasm: "vsha.w.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int32_t>, /* round */ true, /*strip_mine*/ false)";
+    vsha_w_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsha.w.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<int32_t>, /* round */ true, /*strip_mine*/ true)";
+
+    //vshl
+    vshl_b_vv{: vs1, vs2 : vd},
+      disasm: "vshl.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint8_t>, /* round */ false, /*strip_mine*/ false)";
+    vshl_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vshl.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint8_t>, /* round */ false, /*strip_mine*/ true)";
+    vshl_h_vv{: vs1, vs2 : vd},
+      disasm: "vshl.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint16_t>, /* round */ false, /*strip_mine*/ false)";
+    vshl_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vshl.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint16_t>, /* round */ false, /*strip_mine*/ true)";
+    vshl_w_vv{: vs1, vs2 : vd},
+      disasm: "vshl.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint32_t>, /* round */ false, /*strip_mine*/ false)";
+    vshl_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vshl.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint32_t>, /* round */ false, /*strip_mine*/ true)";
+    vshl_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vshl.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint8_t>, /* round */ true, /*strip_mine*/ false)";
+    vshl_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vshl.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint8_t>, /* round */ true, /*strip_mine*/ true)";
+    vshl_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vshl.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint16_t>, /* round */ true, /*strip_mine*/ false)";
+    vshl_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vshl.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint16_t>, /* round */ true, /*strip_mine*/ true)";
+    vshl_w_r_vv{: vs1, vs2 : vd},
+      disasm: "vshl.w.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint32_t>, /* round */ true, /*strip_mine*/ false)";
+    vshl_w_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vshl.w.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVShift<uint32_t>, /* round */ true, /*strip_mine*/ true)";
+
+    //vnot
+    vnot_v{: vs1 : vd},
+      disasm: "vnot.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVNot<int32_t>, /*strip_mine*/ false)";
+    vnot_v_m{: vs1 : vd},
+      disasm: "vnot.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVNot<int32_t>, /*strip_mine*/ true)";
+
+    //vclb
+    vclb_b_v{: vs1 : vd},
+      disasm: "vclb.b.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClb<uint8_t>, /*strip_mine*/ false)";
+    vclb_b_v_m{: vs1 : vd},
+      disasm: "vclb.b.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClb<uint8_t>, /*strip_mine*/ true)";
+    vclb_h_v{: vs1 : vd},
+      disasm: "vclb.h.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClb<uint16_t>, /*strip_mine*/ false)";
+    vclb_h_v_m{: vs1 : vd},
+      disasm: "vclb.h.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClb<uint16_t>, /*strip_mine*/ true)";
+    vclb_w_v{: vs1 : vd},
+      disasm: "vclb.w.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClb<uint32_t>, /*strip_mine*/ false)";
+    vclb_w_v_m{: vs1 : vd},
+      disasm: "vclb.w.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClb<uint32_t>, /*strip_mine*/ true)";
+
+    //vclz
+    vclz_b_v{: vs1 : vd},
+      disasm: "vclz.b.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClz<uint8_t>, /*strip_mine*/ false)";
+    vclz_b_v_m{: vs1 : vd},
+      disasm: "vclz.b.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClz<uint8_t>, /*strip_mine*/ true)";
+    vclz_h_v{: vs1 : vd},
+      disasm: "vclz.h.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClz<uint16_t>, /*strip_mine*/ false)";
+    vclz_h_v_m{: vs1 : vd},
+      disasm: "vclz.h.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClz<uint16_t>, /*strip_mine*/ true)";
+    vclz_w_v{: vs1 : vd},
+      disasm: "vclz.w.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClz<uint32_t>, /*strip_mine*/ false)";
+    vclz_w_v_m{: vs1 : vd},
+      disasm: "vclz.w.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVClz<uint32_t>, /*strip_mine*/ true)";
+
+    //vcpop
+    vcpop_b_v{: vs1 : vd},
+      disasm: "vcpop.b.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVCpop<uint8_t>, /*strip_mine*/ false)";
+    vcpop_b_v_m{: vs1 : vd},
+      disasm: "vcpop.b.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVCpop<uint8_t>, /*strip_mine*/ true)";
+    vcpop_h_v{: vs1 : vd},
+      disasm: "vcpop.h.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVCpop<uint16_t>, /*strip_mine*/ false)";
+    vcpop_h_v_m{: vs1 : vd},
+      disasm: "vcpop.h.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVCpop<uint16_t>, /*strip_mine*/ true)";
+    vcpop_w_v{: vs1 : vd},
+      disasm: "vcpop.w.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVCpop<uint32_t>, /*strip_mine*/ false)";
+    vcpop_w_v_m{: vs1 : vd},
+      disasm: "vcpop.w.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVCpop<uint32_t>, /*strip_mine*/ true)";
+
+    //vmv
+    vmv_v{: vs1 : vd},
+      disasm: "vmv.v", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVMv<int32_t>, /*strip_mine*/ false)";
+    vmv_v_m{: vs1 : vd},
+      disasm: "vmv.v.m", "%vd, %vs1",
+      semfunc: "absl::bind_front(&KelvinVMv<int32_t>, /*strip_mine*/ true)";
+
+    //vsrans
+    vsrans_b_vv{: vs1, vs2 : vd},
+      disasm: "vsrans.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrans_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrans.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrans_h_vv{: vs1, vs2 : vd},
+      disasm: "vsrans.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrans_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrans.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrans_b_vx{: vs1, vs2 : vd},
+      disasm: "vsrans.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrans_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrans.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ true)";
+    vsrans_h_vx{: vs1, vs2 : vd},
+      disasm: "vsrans.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrans_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrans.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ true)";
+    vsrans_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vsrans.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrans_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrans.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrans_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vsrans.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ false)";
+    vsrans_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsrans.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ true)";
+    vsrans_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vsrans.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrans_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrans.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int16_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ true)";
+    vsrans_h_r_vx{: vs1, vs2 : vd},
+      disasm: "vsrans.h.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ false)";
+    vsrans_h_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vsrans.h.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int16_t, int32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsransu
+    vsransu_b_vv{: vs1, vs2 : vd},
+      disasm: "vsransu.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ false)";
+    vsransu_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsransu.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ true)";
+    vsransu_h_vv{: vs1, vs2 : vd},
+      disasm: "vsransu.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ false)";
+    vsransu_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vsransu.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ true)";
+    vsransu_b_vx{: vs1, vs2 : vd},
+      disasm: "vsransu.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ false)";
+    vsransu_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsransu.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ true)";
+    vsransu_h_vx{: vs1, vs2 : vd},
+      disasm: "vsransu.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ false)";
+    vsransu_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vsransu.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ true)";
+    vsransu_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vsransu.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ false)";
+    vsransu_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsransu.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ true)";
+    vsransu_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vsransu.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ false)";
+    vsransu_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsransu.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ true)";
+    vsransu_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vsransu.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ false)";
+    vsransu_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vsransu.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint16_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ true)";
+    vsransu_h_r_vx{: vs1, vs2 : vd},
+      disasm: "vsransu.h.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ false)";
+    vsransu_h_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vsransu.h.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint16_t, uint32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsraqs
+    vsraqs_b_vv{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ false)";
+    vsraqs_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ true)";
+    vsraqs_b_vx{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ false)";
+    vsraqs_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ true)";
+    vsraqs_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ false)";
+    vsraqs_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ true)";
+    vsraqs_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ false)";
+    vsraqs_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vsraqs.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<int8_t, int32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vsraqsu
+    vsraqsu_b_vv{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ false)";
+    vsraqsu_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ false, /*scalar*/ false, /*strip_mine*/ true)";
+    vsraqsu_b_vx{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ false)";
+    vsraqsu_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ false, /*scalar*/ true, /*strip_mine*/ true)";
+    vsraqsu_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ false)";
+    vsraqsu_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ true, /*scalar*/ false, /*strip_mine*/ true)";
+    vsraqsu_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ false)";
+    vsraqsu_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vsraqsu.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSrans<uint8_t, uint32_t>, /*round*/ true, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vmul
+    vmul_b_vv{: vs1, vs2 : vd},
+      disasm: "vmul.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmul_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vmul.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmul_h_vv{: vs1, vs2 : vd},
+      disasm: "vmul.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmul_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmul.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmul_w_vv{: vs1, vs2 : vd},
+      disasm: "vmul.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmul_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmul.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmul_b_vx{: vs1, vs2 : vd},
+      disasm: "vmul.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmul_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmul.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmul_h_vx{: vs1, vs2 : vd},
+      disasm: "vmul.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmul_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmul.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmul_w_vx{: vs1, vs2 : vd},
+      disasm: "vmul.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmul_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmul.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMul<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+   //vmuls
+    vmuls_b_vv{: vs1, vs2 : vd},
+      disasm: "vmuls.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmuls_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vmuls.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmuls_h_vv{: vs1, vs2 : vd},
+      disasm: "vmuls.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmuls_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmuls.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmuls_w_vv{: vs1, vs2 : vd},
+      disasm: "vmuls.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmuls_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmuls.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmuls_b_vx{: vs1, vs2 : vd},
+      disasm: "vmuls.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmuls_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmuls.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmuls_h_vx{: vs1, vs2 : vd},
+      disasm: "vmuls.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmuls_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmuls.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmuls_w_vx{: vs1, vs2 : vd},
+      disasm: "vmuls.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmuls_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmuls.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vmulsu
+    vmulsu_b_vv{: vs1, vs2 : vd},
+      disasm: "vmulsu.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulsu_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulsu.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulsu_h_vv{: vs1, vs2 : vd},
+      disasm: "vmulsu.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulsu_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulsu.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulsu_w_vv{: vs1, vs2 : vd},
+      disasm: "vmulsu.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulsu_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulsu.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulsu_b_vx{: vs1, vs2 : vd},
+      disasm: "vmulsu.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulsu_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulsu.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmulsu_h_vx{: vs1, vs2 : vd},
+      disasm: "vmulsu.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulsu_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulsu.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmulsu_w_vx{: vs1, vs2 : vd},
+      disasm: "vmulsu.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulsu_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulsu.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMuls<uint32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vmulw
+    vmulw_h_vv{: vs1, vs2 : vd},
+      disasm: "vmulw.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulw_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulw.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int16_t, int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulw_w_vv{: vs1, vs2 : vd},
+      disasm: "vmulw.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulw_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulw.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int32_t, int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulw_h_vx{: vs1, vs2 : vd},
+      disasm: "vmulw.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulw_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulw.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int16_t, int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmulw_w_vx{: vs1, vs2 : vd},
+      disasm: "vmulw.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulw_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulw.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<int32_t, int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vmulwu
+    vmulw_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vmulw.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulw_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulw.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint16_t, uint8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulw_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vmulw.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmulw_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulw.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint32_t, uint16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmulw_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vmulw.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulw_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulw.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint16_t, uint8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmulw_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vmulw.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmulw_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulw.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulw<uint32_t, uint16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vmulh
+    vmulh_b_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vmulh_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vmulh_h_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vmulh_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vmulh_w_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vmulh_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vmulh_b_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vmulh_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vmulh_h_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vmulh_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vmulh_w_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vmulh_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+
+    //vmulh.r
+    vmulh_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vmulh_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vmulh_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vmulh_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vmulh_w_r_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.w.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vmulh_w_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vmulh_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vmulh_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vmulh_h_r_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.h.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vmulh_h_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vmulh_w_r_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.w.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vmulh_w_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+
+    //vmulh.u
+    vmulh_b_u_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.b.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vmulh_b_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vmulh_h_u_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.h.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vmulh_h_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vmulh_w_u_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.w.u.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false)";
+    vmulh_w_u_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.u.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false)";
+    vmulh_b_u_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.b.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vmulh_b_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vmulh_h_u_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.h.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vmulh_h_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+    vmulh_w_u_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.w.u.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false)";
+    vmulh_w_u_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.u.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false)";
+
+    //vmulh.ru
+    vmulh_b_ur_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.b.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vmulh_b_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vmulh_h_ur_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.h.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vmulh_h_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vmulh_w_ur_vv{: vs1, vs2 : vd},
+      disasm: "vmulh.w.ur.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true)";
+    vmulh_w_ur_vv_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.ur.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true)";
+    vmulh_b_ur_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.b.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vmulh_b_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.b.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vmulh_h_ur_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.h.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vmulh_h_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.h.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+    vmulh_w_ur_vx{: vs1, vs2 : vd},
+      disasm: "vmulh.w.ur.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true)";
+    vmulh_w_ur_vx_m{: vs1, vs2 : vd},
+      disasm: "vmulh.w.ur.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMulh<uint32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true)";
+
+    //vdmulh
+    vdmulh_b_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false, /* round_neg */ false)";
+    vdmulh_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false, /* round_neg */ false)";
+    vdmulh_h_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false, /* round_neg */ false)";
+    vdmulh_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false, /* round_neg */ false)";
+    vdmulh_w_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ false, /* round_neg */ false)";
+    vdmulh_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ false, /* round_neg */ false)";
+    vdmulh_b_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false, /* round_neg */ false)";
+    vdmulh_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false, /* round_neg */ false)";
+    vdmulh_h_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false, /* round_neg */ false)";
+    vdmulh_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false, /* round_neg */ false)";
+    vdmulh_w_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ false, /* round_neg */ false)";
+    vdmulh_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ false, /* round_neg */ false)";
+
+    //vdmulh.r
+    vdmulh_b_r_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true, /* round_neg */ false)";
+    vdmulh_b_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true, /* round_neg */ false)";
+    vdmulh_h_r_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true, /* round_neg */ false)";
+    vdmulh_h_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true, /* round_neg */ false)";
+    vdmulh_w_r_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.r.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true, /* round_neg */ false)";
+    vdmulh_w_r_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.r.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true, /* round_neg */ false)";
+    vdmulh_b_r_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true, /* round_neg */ false)";
+    vdmulh_b_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true, /* round_neg */ false)";
+    vdmulh_h_r_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true, /* round_neg */ false)";
+    vdmulh_h_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true, /* round_neg */ false)";
+    vdmulh_w_r_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.r.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true, /* round_neg */ false)";
+    vdmulh_w_r_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.r.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true, /* round_neg */ false)";
+
+    //vdmulh.rn
+    vdmulh_b_rn_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.rn.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true, /* round_neg */ true)";
+    vdmulh_b_rn_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.rn.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true, /* round_neg */ true)";
+    vdmulh_h_rn_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.rn.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true, /* round_neg */ true)";
+    vdmulh_h_rn_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.rn.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true, /* round_neg */ true)";
+    vdmulh_w_rn_vv{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.rn.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ false, /*strip_mine*/ false, /* round */ true, /* round_neg */ true)";
+    vdmulh_w_rn_vv_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.rn.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ false, /*strip_mine*/ true, /* round */ true, /* round_neg */ true)";
+    vdmulh_b_rn_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.rn.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true, /* round_neg */ true)";
+    vdmulh_b_rn_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.b.rn.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int8_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true, /* round_neg */ true)";
+    vdmulh_h_rn_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.rn.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true, /* round_neg */ true)";
+    vdmulh_h_rn_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.h.rn.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int16_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true, /* round_neg */ true)";
+    vdmulh_w_rn_vx{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.rn.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ true, /*strip_mine*/ false, /* round */ true, /* round_neg */ true)";
+    vdmulh_w_rn_vx_m{: vs1, vs2 : vd},
+      disasm: "vdmulh.w.rn.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVDmulh<int32_t>, /*scalar*/ true, /*strip_mine*/ true, /* round */ true, /* round_neg */ true)";
+
+    //vmacc
+    vmacc_b_vv{: vs1, vs2 : vd},
+      disasm: "vmacc.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmacc_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vmacc.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmacc_h_vv{: vs1, vs2 : vd},
+      disasm: "vmacc.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmacc_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmacc.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmacc_w_vv{: vs1, vs2 : vd},
+      disasm: "vmacc.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmacc_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmacc.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmacc_b_vx{: vs1, vs2 : vd},
+      disasm: "vmacc.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmacc_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmacc.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmacc_h_vx{: vs1, vs2 : vd},
+      disasm: "vmacc.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmacc_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmacc.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmacc_w_vx{: vs1, vs2 : vd},
+      disasm: "vmacc.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmacc_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmacc.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMacc<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vmadd
+    vmadd_b_vv{: vs1, vs2 : vd},
+      disasm: "vmadd.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmadd_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vmadd.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmadd_h_vv{: vs1, vs2 : vd},
+      disasm: "vmadd.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmadd_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vmadd.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmadd_w_vv{: vs1, vs2 : vd},
+      disasm: "vmadd.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vmadd_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vmadd.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vmadd_b_vx{: vs1, vs2 : vd},
+      disasm: "vmadd.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmadd_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vmadd.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmadd_h_vx{: vs1, vs2 : vd},
+      disasm: "vmadd.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmadd_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vmadd.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vmadd_w_vx{: vs1, vs2 : vd},
+      disasm: "vmadd.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vmadd_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vmadd.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVMadd<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vslidevn
+    vslidevn_b_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.b.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int8_t>, 1 /* index */)";
+    vslidevn_b_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.b.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int8_t>, 2 /* index */)";
+    vslidevn_b_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.b.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int8_t>, 3 /* index */)";
+    vslidevn_b_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.b.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int8_t>, 4 /* index */)";
+    vslidevn_h_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.h.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int16_t>, 1 /* index */)";
+    vslidevn_h_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.h.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int16_t>, 2 /* index */)";
+    vslidevn_h_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.h.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int16_t>, 3 /* index */)";
+    vslidevn_h_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.h.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int16_t>, 4 /* index */)";
+    vslidevn_w_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.w.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int32_t>, 1 /* index */)";
+    vslidevn_w_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.w.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int32_t>, 2 /* index */)";
+    vslidevn_w_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.w.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int32_t>, 3 /* index */)";
+    vslidevn_w_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevn.w.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevn<int32_t>, 4 /* index */)";
+
+    //vslidehn
+    vslidehn_b_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.b.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int8_t>, 1 /* index */)";
+    vslidehn_b_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.b.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int8_t>, 2 /* index */)";
+    vslidehn_b_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.b.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int8_t>, 3 /* index */)";
+    vslidehn_b_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.b.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int8_t>, 4 /* index */)";
+    vslidehn_h_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.h.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int16_t>, 1 /* index */)";
+    vslidehn_h_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.h.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int16_t>, 2 /* index */)";
+    vslidehn_h_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.h.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int16_t>, 3 /* index */)";
+    vslidehn_h_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.h.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int16_t>, 4 /* index */)";
+    vslidehn_w_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.w.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int32_t>, 1 /* index */)";
+    vslidehn_w_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.w.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int32_t>, 2 /* index */)";
+    vslidehn_w_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.w.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int32_t>, 3 /* index */)";
+    vslidehn_w_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehn.w.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehn<int32_t>, 4 /* index */)";
+
+    //vslidevp
+    vslidevp_b_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.b.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int8_t>, 1 /* index */)";
+    vslidevp_b_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.b.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int8_t>, 2 /* index */)";
+    vslidevp_b_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.b.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int8_t>, 3 /* index */)";
+    vslidevp_b_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.b.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int8_t>, 4 /* index */)";
+    vslidevp_h_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.h.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int16_t>, 1 /* index */)";
+    vslidevp_h_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.h.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int16_t>, 2 /* index */)";
+    vslidevp_h_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.h.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int16_t>, 3 /* index */)";
+    vslidevp_h_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.h.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int16_t>, 4 /* index */)";
+    vslidevp_w_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.w.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int32_t>, 1 /* index */)";
+    vslidevp_w_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.w.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int32_t>, 2 /* index */)";
+    vslidevp_w_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.w.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int32_t>, 3 /* index */)";
+    vslidevp_w_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidevp.w.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidevp<int32_t>, 4 /* index */)";
+
+    //vslidehp
+    vslidehp_b_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.b.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int8_t>, 1 /* index */)";
+    vslidehp_b_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.b.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int8_t>, 2 /* index */)";
+    vslidehp_b_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.b.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int8_t>, 3 /* index */)";
+    vslidehp_b_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.b.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int8_t>, 4 /* index */)";
+    vslidehp_h_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.h.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int16_t>, 1 /* index */)";
+    vslidehp_h_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.h.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int16_t>, 2 /* index */)";
+    vslidehp_h_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.h.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int16_t>, 3 /* index */)";
+    vslidehp_h_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.h.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int16_t>, 4 /* index */)";
+    vslidehp_w_1_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.w.1.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int32_t>, 1 /* index */)";
+    vslidehp_w_2_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.w.2.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int32_t>, 2 /* index */)";
+    vslidehp_w_3_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.w.3.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int32_t>, 3 /* index */)";
+    vslidehp_w_4_vv_m{: vs1, vs2 : vd},
+      disasm: "vslidehp.w.4.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSlidehp<int32_t>, 4 /* index */)";
+
+    //vsel
+    vsel_b_vv{: vs1, vs2, vd : vd},
+      disasm: "vsel.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsel_b_vv_m{: vs1, vs2, vd : vd},
+      disasm: "vsel.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsel_h_vv{: vs1, vs2, vd : vd},
+      disasm: "vsel.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsel_h_vv_m{: vs1, vs2, vd : vd},
+      disasm: "vsel.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsel_w_vv{: vs1, vs2, vd : vd},
+      disasm: "vsel.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vsel_w_vv_m{: vs1, vs2, vd : vd},
+      disasm: "vsel.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vsel_b_vx{: vs1, vs2, vd : vd},
+      disasm: "vsel.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsel_b_vx_m{: vs1, vs2, vd : vd},
+      disasm: "vsel.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsel_h_vx{: vs1, vs2, vd : vd},
+      disasm: "vsel.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsel_h_vx_m{: vs1, vs2, vd : vd},
+      disasm: "vsel.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vsel_w_vx{: vs1, vs2, vd : vd},
+      disasm: "vsel.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vsel_w_vx_m{: vs1, vs2, vd : vd},
+      disasm: "vsel.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVSel<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vevn
+    vevn_b_vv{: vs1, vs2 : vd},
+      disasm: "vevn.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vevn_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vevn.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vevn_h_vv{: vs1, vs2 : vd},
+      disasm: "vevn.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vevn_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vevn.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vevn_w_vv{: vs1, vs2 : vd},
+      disasm: "vevn.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vevn_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vevn.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vevn_b_vx{: vs1, vs2 : vd},
+      disasm: "vevn.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vevn_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vevn.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vevn_h_vx{: vs1, vs2 : vd},
+      disasm: "vevn.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vevn_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vevn.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vevn_w_vx{: vs1, vs2 : vd},
+      disasm: "vevn.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vevn_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vevn.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvn<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vodd
+    vodd_b_vv{: vs1, vs2 : vd},
+      disasm: "vodd.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vodd_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vodd.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vodd_h_vv{: vs1, vs2 : vd},
+      disasm: "vodd.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vodd_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vodd.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vodd_w_vv{: vs1, vs2 : vd},
+      disasm: "vodd.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vodd_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vodd.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vodd_b_vx{: vs1, vs2 : vd},
+      disasm: "vodd.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vodd_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vodd.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vodd_h_vx{: vs1, vs2 : vd},
+      disasm: "vodd.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vodd_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vodd.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vodd_w_vx{: vs1, vs2 : vd},
+      disasm: "vodd.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vodd_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vodd.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVOdd<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vevnodd
+    vevnodd_b_vv{: vs1, vs2 : vd},
+      disasm: "vevnodd.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vevnodd_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vevnodd.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vevnodd_h_vv{: vs1, vs2 : vd},
+      disasm: "vevnodd.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vevnodd_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vevnodd.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vevnodd_w_vv{: vs1, vs2 : vd},
+      disasm: "vevnodd.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vevnodd_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vevnodd.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vevnodd_b_vx{: vs1, vs2 : vd},
+      disasm: "vevnodd.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vevnodd_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vevnodd.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vevnodd_h_vx{: vs1, vs2 : vd},
+      disasm: "vevnodd.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vevnodd_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vevnodd.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vevnodd_w_vx{: vs1, vs2 : vd},
+      disasm: "vevnodd.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vevnodd_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vevnodd.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVEvnodd<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vzip
+    vzip_b_vv{: vs1, vs2 : vd},
+      disasm: "vzip.b.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int8_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vzip_b_vv_m{: vs1, vs2 : vd},
+      disasm: "vzip.b.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int8_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vzip_h_vv{: vs1, vs2 : vd},
+      disasm: "vzip.h.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int16_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vzip_h_vv_m{: vs1, vs2 : vd},
+      disasm: "vzip.h.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int16_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vzip_w_vv{: vs1, vs2 : vd},
+      disasm: "vzip.w.vv", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int32_t>, /*scalar*/ false, /*strip_mine*/ false)";
+    vzip_w_vv_m{: vs1, vs2 : vd},
+      disasm: "vzip.w.vv.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int32_t>, /*scalar*/ false, /*strip_mine*/ true)";
+    vzip_b_vx{: vs1, vs2 : vd},
+      disasm: "vzip.b.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int8_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vzip_b_vx_m{: vs1, vs2 : vd},
+      disasm: "vzip.b.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int8_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vzip_h_vx{: vs1, vs2 : vd},
+      disasm: "vzip.h.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int16_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vzip_h_vx_m{: vs1, vs2 : vd},
+      disasm: "vzip.h.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int16_t>, /*scalar*/ true, /*strip_mine*/ true)";
+    vzip_w_vx{: vs1, vs2 : vd},
+      disasm: "vzip.w.vx", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int32_t>, /*scalar*/ true, /*strip_mine*/ false)";
+    vzip_w_vx_m{: vs1, vs2 : vd},
+      disasm: "vzip.w.vx.m", "%vd, %vs1, %vs2",
+      semfunc: "absl::bind_front(&KelvinVZip<int32_t>, /*scalar*/ true, /*strip_mine*/ true)";
+
+    //vld
+    vld_b_x{(: vs1 :), (: : vd)},
+    disasm: "vld.b.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>, /*strip_mine*/ false)";
+    vld_h_x{(: vs1 :), (: : vd)},
+    disasm: "vld.h.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_x{(: vs1 :), (: : vd)},
+    disasm: "vld.w.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_x_m{(: vs1 :), (: : vd)},
+    disasm: "vld.b.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_x_m{(: vs1 :), (: : vd)},
+    disasm: "vld.h.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_x_m{(: vs1 :), (: : vd)},
+    disasm: "vld.w.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_p_x{(: vs1 : vs1), (: : vd)},
+    disasm: "vld.b.p.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ false)";
+    vld_h_p_x{(: vs1 : vs1), (: : vd)},
+    disasm: "vld.h.p.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_p_x{(: vs1 : vs1), (: : vd)},
+    disasm: "vld.w.p.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_p_x_m{(: vs1 : vs1), (: : vd)},
+    disasm: "vld.b.p.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_p_x_m{(: vs1 : vs1), (: : vd)},
+    disasm: "vld.h.p.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_p_x_m{(: vs1 : vs1), (: : vd)},
+    disasm: "vld.w.p.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_p_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.p.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ false)";
+    vld_h_p_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.p.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_p_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.p.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_p_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.p.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_p_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.p.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_p_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.p.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_l_xx{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.b.l.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>, /*strip_mine*/ false)";
+    vld_h_l_xx{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.h.l.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_l_xx{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.w.l.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_l_xx_m{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.b.l.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_l_xx_m{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.h.l.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_l_xx_m{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.w.l.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_lp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.lp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ false)";
+    vld_h_lp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.lp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_lp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.lp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_lp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.lp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_lp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.lp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_lp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.lp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_s_xx{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.b.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>, /*strip_mine*/ false)";
+    vld_h_s_xx{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.h.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_s_xx{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.w.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_s_xx_m{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.b.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_s_xx_m{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.h.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_s_xx_m{(: vs1, vs2 :), (: : vd)},
+    disasm: "vld.w.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_sp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.sp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ false)";
+    vld_h_sp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.sp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_sp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.sp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_sp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.sp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_sp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.sp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_sp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.sp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    vld_b_tp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.tp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ false)";
+    vld_h_tp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.tp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ false)";
+    vld_w_tp_xx{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.tp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ false)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ false)";
+    vld_b_tp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.b.tp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int8_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int8_t>,/*strip_mine*/ true)";
+    vld_h_tp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.h.tp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int16_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int16_t>,/*strip_mine*/ true)";
+    vld_w_tp_xx_m{(: vs1, vs2 : vs1), (: : vd)},
+    disasm: "vld.w.tp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVLd<int32_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ true)",
+             "absl::bind_front(&KelvinVLdRegWrite<int32_t>,/*strip_mine*/ true)";
+    //vst, note `vd` is actually the source vector register, and `vs1` is actually the scaler register.
+    vst_b_x{: vd, vs1 :},
+    disasm: "vst.b.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_h_x{: vd, vs1 :},
+    disasm: "vst.h.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_w_x{: vd, vs1 :},
+    disasm: "vst.w.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_b_x_m{: vd, vs1 :},
+    disasm: "vst.b.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_h_x_m{: vd, vs1 :},
+    disasm: "vst.h.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_w_x_m{: vd, vs1 :},
+    disasm: "vst.w.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_b_p_x{: vd, vs1 : vs1},
+    disasm: "vst.b.p.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_h_p_x{: vd, vs1 : vs1},
+    disasm: "vst.h.p.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_w_p_x{: vd, vs1 : vs1},
+    disasm: "vst.w.p.x", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_b_p_x_m{: vd, vs1 : vs1},
+    disasm: "vst.b.p.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_h_p_x_m{: vd, vs1 : vs1},
+    disasm: "vst.h.p.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_w_p_x_m{: vd, vs1 : vs1},
+    disasm: "vst.w.p.x.m", "%vd, %vs1",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_b_p_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.p.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_h_p_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.p.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_w_p_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.p.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ false)";
+    vst_b_p_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.p.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_h_p_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.p.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_w_p_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vld.w.p.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ false, /*strip_mine*/ true)";
+    vst_b_l_xx{: vd, vs1, vs2 :},
+    disasm: "vst.b.l.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)";
+    vst_h_l_xx{: vd, vs1, vs2 :},
+    disasm: "vst.h.l.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)";
+    vst_w_l_xx{: vd, vs1, vs2 :},
+    disasm: "vst.w.l.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)";
+    vst_b_l_xx_m{: vd, vs1, vs2 :},
+    disasm: "vst.b.l.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)";
+    vst_h_l_xx_m{: vd, vs1, vs2 :},
+    disasm: "vst.h.l.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)";
+    vst_w_l_xx_m{: vd, vs1, vs2 :},
+    disasm: "vst.w.l.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)";
+    vst_b_lp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.lp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)";
+    vst_h_lp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.lp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)";
+    vst_w_lp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.lp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ false)";
+    vst_b_lp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.lp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)";
+    vst_h_lp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.lp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)";
+    vst_w_lp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.lp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ true, /*stride*/ false, /*strip_mine*/ true)";
+    vst_b_s_xx{: vd, vs1, vs2 :},
+    disasm: "vst.b.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)";
+    vst_h_s_xx{: vd, vs1, vs2 :},
+    disasm: "vst.h.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)";
+    vst_w_s_xx{: vd, vs1, vs2 :},
+    disasm: "vst.w.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)";
+    vst_b_s_xx_m{: vd, vs1, vs2 :},
+    disasm: "vst.b.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)";
+    vst_h_s_xx_m{: vd, vs1, vs2 :},
+    disasm: "vst.h.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)";
+    vst_w_s_xx_m{: vd, vs1, vs2 :},
+    disasm: "vst.w.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)";
+    vst_b_sp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.sp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)";
+    vst_h_sp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.sp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)";
+    vst_w_sp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.sp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ false)";
+    vst_b_sp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.sp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)";
+    vst_h_sp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.sp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)";
+    vst_w_sp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.sp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ false, /*stride*/ true, /*strip_mine*/ true)";
+    vst_b_tp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.tp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ false)";
+    vst_h_tp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.tp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ false)";
+    vst_w_tp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.tp.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ false)";
+    vst_b_tp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.b.tp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int8_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ true)";
+    vst_h_tp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.h.tp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int16_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ true)";
+    vst_w_tp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vst.w.tp.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVSt<int32_t>, /*len*/ true, /*stride*/ true, /*strip_mine*/ true)";
+    vstq_b_s_xx{: vd, vs1, vs2 :},
+    disasm: "vstq.b.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int8_t>, /*strip_mine*/ false)";
+    vstq_h_s_xx{: vd, vs1, vs2 :},
+    disasm: "vstq.h.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int16_t>, /*strip_mine*/ false)";
+    vstq_w_s_xx{: vd, vs1, vs2 :},
+    disasm: "vstq.w.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int32_t>, /*strip_mine*/ false)";
+    vstq_b_sp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vstq.b.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int8_t>, /*strip_mine*/ false)";
+    vstq_h_sp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vstq.h.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int16_t>, /*strip_mine*/ false)";
+    vstq_w_sp_xx{: vd, vs1, vs2 : vs1},
+    disasm: "vstq.w.s.xx", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int32_t>, /*strip_mine*/ false)";
+    vstq_b_s_xx_m{: vd, vs1, vs2 :},
+    disasm: "vstq.b.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int8_t>, /*strip_mine*/ true)";
+    vstq_h_s_xx_m{: vd, vs1, vs2 :},
+    disasm: "vstq.h.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int16_t>, /*strip_mine*/ true)";
+    vstq_w_s_xx_m{: vd, vs1, vs2 :},
+    disasm: "vstq.w.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int32_t>, /*strip_mine*/ true)";
+    vstq_b_sp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vstq.b.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int8_t>, /*strip_mine*/ true)";
+    vstq_h_sp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vstq.h.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int16_t>, /*strip_mine*/ true)";
+    vstq_w_sp_xx_m{: vd, vs1, vs2 : vs1},
+    disasm: "vstq.w.s.xx.m", "%vd, %vs1, %vs2",
+    semfunc: "absl::bind_front(&KelvinVStQ<int32_t>, /*strip_mine*/ true)";
+  }
+}
+
+slot kelvin_memory {
+  includes {
+    #include "sim/kelvin_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  opcodes {
+    flushall{},
+      disasm: "flushall",
+      semfunc: "&KelvinNopInstruction";
+    flushat{: rs1 :},
+      disasm: "flushat", "%rs1",
+      semfunc: "&KelvinNopInstruction";
+  }
+}
+
+slot kelvin_system {
+  includes {
+    #include "sim/kelvin_vector_memory_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  resources TwoOp = { next_pc, rs1 : rd[..rd]};
+  resources ThreeOp = { next_pc, rs1, rs2 : rd[..rd]};
+  opcodes {
+    getmaxvl_b{: : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "getmaxvl.b", "%rd",
+      semfunc: "absl::bind_front(&KelvinGetVl<int8_t>, /*strip_mine*/ false, /*is_rs1*/ false, /*is_rs2*/ false)";
+    getmaxvl_h{: : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "getmaxvl.h", "%rd",
+      semfunc: "absl::bind_front(&KelvinGetVl<int16_t>, /*strip_mine*/ false, /*is_rs1*/ false, /*is_rs2*/ false)";
+    getmaxvl_w{: : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "getmaxvl.w", "%rd",
+      semfunc: "absl::bind_front(&KelvinGetVl<int32_t>, /*strip_mine*/ false, /*is_rs1*/ false, /*is_rs2*/ false)";
+    getvl_b_x{: rs1 : rd},
+      resources: TwoOp,
+      disasm: "getvl.b.x", "%rd, %rs1",
+      semfunc: "absl::bind_front(&KelvinGetVl<int8_t>, /*strip_mine*/ false, /*is_rs1*/ true, /*is_rs2*/ false)";
+    getvl_h_x{: rs1 : rd},
+      resources: TwoOp,
+      disasm: "getvl.h.x", "%rd, %rs1",
+      semfunc: "absl::bind_front(&KelvinGetVl<int16_t>, /*strip_mine*/ false, /*is_rs1*/ true, /*is_rs2*/ false)";
+    getvl_w_x{: rs1 : rd},
+      resources: TwoOp,
+      disasm: "getvl.w.x", "%rd, %rs1",
+      semfunc: "absl::bind_front(&KelvinGetVl<int32_t>, /*strip_mine*/ false, /*is_rs1*/ true, /*is_rs2*/ false)";
+    getvl_b_xx{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "getvl.b.xx", "%rd, %rs1, %rs2",
+      semfunc: "absl::bind_front(&KelvinGetVl<int8_t>, /*strip_mine*/ false, /*is_rs1*/ true, /*is_rs2*/ true)";
+    getvl_h_xx{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "getvl.h.xx", "%rd, %rs1, %rs2",
+      semfunc: "absl::bind_front(&KelvinGetVl<int16_t>, /*strip_mine*/ false, /*is_rs1*/ true, /*is_rs2*/ true)";
+    getvl_w_xx{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "getvl.w.xx", "%rd, %rs1, %rs2",
+      semfunc: "absl::bind_front(&KelvinGetVl<int32_t>, /*strip_mine*/ false, /*is_rs1*/ true, /*is_rs2*/ true)";
+    getmaxvl_b_m{: : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "getmaxvl.b.m", "%rd",
+      semfunc: "absl::bind_front(&KelvinGetVl<int8_t>, /*strip_mine*/ true, /*is_rs1*/ false, /*is_rs2*/ false)";
+    getmaxvl_h_m{: : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "getmaxvl.h.m", "%rd",
+      semfunc: "absl::bind_front(&KelvinGetVl<int16_t>, /*strip_mine*/ true, /*is_rs1*/ false, /*is_rs2*/ false)";
+    getmaxvl_w_m{: : rd},
+      resources: { next_pc : rd[0..]},
+      disasm: "getmaxvl.w.m", "%rd",
+      semfunc: "absl::bind_front(&KelvinGetVl<int32_t>, /*strip_mine*/ true, /*is_rs1*/ false, /*is_rs2*/ false)";
+    getvl_b_x_m{: rs1 : rd},
+      resources: TwoOp,
+      disasm: "getvl.b.x.m", "%rd, %rs1",
+      semfunc: "absl::bind_front(&KelvinGetVl<int8_t>, /*strip_mine*/ true, /*is_rs1*/ true, /*is_rs2*/ false)";
+    getvl_h_x_m{: rs1 : rd},
+      resources: TwoOp,
+      disasm: "getvl.h.x.m", "%rd, %rs1",
+      semfunc: "absl::bind_front(&KelvinGetVl<int16_t>, /*strip_mine*/ true, /*is_rs1*/ true, /*is_rs2*/ false)";
+    getvl_w_x_m{: rs1 : rd},
+      resources: TwoOp,
+      disasm: "getvl.w.x.m", "%rd, %rs1",
+      semfunc: "absl::bind_front(&KelvinGetVl<int32_t>, /*strip_mine*/ true, /*is_rs1*/ true, /*is_rs2*/ false)";
+    getvl_b_xx_m{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "getvl.b.xx.m", "%rd, %rs1, %rs2",
+      semfunc: "absl::bind_front(&KelvinGetVl<int8_t>, /*strip_mine*/ true, /*is_rs1*/ true, /*is_rs2*/ true)";
+    getvl_h_xx_m{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "getvl.h.xx.m", "%rd, %rs1, %rs2",
+      semfunc: "absl::bind_front(&KelvinGetVl<int16_t>, /*strip_mine*/ true, /*is_rs1*/ true, /*is_rs2*/ true)";
+    getvl_w_xx_m{: rs1, rs2 : rd},
+      resources: ThreeOp,
+      disasm: "getvl.w.xx.m", "%rd, %rs1, %rs2",
+      semfunc: "absl::bind_front(&KelvinGetVl<int32_t>, /*strip_mine*/ true, /*is_rs1*/ true, /*is_rs2*/ true)";
+  }
+}
+
+slot kelvin_log {
+  includes {
+    #include "sim/kelvin_instructions.h"
+  }
+  default size = 4;
+  default latency = global_latency;
+  opcodes {
+    flog{: rs1 :},
+      resources: { next_pc : rs1[0..]},
+      disasm: "flog", "%rs1",
+      semfunc: "absl::bind_front(&KelvinLogInstruction, /*log_mode*/ 0)";
+    slog{: rs1 :},
+      resources: { next_pc : rs1[0..]},
+      disasm: "slog", "%rs1",
+      semfunc: "absl::bind_front(&KelvinLogInstruction, /*log_mode*/ 1)";
+    clog{: rs1 :},
+      resources: { next_pc : rs1[0..]},
+      disasm: "clog", "%rs1",
+      semfunc: "absl::bind_front(&KelvinLogInstruction, /*log_mode*/ 2)";
+    klog{: rs1 :},
+      resources: { next_pc : rs1[0..]},
+      disasm: "klog", "%rs1",
+      semfunc: "absl::bind_front(&KelvinLogInstruction, /*log_mode*/ 3)";
+  }
+}
+
+// Combining all kelvin instruction sets.
+slot kelvin : riscv32i, riscv32m, zicsr, zfencei, privileged, kelvin_arith, kelvin_log, kelvin_memory, kelvin_system {
+  includes {
+    #include "sim/kelvin_instructions.h"
+  }
+  default opcode =
+    disasm: "Illegal instruction at 0x%(@:08x)",
+    semfunc: "&KelvinIllegalInstruction";
+}
diff --git a/sim/kelvin_encoding.cc b/sim/kelvin_encoding.cc
new file mode 100644
index 0000000..ba8a9ce
--- /dev/null
+++ b/sim/kelvin_encoding.cc
@@ -0,0 +1,383 @@
+#include "sim/kelvin_encoding.h"
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "sim/kelvin_bin_decoder.h"
+#include "sim/kelvin_decoder.h"
+#include "sim/kelvin_enums.h"
+#include "sim/kelvin_state.h"
+#include "absl/log/log.h"
+#include "absl/strings/str_cat.h"
+#include "absl/types/span.h"
+#include "riscv/riscv_register.h"
+#include "riscv/riscv_state.h"
+#include "mpact/sim/generic/immediate_operand.h"
+#include "mpact/sim/generic/literal_operand.h"
+#include "mpact/sim/generic/register.h"
+#include "mpact/sim/generic/simple_resource.h"
+
+namespace kelvin::sim::isa32 {
+
+template <typename RegType>
+inline void GetVRegGroup(
+    KelvinState *state, int reg_num, bool strip_mine, int widen_factor,
+    std::vector<mpact::sim::generic::RegisterBase *> *vreg_group) {
+  auto regs_count = (strip_mine ? 4 : 1) * widen_factor;
+  for (int i = 0; i < regs_count; ++i) {
+    auto vreg_name =
+        absl::StrCat(mpact::sim::riscv::RiscVState::kVregPrefix, reg_num + i);
+    vreg_group->push_back(state->GetRegister<RegType>(vreg_name).first);
+  }
+}
+
+template <typename RegType>
+inline SourceOperandInterface *GetVectorRegisterSourceOp(KelvinState *state,
+                                                         int reg_num,
+                                                         bool strip_mine,
+                                                         int widen_factor) {
+  std::vector<mpact::sim::generic::RegisterBase *> vreg_group;
+  GetVRegGroup<RegType>(state, reg_num, strip_mine, widen_factor, &vreg_group);
+  auto *v_src_op = new mpact::sim::riscv::RV32VectorSourceOperand(
+      absl::Span<mpact::sim::generic::RegisterBase *>(vreg_group),
+      absl::StrCat(mpact::sim::riscv::RiscVState::kVregPrefix, reg_num));
+  return v_src_op;
+}
+
+template <typename RegType>
+inline DestinationOperandInterface *GetVectorRegisterDestinationOp(
+    KelvinState *state, int reg_num, bool strip_mine, bool widening,
+    int latency) {
+  std::vector<mpact::sim::generic::RegisterBase *> vreg_group;
+  GetVRegGroup<RegType>(state, reg_num, strip_mine, widening ? 2 : 1,
+                        &vreg_group);
+  auto *v_dst_op = new mpact::sim::riscv::RV32VectorDestinationOperand(
+      absl::Span<mpact::sim::generic::RegisterBase *>(vreg_group), latency,
+      absl::StrCat(mpact::sim::riscv::RiscVState::kVregPrefix, reg_num));
+  return v_dst_op;
+}
+
+// Generic helper functions to create register operands.
+template <typename RegType>
+inline DestinationOperandInterface *GetRegisterDestinationOp(KelvinState *state,
+                                                             std::string name,
+                                                             int latency) {
+  auto *reg = state->GetRegister<RegType>(name).first;
+  return reg->CreateDestinationOperand(latency);
+}
+
+template <typename RegType>
+inline DestinationOperandInterface *GetRegisterDestinationOp(
+    KelvinState *state, std::string name, int latency, std::string op_name) {
+  auto *reg = state->GetRegister<RegType>(name).first;
+  return reg->CreateDestinationOperand(latency, op_name);
+}
+
+template <typename T>
+inline DestinationOperandInterface *GetCSRSetBitsDestinationOp(
+    KelvinState *state, std::string name, int latency, std::string op_name) {
+  auto result = state->csr_set()->GetCsr(name);
+  if (!result.ok()) {
+    LOG(ERROR) << "No such CSR '" << name << "'";
+    return nullptr;
+  }
+  auto *csr = result.value();
+  auto *op = csr->CreateSetDestinationOperand(latency, op_name);
+  return op;
+}
+
+template <typename RegType>
+inline SourceOperandInterface *GetRegisterSourceOp(KelvinState *state,
+                                                   std::string name) {
+  auto *reg = state->GetRegister<RegType>(name).first;
+  auto *op = reg->CreateSourceOperand();
+  return op;
+}
+
+template <typename RegType>
+inline SourceOperandInterface *GetRegisterSourceOp(KelvinState *state,
+                                                   std::string name,
+                                                   std::string op_name) {
+  auto *reg = state->GetRegister<RegType>(name).first;
+  auto *op = reg->CreateSourceOperand(op_name);
+  return op;
+}
+
+KelvinEncoding::KelvinEncoding(KelvinState *state) : state_(state) {
+  InitializeSourceOperandGetters();
+  InitializeDestinationOperandGetters();
+  resource_pool_ = new mpact::sim::generic::SimpleResourcePool("Kelvin", 128);
+}
+
+KelvinEncoding::~KelvinEncoding() { delete resource_pool_; }
+
+void KelvinEncoding::InitializeSourceOperandGetters() {
+  // Source operand getters.
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kBImm12), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<int32_t>(
+            encoding::inst32_format::ExtractBImm(inst_word_));
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kCSRUimm5), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<uint32_t>(
+            encoding::inst32_format::ExtractIUimm5(inst_word_));
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kCsr), [this]() {
+        auto csr_indx = encoding::i_type::ExtractUImm12(inst_word_);
+        auto res = state_->csr_set()->GetCsr(csr_indx);
+        if (!res.ok()) {
+          return new mpact::sim::generic::ImmediateOperand<uint32_t>(csr_indx);
+        }
+        auto *csr = res.value();
+        return new mpact::sim::generic::ImmediateOperand<uint32_t>(csr_indx,
+                                                                   csr->name());
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kIImm12), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<int32_t>(
+            encoding::inst32_format::ExtractImm12(inst_word_));
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kIUimm5), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<uint32_t>(
+            encoding::inst32_format::ExtractRUimm5(inst_word_));
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kJImm12), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<int32_t>(
+            encoding::inst32_format::ExtractImm12(inst_word_));
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kJImm20), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<int32_t>(
+            encoding::inst32_format::ExtractJImm(inst_word_));
+      }));
+  source_op_getters_.insert(std::make_pair(
+      static_cast<int>(SourceOpEnum::kRs1),
+      [this]() -> SourceOperandInterface * {
+        int num = encoding::r_type::ExtractRs1(inst_word_);
+        if (num == 0)
+          return new mpact::sim::generic::IntLiteralOperand<0>({1},
+                                                               xreg_alias_[0]);
+        return GetRegisterSourceOp<mpact::sim::riscv::RV32Register>(
+            state_,
+            absl::StrCat(mpact::sim::riscv::RiscVState::kXregPrefix, num),
+            xreg_alias_[num]);
+      }));
+  source_op_getters_.insert(std::make_pair(
+      static_cast<int>(SourceOpEnum::kRs2),
+      [this]() -> SourceOperandInterface * {
+        int num = encoding::r_type::ExtractRs2(inst_word_);
+        if (num == 0)
+          return new mpact::sim::generic::IntLiteralOperand<0>({1},
+                                                               xreg_alias_[0]);
+        return GetRegisterSourceOp<mpact::sim::riscv::RV32Register>(
+            state_,
+            absl::StrCat(mpact::sim::riscv::RiscVState::kXregPrefix, num),
+            xreg_alias_[num]);
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kSImm12), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<int32_t>(
+            encoding::inst32_format::ExtractSImm(inst_word_));
+      }));
+  source_op_getters_.insert(
+      std::make_pair(static_cast<int>(SourceOpEnum::kUImm20), [this]() {
+        return new mpact::sim::generic::ImmediateOperand<int32_t>(
+            encoding::inst32_format::ExtractUImm(inst_word_));
+      }));
+  source_op_getters_.emplace(
+      static_cast<int>(SourceOpEnum::kVs1),
+      [this]() -> SourceOperandInterface * {
+        auto reg_num = encoding::kelvin_v2_args_type::ExtractVs1(inst_word_);
+        bool strip_mine = encoding::kelvin_v2_args_type::ExtractM(inst_word_);
+        auto form = encoding::kelvin_v2_args_type::ExtractForm(inst_word_);
+        // .xx form uses scalar xs1.
+        if (form == 3) {
+          if (reg_num == 0) {
+            return new mpact::sim::generic::IntLiteralOperand<0>(
+                {1}, xreg_alias_[0]);
+          }
+          return GetRegisterSourceOp<mpact::sim::riscv::RV32Register>(
+              state_,
+              absl::StrCat(mpact::sim::riscv::RiscVState::kXregPrefix, reg_num),
+              xreg_alias_[reg_num]);
+        }
+        return GetVectorRegisterSourceOp<mpact::sim::riscv::RVVectorRegister>(
+            state_, reg_num, strip_mine, GetSrc1WidenFactor());
+      });
+  source_op_getters_.emplace(
+      static_cast<int>(SourceOpEnum::kVs2),
+      [this]() -> SourceOperandInterface * {
+        auto reg_num = encoding::kelvin_v2_args_type::ExtractVs2(inst_word_);
+        bool strip_mine = encoding::kelvin_v2_args_type::ExtractM(inst_word_);
+        auto form = encoding::kelvin_v2_args_type::ExtractForm(inst_word_);
+        // .vx or .xx forms are using scalar xs2.
+        if (form == 2 || form == 3) {
+          if (reg_num == 0) {
+            return new mpact::sim::generic::IntLiteralOperand<0>(
+                {1}, xreg_alias_[0]);
+          }
+          return GetRegisterSourceOp<mpact::sim::riscv::RV32Register>(
+              state_,
+              absl::StrCat(mpact::sim::riscv::RiscVState::kXregPrefix, reg_num),
+              xreg_alias_[reg_num]);
+        }
+        return GetVectorRegisterSourceOp<mpact::sim::riscv::RVVectorRegister>(
+            state_, reg_num, strip_mine, 1 /* widen_factor */);
+      });
+  source_op_getters_.insert(std::make_pair(
+      static_cast<int>(SourceOpEnum::kNone), []() { return nullptr; }));
+}
+
+void KelvinEncoding::InitializeDestinationOperandGetters() {
+  // Destination operand getters.
+  dest_op_getters_.insert(
+      std::make_pair(static_cast<int>(DestOpEnum::kCsr), [this](int latency) {
+        return GetRegisterDestinationOp<mpact::sim::riscv::RV32Register>(
+            state_, KelvinState::kCsrName, latency);
+      }));
+  dest_op_getters_.insert(std::make_pair(
+      static_cast<int>(DestOpEnum::kNextPc), [this](int latency) {
+        return GetRegisterDestinationOp<mpact::sim::riscv::RV32Register>(
+            state_, KelvinState::kPcName, latency);
+      }));
+  dest_op_getters_.insert(std::make_pair(
+      static_cast<int>(DestOpEnum::kRd),
+      [this](int latency) -> DestinationOperandInterface * {
+        int num = encoding::r_type::ExtractRd(inst_word_);
+        if (num == 0) {
+          return GetRegisterDestinationOp<mpact::sim::riscv::RV32Register>(
+              state_, "X0Dest", 0, xreg_alias_[0]);
+        } else {
+          return GetRegisterDestinationOp<mpact::sim::riscv::RVFpRegister>(
+              state_, absl::StrCat(KelvinState::kXregPrefix, num), latency,
+              xreg_alias_[num]);
+        }
+      }));
+  dest_op_getters_.emplace(
+      static_cast<int>(DestOpEnum::kVd),
+      [this](int latency) -> DestinationOperandInterface * {
+        auto reg_num = encoding::kelvin_v2_args_type::ExtractVd(inst_word_);
+        bool strip_mine = encoding::kelvin_v2_args_type::ExtractM(inst_word_);
+        return GetVectorRegisterDestinationOp<
+            mpact::sim::riscv::RVVectorRegister>(state_, reg_num, strip_mine,
+                                                 IsWidenDestinationRegisterOp(),
+                                                 latency);
+      });
+  dest_op_getters_.insert(std::make_pair(
+      static_cast<int>(DestOpEnum::kVs1),
+      [this](int latency) -> DestinationOperandInterface * {
+        auto reg_num = encoding::kelvin_v2_args_type::ExtractVs1(inst_word_);
+        // Only vld.*p/vst.*p instructions are writing post incremented address
+        // to "vs1" register. And it has to be a scalar register in that case.
+        if (reg_num == 0) {
+          return GetRegisterDestinationOp<mpact::sim::riscv::RV32Register>(
+              state_, "X0Dest", 0, xreg_alias_[0]);
+        } else {
+          return GetRegisterDestinationOp<mpact::sim::riscv::RVFpRegister>(
+              state_, absl::StrCat(KelvinState::kXregPrefix, reg_num), latency,
+              xreg_alias_[reg_num]);
+        }
+      }));
+  dest_op_getters_.insert(std::make_pair(static_cast<int>(DestOpEnum::kNone),
+                                         [](int latency) { return nullptr; }));
+}
+
+// Parse the instruction word to determine the opcode.
+void KelvinEncoding::ParseInstruction(uint32_t inst_word) {
+  inst_word_ = inst_word;
+  opcode_ = encoding::DecodeKelvinInst(inst_word_);
+}
+
+DestinationOperandInterface *KelvinEncoding::GetDestination(SlotEnum, int,
+                                                            OpcodeEnum opcode,
+                                                            DestOpEnum dest_op,
+                                                            int, 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 *KelvinEncoding::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)();
+}
+
+bool KelvinEncoding::IsWidenDestinationRegisterOp() const {
+  auto func1 = encoding::kelvin_v2_args_type::ExtractFunc1(inst_word_);
+  auto func2 = encoding::kelvin_v2_args_type::ExtractFunc2(inst_word_);
+  auto func2_ignore_unsigned = func2 & (~(1u << 0));
+  // Func1 0b100 VAddw[u] and VSubw[u] need 2x destination registers.
+  if ((func1 == 0b100) &&
+      (func2_ignore_unsigned == 0b100 || func2_ignore_unsigned == 0b110)) {
+    return true;
+  }
+
+  // Func1 0b001 VMvp also needs 2x destination registers.
+  if ((func1 == 0b001) && (func2 == 0b1101)) {
+    return true;
+  }
+
+  // Func1 0b011 VMulw[u] needs 2x destination registers.
+  if ((func1 == 0b011) && (func2_ignore_unsigned == 0b0100)) {
+    return true;
+  }
+
+  // Func1 0b110 VEvnodd and VZip needs 2x destination registers.
+  if ((func1 == 0b110) && (func2 == 0b011010 || func2 == 0b011100)) {
+    return true;
+  }
+
+  return false;
+}
+
+int KelvinEncoding::GetSrc1WidenFactor() const {
+  auto func1 = encoding::kelvin_v2_args_type::ExtractFunc1(inst_word_);
+  auto func2 = encoding::kelvin_v2_args_type::ExtractFunc2(inst_word_);
+  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.
+  if ((func1 == 0b100) && (func2_ignore_unsigned == 0b1010)) {
+    return 2;
+  }
+
+  // Func1 0b010 VSrans[u][.r] also needs 2x src1 registers.
+  if ((func1 == 0b010) && (sz == 0) &&
+      (func2_ignore_unsigned == 0b010000 ||
+       func2_ignore_unsigned == 0b010010)) {
+    return 2;
+  }
+
+  // Func1 0b010 VSraqs[u][.r] needs 4x src1 registers.
+  if ((func1 == 0b010) && (sz == 0) &&
+      (func2_ignore_unsigned == 0b011000 ||
+       func2_ignore_unsigned == 0b011010)) {
+    return 4;
+  }
+
+  return 1;
+}
+
+}  // namespace kelvin::sim::isa32
diff --git a/sim/kelvin_encoding.h b/sim/kelvin_encoding.h
new file mode 100644
index 0000000..17a131b
--- /dev/null
+++ b/sim/kelvin_encoding.h
@@ -0,0 +1,116 @@
+#ifndef SIM_KELVIN_ENCODING_H_
+#define SIM_KELVIN_ENCODING_H_
+
+#include <cstdint>
+#include <string>
+
+#include "sim/kelvin_decoder.h"
+#include "sim/kelvin_enums.h"
+#include "sim/kelvin_state.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/functional/any_invocable.h"
+#include "mpact/sim/generic/simple_resource.h"
+
+namespace kelvin::sim::isa32 {
+
+// 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 KelvinEncoding : public KelvinEncodingBase {
+ public:
+  explicit KelvinEncoding(KelvinState *state);
+  ~KelvinEncoding() override;
+
+  // Parses an instruction and determines the opcode.
+  void ParseInstruction(uint32_t inst_word);
+
+  // Returns the opcode in the current instruction representation.
+  OpcodeEnum GetOpcode(SlotEnum, int) override { return opcode_; }
+
+  // There is no predicate, so return nullptr.
+  PredicateOperandInterface *GetPredicate(SlotEnum, int, OpcodeEnum,
+                                          PredOpEnum) override {
+    return nullptr;
+  }
+
+  // Return the resource operand corresponding to the resource enum. If argument
+  // is not kNone, it means that the resource enum is a pool of resources and
+  // the resource element from the pool is specified by the
+  // ResourceArgumentEnum. This is used for instance for register resources,
+  // where the resource itself is a register bank, and the argument specifies
+  // which register (or more precisely) which encoding "field" specifies the
+  // register number.
+  ResourceOperandInterface *GetSimpleResourceOperand(
+      SlotEnum, int, OpcodeEnum, SimpleResourceVector &resource_vec,
+      int end) override {
+    return nullptr;
+  }
+  ResourceOperandInterface *GetComplexResourceOperand(
+      SlotEnum, int, OpcodeEnum, ComplexResourceEnum resource, int begin,
+      int end) override {
+    return nullptr;
+  }
+
+  // The following method returns a source operand that corresponds to the
+  // particular operand field.
+  SourceOperandInterface *GetSource(SlotEnum, int, OpcodeEnum, SourceOpEnum op,
+                                    int source_no) override;
+
+  // The following method returns a destination operand that corresponds to the
+  // particular operand field.
+  DestinationOperandInterface *GetDestination(SlotEnum, int, OpcodeEnum,
+                                              DestOpEnum op, int,
+                                              int latency) override;
+
+  // This method returns latency for any destination operand for which the
+  // latency specifier in the .isa file is '*'. Since there are none, just
+  // return 0.
+  int GetLatency(SlotEnum, int, OpcodeEnum, DestOpEnum, int) override {
+    return 0;
+  }
+
+  // Getter.
+  mpact::sim::generic::SimpleResourcePool *resource_pool() const {
+    return resource_pool_;
+  }
+
+ protected:
+  using SourceOpGetterMap =
+      absl::flat_hash_map<int, absl::AnyInvocable<SourceOperandInterface *()>>;
+  using DestOpGetterMap = absl::flat_hash_map<
+      int, absl::AnyInvocable<DestinationOperandInterface *(int)>>;
+
+  const std::string xreg_alias_[32] = {
+      "zero", "ra", "sp", "gp", "tp",  "t0",  "t1", "t2", "s0", "s1", "a0",
+      "a1",   "a2", "a3", "a4", "a5",  "a6",  "a7", "s2", "s3", "s4", "s5",
+      "s6",   "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
+
+  SourceOpGetterMap &source_op_getters() { return source_op_getters_; }
+  DestOpGetterMap &dest_op_getters() { return dest_op_getters_; }
+
+  KelvinState *state() const { return state_; }
+  OpcodeEnum opcode() const { return opcode_; }
+  uint32_t inst_word() const { return inst_word_; }
+
+ private:
+  std::string GetSimpleResourceName(SimpleResourceEnum resource_enum);
+  // These methods initialize the source and destination operand getter
+  // arrays, and the complex resource getter array.
+  void InitializeSourceOperandGetters();
+  void InitializeDestinationOperandGetters();
+  bool IsWidenDestinationRegisterOp() const;
+  int GetSrc1WidenFactor() const;
+
+  SourceOpGetterMap source_op_getters_;
+  DestOpGetterMap dest_op_getters_;
+  KelvinState *state_;
+  uint32_t inst_word_;
+  OpcodeEnum opcode_;
+  mpact::sim::generic::SimpleResourcePool *resource_pool_ = nullptr;
+};
+
+}  // namespace kelvin::sim::isa32
+
+#endif  // SIM_KELVIN_ENCODING_H_
diff --git a/sim/kelvin_instructions.cc b/sim/kelvin_instructions.cc
new file mode 100644
index 0000000..357eb9b
--- /dev/null
+++ b/sim/kelvin_instructions.cc
@@ -0,0 +1,95 @@
+#include "sim/kelvin_instructions.h"
+
+#include <cstdint>
+#include <string>
+
+#include "sim/kelvin_state.h"
+
+namespace kelvin::sim {
+
+void KelvinIllegalInstruction(mpact::sim::generic::Instruction *inst) {
+  auto *state = static_cast<KelvinState *>(inst->state());
+  state->Trap(/*is_interrupt*/ false, /*trap_value*/ 0,
+              *mpact::sim::riscv::ExceptionCode::kIllegalInstruction,
+              /*epc*/ inst->address(), inst);
+}
+
+void KelvinNopInstruction(mpact::sim::generic::Instruction *inst) {}
+
+void KelvinIMpause(const mpact::sim::generic::Instruction *inst) {
+  auto *state = static_cast<KelvinState *>(inst->state());
+  state->MPause(inst);
+}
+
+// A helper function to determine if there is a \0 in a char[4] stored in
+// uint32_t
+bool WordHasZero(uint32_t data) {
+  return (((data >> 24) & 0xff) == 0) || (((data >> 16) & 0xff) == 0) ||
+         (((data >> 8) & 0xff) == 0) || ((data & 0xff) == 0);
+}
+
+// A helper function to load a string from the memory address by detecting the
+// '\0' terminator
+void KelvinStringLoadHelper(const mpact::sim::generic::Instruction *inst,
+                            std::string *out_string) {
+  auto *state = static_cast<KelvinState *>(inst->state());
+  auto addr = mpact::sim::generic::GetInstructionSource<uint32_t>(inst, 0, 0);
+  uint32_t data;
+  auto *db = state->db_factory()->Allocate<uint32_t>(1);
+  do {
+    state->LoadMemory(inst, addr, db, nullptr, nullptr);
+    data = db->Get<uint32_t>(0);
+    *out_string +=
+        std::string(reinterpret_cast<char *>(&data), sizeof(uint32_t));
+    addr += 4;
+  } while (!WordHasZero(data) && addr < state->max_physical_address());
+  // Trim the string properly.
+  out_string->resize(out_string->find('\0'));
+  db->DecRef();
+}
+
+// Handle FLOG, SLOG, CLOG, and KLOG instructions
+void KelvinLogInstruction(int log_mode,
+                          mpact::sim::generic::Instruction *inst) {
+  auto *state = static_cast<KelvinState *>(inst->state());
+  switch (log_mode) {
+    case 0: {  // Format log op to set the format of the printout and print it.
+      std::string format_string;
+      KelvinStringLoadHelper(inst, &format_string);
+      state->PrintLog(format_string);
+      break;
+    }
+    case 1: {  // Scalar log op to load an integer argument.
+      auto data =
+          mpact::sim::generic::GetInstructionSource<uint32_t>(inst, 0, 0);
+      state->SetLogArgs(data);
+      break;
+    }
+    case 2: {  // Character log op to load a group of char[4] as an argument.
+      auto data =
+          mpact::sim::generic::GetInstructionSource<uint32_t>(inst, 0, 0);
+      auto *clog_string = state->clog_string();
+      // CLOG can break a long character array as multiple CLOG calls, and they
+      // need to be combined as a single string argument.
+      *clog_string +=
+          std::string(reinterpret_cast<char *>(&data), sizeof(uint32_t));
+      if (WordHasZero(data)) {
+        // Trim the string properly.
+        clog_string->resize(clog_string->find('\0'));
+        state->SetLogArgs(*clog_string);
+        clog_string->clear();
+      }
+      break;
+    }
+    case 3: {  // String log to op load a string argument.
+      std::string str_arg;
+      KelvinStringLoadHelper(inst, &str_arg);
+      state->SetLogArgs(str_arg);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+}  // namespace kelvin::sim
diff --git a/sim/kelvin_instructions.h b/sim/kelvin_instructions.h
new file mode 100644
index 0000000..f3952ab
--- /dev/null
+++ b/sim/kelvin_instructions.h
@@ -0,0 +1,18 @@
+#ifndef SIM_KELVIN_INSTRUCTIONS_H_
+#define SIM_KELVIN_INSTRUCTIONS_H_
+
+#include "mpact/sim/generic/instruction.h"
+
+namespace kelvin::sim {
+
+void KelvinIllegalInstruction(mpact::sim::generic::Instruction *inst);
+
+void KelvinNopInstruction(mpact::sim::generic::Instruction *inst);
+
+void KelvinIMpause(const mpact::sim::generic::Instruction *inst);
+
+void KelvinLogInstruction(int log_mode, mpact::sim::generic::Instruction *inst);
+
+}  // namespace kelvin::sim
+
+#endif  // SIM_KELVIN_INSTRUCTIONS_H_
diff --git a/sim/kelvin_sim.cc b/sim/kelvin_sim.cc
new file mode 100644
index 0000000..b60a923
--- /dev/null
+++ b/sim/kelvin_sim.cc
@@ -0,0 +1,91 @@
+#include <signal.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "sim/kelvin_top.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/usage.h"
+#include "absl/log/log.h"
+#include "riscv/debug_command_shell.h"
+#include "mpact/sim/util/program_loader/elf_program_loader.h"
+
+// Flags for specifying interactive mode.
+ABSL_FLAG(bool, i, false, "Interactive mode");
+ABSL_FLAG(bool, interactive, false, "Interactive mode");
+
+// Static pointer to the top instance. Used by the control-C handler.
+static kelvin::sim::KelvinTop *top = nullptr;
+
+// Control-c handler to interrupt any running simulation.
+static void sim_sigint_handler(int arg) {
+  if (top != nullptr) {
+    (void)top->Halt();
+    return;
+  } else {
+    exit(-1);
+  }
+}
+
+int main(int argc, char **argv) {
+  absl::SetProgramUsageMessage("Kelvin MPACT-Sim based CLI tool");
+  auto out_args = absl::ParseCommandLine(argc, argv);
+  argc = out_args.size();
+  argv = &out_args[0];
+  if (argc != 2) {
+    std::cerr << "Only a single input file allowed" << std::endl;
+    return -1;
+  }
+  std::string file_name = argv[1];
+
+  kelvin::sim::KelvinTop kelvin_top("Kelvin");
+
+  // Set up control-c handling.
+  top = &kelvin_top;
+  struct sigaction sa;
+  sa.sa_flags = 0;
+  sigemptyset(&sa.sa_mask);
+  sigaddset(&sa.sa_mask, SIGINT);
+  sa.sa_handler = &sim_sigint_handler;
+  sigaction(SIGINT, &sa, nullptr);
+
+  // Load the elf segments into memory.
+  mpact::sim::util::ElfProgramLoader elf_loader(kelvin_top.memory());
+  auto load_result = elf_loader.LoadProgram(file_name);
+  if (!load_result.ok()) {
+    std::cerr << "Error while loading '" << file_name
+              << "': " << load_result.status().message();
+  }
+
+  // Initialize the PC to the entry point.
+  uint32_t entry_point = load_result.value();
+  auto pc_write = kelvin_top.WriteRegister("pc", entry_point);
+  if (!pc_write.ok()) {
+    std::cerr << "Error writing to pc: " << pc_write.message();
+  }
+
+  // Determine if this is being run interactively or as a batch job.
+  bool interactive = absl::GetFlag(FLAGS_i) || absl::GetFlag(FLAGS_interactive);
+  if (interactive) {
+    mpact::sim::riscv::DebugCommandShell cmd_shell(
+        {{&kelvin_top, &elf_loader}});
+    cmd_shell.Run(std::cin, std::cout);
+    std::cout << "Total cycles: " << kelvin_top.GetCycleCount() << std::endl;
+  } else {
+    std::cerr << "Starting simulation\n";
+
+    auto run_status = kelvin_top.Run();
+    if (!run_status.ok()) {
+      std::cerr << run_status.message() << std::endl;
+    }
+
+    auto wait_status = kelvin_top.Wait();
+    if (!wait_status.ok()) {
+      std::cerr << wait_status.message() << std::endl;
+    }
+    std::cout << "Total cycles: " << kelvin_top.GetCycleCount() << std::endl;
+    std::cerr << "Simulation done\n";
+  }
+}
diff --git a/sim/kelvin_state.cc b/sim/kelvin_state.cc
new file mode 100644
index 0000000..5fd15ca
--- /dev/null
+++ b/sim/kelvin_state.cc
@@ -0,0 +1,65 @@
+
+#include "sim/kelvin_state.h"
+
+#include <cstdint>
+#include <iostream>
+#include <string>
+
+#include "absl/log/check.h"
+#include "absl/strings/string_view.h"
+
+namespace kelvin::sim {
+
+constexpr uint32_t kVectorRegisterWidth = 32;
+
+KelvinState::KelvinState(
+    absl::string_view id, mpact::sim::riscv::RiscVXlen xlen,
+    mpact::sim::util::MemoryInterface *memory,
+    mpact::sim::util::AtomicMemoryOpInterface *atomic_memory)
+    : mpact::sim::riscv::RiscVState(id, xlen, memory, atomic_memory) {
+  set_vector_register_width(kVectorRegisterWidth);
+}
+
+KelvinState::KelvinState(absl::string_view id,
+                         mpact::sim::riscv::RiscVXlen xlen,
+                         mpact::sim::util::MemoryInterface *memory)
+    : KelvinState(id, xlen, memory, nullptr) {}
+
+KelvinState::KelvinState(absl::string_view id,
+                         mpact::sim::riscv::RiscVXlen xlen)
+    : KelvinState(id, xlen, nullptr, nullptr) {}
+
+void KelvinState::MPause(const Instruction *inst) {
+  for (auto &handler : on_mpause_) {
+    bool res = handler(inst);
+    if (res) return;
+  }
+  // Set the return address to the current instruction.
+  auto epc = (inst != nullptr) ? inst->address() : 0;
+  Trap(/*is_interrupt=*/false, 0, 3, epc, inst);
+}
+
+// Print the logging message based on log_args_.
+void KelvinState::PrintLog(absl::string_view format_string) {
+  char *print_ptr = const_cast<char *>(format_string.data());
+  while (*print_ptr) {
+    if (*print_ptr == '%') {
+      CHECK_GT(log_args_.size(), 0)
+          << "Invalid program with insufficient log argurments";
+      if (log_args_[0].type() == typeid(uint32_t)) {
+        std::cout << std::any_cast<uint32_t>(log_args_[0]);
+      }
+      if (log_args_[0].type() == typeid(std::string)) {
+        std::cout << std::any_cast<std::string>(log_args_[0]);
+      }
+      log_args_.erase(log_args_.begin());
+      print_ptr += 2;  // skip the format specifier too.
+    } else {
+      std::cout << *print_ptr++;
+    }
+  }
+  // Flush log_args_
+  log_args_.clear();
+}
+
+}  // namespace kelvin::sim
diff --git a/sim/kelvin_state.h b/sim/kelvin_state.h
new file mode 100644
index 0000000..abac4a2
--- /dev/null
+++ b/sim/kelvin_state.h
@@ -0,0 +1,66 @@
+#ifndef SIM_KELVIN_STATE_H_
+#define SIM_KELVIN_STATE_H_
+
+#include <any>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/functional/any_invocable.h"
+#include "absl/strings/string_view.h"
+#include "riscv/riscv_state.h"
+
+namespace kelvin::sim {
+
+using Instruction = ::mpact::sim::generic::Instruction;
+
+// Default to 256 to match
+// https://spacebeaker.googlesource.com/shodan/experimental-kelvin/+/refs/heads/master/tools/iss/iss.cc#18.
+inline constexpr uint32_t kVectorLengthInBits = 256;
+
+class KelvinState : public mpact::sim::riscv::RiscVState {
+ public:
+  KelvinState(absl::string_view id, mpact::sim::riscv::RiscVXlen xlen,
+              mpact::sim::util::MemoryInterface *memory,
+              mpact::sim::util::AtomicMemoryOpInterface *atomic_memory);
+  KelvinState(absl::string_view id, mpact::sim::riscv::RiscVXlen xlen,
+              mpact::sim::util::MemoryInterface *memory);
+  KelvinState(absl::string_view id, mpact::sim::riscv::RiscVXlen xlen);
+  ~KelvinState() override = default;
+
+  // Deleted Constructors and operators.
+
+  KelvinState(const KelvinState &) = delete;
+  KelvinState(KelvinState &&) = delete;
+  KelvinState &operator=(const KelvinState &) = delete;
+  KelvinState &operator=(KelvinState &&) = delete;
+
+  void set_vector_length(uint32_t length) { vector_length_ = length; }
+  uint32_t vector_length() const { return vector_length_; }
+
+  void SetLogArgs(std::any data) { log_args_.emplace_back(std::move(data)); }
+  std::string *clog_string() { return &clog_string_; }
+  void PrintLog(absl::string_view format_string);
+
+  // Extra Kelvin terminating state.
+  void MPause(const Instruction *inst);
+
+  // Add terminating state handler.
+  void AddMpauseHandler(absl::AnyInvocable<bool(const Instruction *)> handler) {
+    on_mpause_.emplace_back(std::move(handler));
+  }
+
+ private:
+  uint32_t vector_length_{kVectorLengthInBits};
+
+  // Variables to store the log arguments.
+  std::vector<std::any> log_args_;
+  std::string clog_string_;
+  // Extra state handlers
+  std::vector<absl::AnyInvocable<bool(const Instruction *)>> on_mpause_;
+};
+
+}  // namespace kelvin::sim
+
+#endif  // SIM_KELVIN_STATE_H_
diff --git a/sim/kelvin_top.cc b/sim/kelvin_top.cc
new file mode 100644
index 0000000..39b1724
--- /dev/null
+++ b/sim/kelvin_top.cc
@@ -0,0 +1,565 @@
+#include "sim/kelvin_top.h"
+
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <thread>  // NOLINT(build/c++11): built with c++17
+#include <utility>
+
+#include "sim/decoder.h"
+#include "sim/kelvin_enums.h"
+#include "sim/kelvin_state.h"
+#include "absl/flags/flag.h"
+#include "absl/functional/bind_front.h"
+#include "absl/log/check.h"
+#include "absl/log/log.h"
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
+#include "riscv/riscv_register_aliases.h"
+#include "riscv/riscv_state.h"
+#include "mpact/sim/generic/data_buffer.h"
+#include "mpact/sim/generic/decode_cache.h"
+#include "mpact/sim/generic/resource_operand_interface.h"
+#include "mpact/sim/util/memory/flat_demand_memory.h"
+
+ABSL_FLAG(bool, use_semihost, false, "Use semihost in the simulation");
+
+namespace kelvin::sim {
+
+constexpr char kKelvinName[] = "Kelvin";
+
+// Local helper function used to execute instructions.
+static inline bool ExecuteInstruction(mpact::sim::util::Instruction *inst) {
+  for (auto *resource : inst->ResourceHold()) {
+    if (!resource->IsFree()) {
+      return false;
+    }
+  }
+  for (auto *resource : inst->ResourceAcquire()) {
+    resource->Acquire();
+  }
+  // Comment out instruction logging during execution.
+  // LOG(INFO) << "[" << std::hex << inst->address() << "] " <<
+  // inst->AsString();
+
+  inst->Execute(nullptr);
+  return true;
+}
+
+KelvinTop::KelvinTop(std::string name)
+    : Component{std::move(name)},
+      counter_num_instructions_{"num_instructions", 0},
+      counter_num_cycles_{"num_cycles", 0} {
+  // Using a single flat memory for this core.
+  memory_ = new mpact::sim::util::FlatDemandMemory(0);
+  Initialize();
+}
+
+KelvinTop::~KelvinTop() {
+  // If the simulator is still running, request a halt (set halted_ to true),
+  // and wait until the simulator finishes before continuing the destructor.
+  if (run_status_ == RunStatus::kRunning) {
+    run_halted_->WaitForNotification();
+    delete run_halted_;
+  }
+
+  delete rv_bp_manager_;
+  delete decode_cache_;
+  delete kelvin_decoder_;
+  delete state_;
+  delete fp_state_;
+  delete watcher_;
+  delete memory_;
+  delete semihost_;
+}
+
+void KelvinTop::Initialize() {
+  // Create the simulation state
+  state_ = new sim::KelvinState(kKelvinName, mpact::sim::riscv::RiscVXlen::RV32,
+                                memory_);
+  fp_state_ = new mpact::sim::riscv::RiscVFPState(state_);
+  state_->set_rv_fp(fp_state_);
+  pc_ = state_->registers()->at(sim::KelvinState::kPcName);
+  // Set up the decoder and decode cache.
+  kelvin_decoder_ = new sim::KelvinDecoder(state_, memory_);
+  for (int i = 0; i < static_cast<int>(isa32::OpcodeEnum::kPastMaxValue); i++) {
+    counter_opcode_[i].Initialize(absl::StrCat("num_", isa32::kOpcodeNames[i]),
+                                  0);
+    CHECK_OK(AddCounter(&counter_opcode_[i]));
+  }
+  decode_cache_ =
+      mpact::sim::generic::DecodeCache::Create({16 * 1024, 2}, kelvin_decoder_);
+  CHECK(decode_cache_) << "Failed to create decode cache";
+  // Register instruction counter.
+  CHECK_OK(AddCounter(&counter_num_instructions_))
+      << "Failed to register counter";
+  rv_bp_manager_ = new mpact::sim::riscv::RiscVBreakpointManager(
+      memory_, absl::bind_front(&mpact::sim::generic::DecodeCache::Invalidate,
+                                decode_cache_));
+  // Make sure the architectural and abi register aliases are added.
+  std::string reg_name;
+  for (int i = 0; i < 32; i++) {
+    reg_name = absl::StrCat(sim::KelvinState::kXregPrefix, i);
+    (void)state_->AddRegister<mpact::sim::riscv::RV32Register>(reg_name);
+    (void)state_->AddRegisterAlias<mpact::sim::riscv::RV32Register>(
+        reg_name, mpact::sim::riscv::kXRegisterAliases[i]);
+  }
+  for (int i = 0; i < 32; i++) {
+    reg_name = absl::StrCat(sim::KelvinState::kFregPrefix, i);
+    (void)state_->AddRegister<mpact::sim::riscv::RVFpRegister>(reg_name);
+    (void)state_->AddRegisterAlias<mpact::sim::riscv::RVFpRegister>(
+        reg_name, mpact::sim::riscv::kFRegisterAliases[i]);
+  }
+
+  semihost_ = new mpact::sim::riscv::RiscVArmSemihost(
+      mpact::sim::riscv::RiscVArmSemihost::BitWidth::kWord32, memory_, memory_);
+  // Set the software breakpoint callback.
+  state_->AddEbreakHandler([this](const mpact::sim::generic::Instruction *inst)
+                               -> bool {
+    if (inst != nullptr) {
+      if (absl::GetFlag(FLAGS_use_semihost) &&
+          semihost_->IsSemihostingCall(inst)) {
+        semihost_->OnEBreak(inst);
+      } else if (absl::GetFlag(FLAGS_use_semihost)) {  // Software breakpoint.
+        RequestHalt(HaltReason::kSoftwareBreakpoint, inst);
+      } else {  // The default Kelvin simulation mode.
+        std::cout << "Hit breakpoint or program exits with fault" << std::endl;
+        RequestHalt(HaltReason::kSoftwareBreakpoint, inst);
+      }
+      return true;
+    }
+    return false;
+  });
+
+  state_->AddMpauseHandler(
+      [this](const mpact::sim::generic::Instruction *inst) -> bool {
+        if (inst != nullptr) {  // Software breakpoint
+          std::cout << "Program exits properly" << std::endl;
+          RequestHalt(HaltReason::kSoftwareBreakpoint, inst);
+          return true;
+        }
+        return false;
+      });
+
+  // Set illegal instruction callback.
+  state_->set_on_trap([this](bool is_interrupt, uint64_t trap_value,
+                             uint64_t exception_code, uint64_t epc,
+                             const Instruction *inst) -> bool {
+    if (exception_code ==
+        static_cast<uint64_t>(
+            mpact::sim::riscv::ExceptionCode::kIllegalInstruction)) {
+      std::cerr << "Illegal instruction at 0x" << std::hex << epc << std::endl;
+      RequestHalt(HaltReason::kSoftwareBreakpoint, nullptr);
+      return true;
+    }
+    return false;
+  });
+
+  semihost_->set_exit_callback(
+      [this]() { RequestHalt(HaltReason::kSemihostHaltRequest, nullptr); });
+}
+
+absl::Status KelvinTop::Halt() {
+  // If it is already halted, just return.
+  if (run_status_ == RunStatus::kHalted) {
+    return absl::OkStatus();
+  }
+  // If it is not running, then there's an error.
+  if (run_status_ != RunStatus::kRunning) {
+    return absl::FailedPreconditionError(
+        "KelvinTop::Halt: Core is not running");
+  }
+  halt_reason_ = HaltReason::kUserRequest;
+  halted_ = true;
+  return absl::OkStatus();
+}
+
+absl::Status KelvinTop::StepPastBreakpoint() {
+  uint64_t pc = state_->pc_operand()->AsUint64(0);
+  uint64_t bpt_pc = pc;
+  // Disable the breakpoint. Status will show error if there is no breakpoint.
+  auto status = rv_bp_manager_->DisableBreakpoint(pc);
+  // Execute the real instruction.
+  auto real_inst = decode_cache_->GetDecodedInstruction(pc);
+  real_inst->IncRef();
+  auto next_seq_pc = pc + real_inst->size();
+  SetPc(next_seq_pc);
+  bool executed = false;
+  do {
+    executed = ExecuteInstruction(real_inst);
+    counter_num_cycles_.Increment(1);
+    state_->AdvanceDelayLines();
+  } while (!executed);
+  // Increment counter.
+  counter_opcode_[real_inst->opcode()].Increment(1);
+  counter_num_instructions_.Increment(1);
+  real_inst->DecRef();
+  // Re-enable the breakpoint.
+  if (status.ok()) {
+    status = rv_bp_manager_->EnableBreakpoint(bpt_pc);
+    if (!status.ok()) return status;
+  }
+  return absl::OkStatus();
+}
+
+absl::StatusOr<int> KelvinTop::Step(int num) {
+  if (num <= 0) {
+    return absl::InvalidArgumentError("Step count must be > 0");
+  }
+  // If the simulator is running, return with an error.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError(
+        "KelvinTop::Step: Core must be halted");
+  }
+  run_status_ = RunStatus::kSingleStep;
+  int count = 0;
+  halted_ = false;
+  // First check to see if the previous halt was due to a breakpoint. If so,
+  // need to step over the breakpoint.
+  if (halt_reason_ == HaltReason::kSoftwareBreakpoint) {
+    halt_reason_ = HaltReason::kNone;
+    auto status = StepPastBreakpoint();
+    if (!status.ok()) return status;
+    count++;
+  }
+
+  // Step the simulator forward until the number of steps have been achieved, or
+  // there is a halt request.
+  auto pc_operand = state_->pc_operand();
+  // This holds the value of the current pc, and post-loop, the address of
+  // the most recently executed instruction.
+  uint64_t pc;
+  // At the top of the loop this holds the address of the instruction to be
+  // executed next. Post-loop it holds the address of the next instruction to
+  // be executed.
+  uint64_t next_pc = pc_operand->AsUint64(0);
+  uint64_t next_seq_pc;
+  while (!halted_ && (count < num)) {
+    pc = next_pc;
+    auto *inst = decode_cache_->GetDecodedInstruction(pc);
+    next_seq_pc = pc + inst->size();
+    // Set the PC destination operand to next_seq_pc. Any branch that is
+    // executed will overwrite this.
+    SetPc(next_seq_pc);
+    bool executed = false;
+    do {
+      executed = ExecuteInstruction(inst);
+      counter_num_cycles_.Increment(1);
+      state_->AdvanceDelayLines();
+    } while (!executed);
+    count++;
+    // Update counters.
+    counter_opcode_[inst->opcode()].Increment(1);
+    counter_num_instructions_.Increment(1);
+    // Get the next pc value.
+    next_pc = pc_operand->AsUint64(0);
+  }
+  // Update the pc register, now that it can be read.
+  if (halt_reason_ == HaltReason::kSoftwareBreakpoint) {
+    // If at a breakpoint, keep the pc at the current value.
+    SetPc(pc);
+  } else {
+    // Otherwise set it to point to the next instruction.
+    SetPc(next_pc);
+  }
+  // If there is no halt request, there is no specific halt reason.
+  if (!halted_) {
+    halt_reason_ = HaltReason::kNone;
+  }
+  run_status_ = RunStatus::kHalted;
+  return count;
+}
+
+absl::Status KelvinTop::Run() {
+  // Verify that the core isn't running already.
+  if (run_status_ == RunStatus::kRunning) {
+    return absl::FailedPreconditionError(
+        "KelvinTop::Run: core is already running");
+  }
+  // First check to see if the previous halt was due to a breakpoint. If so,
+  // need to step over the breakpoint.
+  if (halt_reason_ == HaltReason::kSoftwareBreakpoint) {
+    halt_reason_ = HaltReason::kNone;
+    auto status = StepPastBreakpoint();
+    if (!status.ok()) return status;
+  }
+  run_status_ = RunStatus::kRunning;
+  halted_ = false;
+
+  // The simulator is now run in a separate thread so as to allow a user
+  // interface to continue operating. Allocate a new run_halted_ Notification
+  // object, as they are single used only.
+  run_halted_ = new absl::Notification();
+  // The thread is detached so it executes without having to be joined.
+  std::thread([this]() {
+    auto pc_operand = state_->pc_operand();
+    // This holds the value of the current pc, and post-loop, the address of
+    // the most recently executed instruction.
+    uint64_t pc;
+    // At the top of the loop this holds the address of the instruction to be
+    // executed next. Post-loop it holds the address of the next instruction to
+    // be executed.
+    uint64_t next_pc = pc_operand->AsUint64(0);
+    uint64_t next_seq_pc;
+    while (!halted_) {
+      pc = next_pc;
+      auto *inst = decode_cache_->GetDecodedInstruction(pc);
+      next_seq_pc = pc + inst->size();
+      // Set the PC destination operand to next_seq_pc. Any branch that is
+      // executed will overwrite this.
+      SetPc(next_seq_pc);
+      bool executed = false;
+      do {
+        executed = ExecuteInstruction(inst);
+        counter_num_cycles_.Increment(1);
+        state_->AdvanceDelayLines();
+      } while (!executed);
+      // Update counters.
+      counter_opcode_[inst->opcode()].Increment(1);
+      counter_num_instructions_.Increment(1);
+      // Get the next pc value.
+      next_pc = pc_operand->AsUint64(0);
+    }
+    // Update the pc register, now that it can be read (since we are not
+    // running).
+    if (halt_reason_ == HaltReason::kSoftwareBreakpoint) {
+      // If at a breakpoint, keep the pc at the current value.
+      SetPc(pc);
+    } else {
+      // Otherwise set it to point to the next instruction.
+      SetPc(next_pc);
+    }
+    run_status_ = RunStatus::kHalted;
+    // Notify that the run has completed.
+    run_halted_->Notify();
+  }).detach();
+  return absl::OkStatus();
+}
+
+absl::Status KelvinTop::Wait() {
+  // If the simulator isn't running, then just return.
+  if (run_status_ != RunStatus::kRunning) return absl::OkStatus();
+
+  // Wait for the simulator to finish (i.e., a value is available on the
+  // channel).
+  run_halted_->WaitForNotification();
+  delete run_halted_;
+  run_halted_ = nullptr;
+  return absl::OkStatus();
+}
+
+absl::StatusOr<KelvinTop::RunStatus> KelvinTop::GetRunStatus() {
+  return run_status_;
+}
+
+absl::StatusOr<KelvinTop::HaltReason> KelvinTop::GetLastHaltReason() {
+  return halt_reason_;
+}
+
+absl::StatusOr<uint64_t> KelvinTop::ReadRegister(const std::string &name) {
+  // The registers aren't protected by a mutex, so let's not read them while
+  // the simulator is running.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError("ReadRegister: Core must be halted");
+  }
+  auto iter = state_->registers()->find(name);
+
+  // Was the register found? If not try CSRs.
+  if (iter == state_->registers()->end()) {
+    auto result = state_->csr_set()->GetCsr(name);
+    if (!result.ok()) {
+      return absl::NotFoundError(
+          absl::StrCat("Register '", name, "' not found"));
+    }
+    auto *csr = *result;
+    return csr->GetUint32();
+  }
+
+  auto *db = (iter->second)->data_buffer();
+  uint64_t value;
+  switch (db->size<uint8_t>()) {
+    case 1:
+      value = static_cast<uint64_t>(db->Get<uint8_t>(0));
+      break;
+    case 2:
+      value = static_cast<uint64_t>(db->Get<uint16_t>(0));
+      break;
+    case 4:
+      value = static_cast<uint64_t>(db->Get<uint32_t>(0));
+      break;
+    case 8:
+      value = static_cast<uint64_t>(db->Get<uint64_t>(0));
+      break;
+    default:
+      return absl::InternalError("Register size is not 1, 2, 4, or 8 bytes");
+  }
+  return value;
+}
+
+absl::Status KelvinTop::WriteRegister(const std::string &name, uint64_t value) {
+  // The registers aren't protected by a mutex, so let's not write them while
+  // the simulator is running.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError("WriteRegister: Core must be halted");
+  }
+  auto iter = state_->registers()->find(name);
+  // Was the register found? If not try CSRs.
+  if (iter == state_->registers()->end()) {
+    auto result = state_->csr_set()->GetCsr(name);
+    if (!result.ok()) {
+      return absl::NotFoundError(
+          absl::StrCat("Register '", name, "' not found"));
+    }
+    auto *csr = *result;
+    csr->Set(static_cast<uint32_t>(value));
+    return absl::OkStatus();
+  }
+
+  // If stopped at a software breakpoint and the pc is changed, change the
+  // halt reason, since the next instruction won't be where we stopped.
+  if ((name == "pc") && (halt_reason_ == HaltReason::kSoftwareBreakpoint)) {
+    halt_reason_ = HaltReason::kNone;
+  }
+
+  auto *db = (iter->second)->data_buffer();
+  switch (db->size<uint8_t>()) {
+    case 1:
+      db->Set<uint8_t>(0, static_cast<uint8_t>(value));
+      break;
+    case 2:
+      db->Set<uint16_t>(0, static_cast<uint16_t>(value));
+      break;
+    case 4:
+      db->Set<uint32_t>(0, static_cast<uint32_t>(value));
+      break;
+    case 8:
+      db->Set<uint64_t>(0, static_cast<uint64_t>(value));
+      break;
+    default:
+      return absl::InternalError("Register size is not 1, 2, 4, or 8 bytes");
+  }
+  return absl::OkStatus();
+}
+
+absl::StatusOr<size_t> KelvinTop::ReadMemory(uint64_t address, void *buffer,
+                                             size_t length) {
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError("ReadMemory: Core must be halted");
+  }
+  auto *db = db_factory_.Allocate(length);
+  // Load bypassing any watch points/semihosting.
+  state_->memory()->Load(address, db, nullptr, nullptr);
+  std::memcpy(buffer, db->raw_ptr(), length);
+  db->DecRef();
+  return length;
+}
+
+absl::StatusOr<size_t> KelvinTop::WriteMemory(uint64_t address,
+                                              const void *buffer,
+                                              size_t length) {
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError("WriteMemory: Core must be halted");
+  }
+  auto *db = db_factory_.Allocate(length);
+  std::memcpy(db->raw_ptr(), buffer, length);
+  // Store bypassing any watch points/semihosting.
+  state_->memory()->Store(address, db);
+  db->DecRef();
+  return length;
+}
+
+bool KelvinTop::HasBreakpoint(uint64_t address) {
+  return rv_bp_manager_->HasBreakpoint(address);
+}
+
+absl::Status KelvinTop::SetSwBreakpoint(uint64_t address) {
+  // Don't try if the simulator is running.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError(
+        "SetSwBreakpoint: Core must be halted");
+  }
+  // If there is no breakpoint manager, return an error.
+  if (rv_bp_manager_ == nullptr) {
+    return absl::InternalError("Breakpoints are not enabled");
+  }
+  // Try setting the breakpoint.
+  return rv_bp_manager_->SetBreakpoint(address);
+}
+
+absl::Status KelvinTop::ClearSwBreakpoint(uint64_t address) {
+  // Don't try if the simulator is running.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError(
+        "ClearSwBreakpoing: Core must be halted");
+  }
+  if (rv_bp_manager_ == nullptr) {
+    return absl::InternalError("Breakpoints are not enabled");
+  }
+  return rv_bp_manager_->ClearBreakpoint(address);
+}
+
+absl::Status KelvinTop::ClearAllSwBreakpoints() {
+  // Don't try if the simulator is running.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError(
+        "ClearAllSwBreakpoints: Core must be halted");
+  }
+  if (rv_bp_manager_ == nullptr) {
+    return absl::InternalError("Breakpoints are not enabled");
+  }
+  rv_bp_manager_->ClearAllBreakpoints();
+  return absl::OkStatus();
+}
+
+absl::StatusOr<mpact::sim::generic::Instruction *> KelvinTop::GetInstruction(
+    uint64_t address) {
+  auto inst = decode_cache_->GetDecodedInstruction(address);
+  return inst;
+}
+
+absl::StatusOr<std::string> KelvinTop::GetDisassembly(uint64_t address) {
+  // Don't try if the simulator is running.
+  if (run_status_ != RunStatus::kHalted) {
+    return absl::FailedPreconditionError("GetDissasembly: Core must be halted");
+  }
+
+  mpact::sim::generic::Instruction *inst = nullptr;
+  // If requesting the disassembly for an instruction at a breakpoint, return
+  // that of the original instruction instead.
+  if (rv_bp_manager_->IsBreakpoint(address)) {
+    auto bp_pc = address;
+    // Disable the breakpoint.
+    auto status = rv_bp_manager_->DisableBreakpoint(bp_pc);
+    if (!status.ok()) return status;
+    // Get the real instruction.
+    inst = decode_cache_->GetDecodedInstruction(bp_pc);
+    auto disasm = inst != nullptr ? inst->AsString() : "Invalid instruction";
+    // Re-enable the breakpoint.
+    status = rv_bp_manager_->EnableBreakpoint(bp_pc);
+    if (!status.ok()) return status;
+    return disasm;
+  }
+
+  // If not at the breakpoint, or requesting a different instruction,
+  inst = decode_cache_->GetDecodedInstruction(address);
+  auto disasm = inst != nullptr ? inst->AsString() : "Invalid instruction";
+  return disasm;
+}
+
+void KelvinTop::RequestHalt(HaltReason halt_reason,
+                            const mpact::sim::generic::Instruction *inst) {
+  // First set the halt_reason_, then the half flag.
+  halt_reason_ = halt_reason;
+  halted_ = true;
+}
+
+void KelvinTop::SetPc(uint64_t value) {
+  if (pc_->data_buffer()->size<uint8_t>() == 4) {
+    pc_->data_buffer()->Set<uint32_t>(0, static_cast<uint32_t>(value));
+  } else {
+    pc_->data_buffer()->Set<uint64_t>(0, value);
+  }
+}
+
+}  // namespace kelvin::sim
diff --git a/sim/kelvin_top.h b/sim/kelvin_top.h
new file mode 100644
index 0000000..e562e3b
--- /dev/null
+++ b/sim/kelvin_top.h
@@ -0,0 +1,120 @@
+#ifndef SIM_KELVIN_TOP_H_
+#define SIM_KELVIN_TOP_H_
+
+#include <cstdint>
+#include <string>
+
+#include "sim/kelvin_enums.h"
+#include "sim/kelvin_state.h"
+#include "absl/flags/declare.h"
+#include "absl/synchronization/notification.h"
+#include "riscv/riscv_arm_semihost.h"
+#include "riscv/riscv_breakpoint.h"
+#include "riscv/riscv_fp_state.h"
+#include "mpact/sim/generic/component.h"
+#include "mpact/sim/generic/core_debug_interface.h"
+#include "mpact/sim/generic/decode_cache.h"
+#include "mpact/sim/generic/decoder_interface.h"
+#include "mpact/sim/generic/register.h"
+#include "mpact/sim/util/memory/memory_interface.h"
+#include "mpact/sim/util/memory/memory_watcher.h"
+
+ABSL_DECLARE_FLAG(bool, use_semihost);
+
+namespace kelvin::sim {
+
+// Top level class for the Kelvin simulator. This is the main interface for
+// interacting and controlling execution of programs running on the simulator.
+// This class brings together the decoder, the architecture state, and control.
+class KelvinTop : public mpact::sim::generic::Component,
+                  public mpact::sim::generic::CoreDebugInterface {
+ public:
+  using RunStatus = mpact::sim::generic::CoreDebugInterface::RunStatus;
+  using HaltReason = mpact::sim::generic::CoreDebugInterface::HaltReason;
+
+  explicit KelvinTop(std::string name);
+  ~KelvinTop() override;
+
+  // Methods inherited from CoreDebugInterface.
+  absl::Status Halt() override;
+  absl::StatusOr<int> Step(int num) override;
+  absl::Status Run() override;
+  absl::Status Wait() override;
+
+  absl::StatusOr<RunStatus> GetRunStatus() override;
+  absl::StatusOr<HaltReason> GetLastHaltReason() override;
+
+  // Register access by register name.
+  absl::StatusOr<uint64_t> ReadRegister(const std::string &name) override;
+  absl::Status WriteRegister(const std::string &name, uint64_t value) override;
+
+  // Read and Write memory methods bypass any semihosting.
+  absl::StatusOr<size_t> ReadMemory(uint64_t address, void *buf,
+                                    size_t length) override;
+  absl::StatusOr<size_t> WriteMemory(uint64_t address, const void *buf,
+                                     size_t length) override;
+
+  bool HasBreakpoint(uint64_t address) override;
+  absl::Status SetSwBreakpoint(uint64_t address) override;
+  absl::Status ClearSwBreakpoint(uint64_t address) override;
+  absl::Status ClearAllSwBreakpoints() override;
+
+  // Return the instruction object for the instruction at the given address.
+  absl::StatusOr<mpact::sim::generic::Instruction *> GetInstruction(
+      uint64_t address) override;
+  // Return the string representation for the instruction at the given address.
+  absl::StatusOr<std::string> GetDisassembly(uint64_t address) override;
+
+  // Called when a halt is requested.
+  void RequestHalt(HaltReason halt_reason,
+                   const mpact::sim::generic::Instruction *inst);
+
+  // Accessors.
+  sim::KelvinState *state() const { return state_; }
+  mpact::sim::util::MemoryInterface *memory() const { return memory_; }
+
+  // Cycle helper function
+  uint64_t GetCycleCount() const { return counter_num_cycles_.GetValue(); }
+
+ private:
+  // Initialize the top.
+  void Initialize();
+  // Helper method to step past a breakpoint.
+  absl::Status StepPastBreakpoint();
+  // Set the pc value.
+  void SetPc(uint64_t value);
+
+  // The DB factory is used to manage data buffers for memory read/writes.
+  mpact::sim::generic::DataBufferFactory db_factory_;
+  // Current status and last halt reasons.
+  RunStatus run_status_ = RunStatus::kHalted;
+  HaltReason halt_reason_ = HaltReason::kNone;
+  // Halting flag. This is set to true when execution must halt.
+  bool halted_ = false;
+  absl::Notification *run_halted_;
+  // The local Kelvin state.
+  sim::KelvinState *state_;
+  mpact::sim::riscv::RiscVFPState *fp_state_;
+  // Breakpoint manager.
+  mpact::sim::riscv::RiscVBreakpointManager *rv_bp_manager_ = nullptr;
+  // The pc register instance.
+  mpact::sim::generic::RegisterBase *pc_;
+  // Kelvin decoder decoder instance.
+  mpact::sim::generic::DecoderInterface *kelvin_decoder_ = nullptr;
+  // Decode cache, memory and memory watcher.
+  mpact::sim::generic::DecodeCache *decode_cache_ = nullptr;
+  mpact::sim::util::MemoryInterface *memory_ = nullptr;
+  mpact::sim::util::MemoryWatcher *watcher_ = nullptr;
+  // Counter for the number of instructions simulated.
+  mpact::sim::generic::SimpleCounter<uint64_t>
+      counter_opcode_[static_cast<int>(sim::isa32::OpcodeEnum::kPastMaxValue)];
+  mpact::sim::generic::SimpleCounter<uint64_t> counter_num_instructions_;
+  mpact::sim::generic::SimpleCounter<uint64_t> counter_num_cycles_;
+  absl::flat_hash_map<uint32_t, std::string> register_id_map_;
+  // Setup arm semihosting.
+  mpact::sim::riscv::RiscVArmSemihost *semihost_ = nullptr;
+};
+
+}  // namespace kelvin::sim
+
+#endif  // SIM_KELVIN_TOP_H_
diff --git a/sim/kelvin_vector_instructions.cc b/sim/kelvin_vector_instructions.cc
new file mode 100644
index 0000000..33e6401
--- /dev/null
+++ b/sim/kelvin_vector_instructions.cc
@@ -0,0 +1,1264 @@
+#include "sim/kelvin_vector_instructions.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+#include <limits>
+#include <type_traits>
+
+#include "sim/kelvin_state.h"
+#include "absl/functional/bind_front.h"
+#include "absl/numeric/bits.h"
+#include "absl/types/span.h"
+#include "riscv/riscv_register.h"
+#include "mpact/sim/generic/data_buffer.h"
+#include "mpact/sim/generic/instruction.h"
+
+namespace kelvin::sim {
+
+using mpact::sim::generic::DataBuffer;
+using mpact::sim::generic::GetInstructionSource;
+using mpact::sim::generic::Instruction;
+using mpact::sim::riscv::RV32VectorDestinationOperand;
+
+template <typename Vd, typename Vs1, typename Vs2>
+Vd BinaryOpInvoke(std::function<Vd(Vs1, Vs2)> op, Vd vd, Vs1 vs1, Vs2 vs2) {
+  return op(vs1, vs2);
+}
+template <typename Vd, typename Vs1, typename Vs2>
+Vd BinaryOpInvoke(std::function<Vd(Vd, Vs1, Vs2)> op, Vd vd, Vs1 vs1, Vs2 vs2) {
+  return op(vd, vs1, vs2);
+}
+
+template <typename Vd, typename Vs1, typename Vs2>
+Vs1 CommonBinaryOpGetArg1(const Instruction *inst, bool scalar, int num_ops,
+                          int op_index, int dst_element_index,
+                          int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(Vs1);
+  auto src_element_index = op_index * elts_per_register +
+                           dst_element_index * sizeof(Vd) / sizeof(Vs1);
+  if (sizeof(Vd) == sizeof(Vs1) && sizeof(Vs1) == 2 * sizeof(Vs2)) {
+    // special case for VAcc instructions, which uses double the amount
+    // of registers for Vs1, because it's 2x the size of Vs2.
+    src_element_index += num_ops * elts_per_register * dst_reg_index;
+  } else {
+    src_element_index += dst_reg_index;
+  }
+  return GetInstructionSource<Vs1>(inst, 0, src_element_index);
+}
+
+template <typename Vd, typename Vs1, typename Vs2>
+Vs2 CommonBinaryOpGetArg2(const Instruction *inst, bool scalar, int num_ops,
+                          int op_index, int dst_element_index,
+                          int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(Vs2);
+  auto src_element_index = op_index * elts_per_register +
+                           dst_element_index * sizeof(Vd) / sizeof(Vs2) +
+                           dst_reg_index;
+  return GetInstructionSource<Vs2>(inst, 1, scalar ? 0 : src_element_index);
+}
+
+template <typename T, typename Vd, typename Vs1, typename Vs2>
+using SourceArgGetter =
+    std::function<T(const Instruction *inst, bool scalar, int num_ops,
+                    int op_index, int dst_element_index, int dst_reg_index)>;
+
+template <bool halftype = false, bool widen_dst = false, typename Vd,
+          typename Vs1, typename Vs2, typename... VDArgs>
+void KelvinBinaryVectorOp(const Instruction *inst, bool scalar, bool strip_mine,
+                          std::function<Vd(VDArgs..., Vs1, Vs2)> op,
+                          SourceArgGetter<Vs1, Vd, Vs1, Vs2> arg1_getter =
+                              CommonBinaryOpGetArg1<Vd, Vs1, Vs2>,
+                          SourceArgGetter<Vs2, Vd, Vs1, Vs2> arg2_getter =
+                              CommonBinaryOpGetArg2<Vd, Vs1, Vs2>) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_dest_register = vector_size_in_bytes / sizeof(Vd);
+
+  // For kelvin, stripmining issues 4 contiguous vector ops.
+  auto num_ops = strip_mine ? 4 : 1;
+  constexpr bool is_widen_op =
+      (sizeof(Vd) > sizeof(Vs2) && !halftype) || widen_dst;
+  // Widening requires 2 destination regs per op.
+  constexpr size_t dest_regs_per_op = is_widen_op ? 2 : 1;
+  // Special case for VADD3 op which is adding dest value to vs1 + vs2.
+  constexpr bool is_reading_dest = sizeof...(VDArgs) == 1;
+  auto vd = static_cast<RV32VectorDestinationOperand *>(inst->Destination(0));
+
+  for (int op_index = 0; op_index < num_ops; ++op_index) {
+    DataBuffer *dest_db[dest_regs_per_op];
+    absl::Span<Vd> dest_span[dest_regs_per_op];
+
+    for (int i = 0; i < dest_regs_per_op; ++i) {
+      dest_db[i] = is_reading_dest
+                       ? vd->CopyDataBuffer(op_index + i * num_ops)
+                       : vd->AllocateDataBuffer(op_index + i * num_ops);
+      dest_span[i] = dest_db[i]->template Get<Vd>();
+    }
+
+    for (int dst_element_index = 0; dst_element_index < elts_per_dest_register;
+         ++dst_element_index) {
+      for (int dst_reg_index = 0; dst_reg_index < dest_regs_per_op;
+           ++dst_reg_index) {
+        auto arg1 = arg1_getter(inst, scalar, num_ops, op_index,
+                                dst_element_index, dst_reg_index);
+        auto arg2 = arg2_getter(inst, scalar, num_ops, op_index,
+                                dst_element_index, dst_reg_index);
+        dest_span[dst_reg_index][dst_element_index] = BinaryOpInvoke(
+            op, dest_span[dst_reg_index][dst_element_index], arg1, arg2);
+      }
+    }
+
+    for (int i = 0; i < dest_regs_per_op; ++i) {
+      dest_db[i]->Submit();
+    }
+  }
+}
+
+template <typename Vd, typename Vs>
+void KelvinUnaryVectorOp(const Instruction *inst, bool strip_mine,
+                         std::function<Vd(Vs)> op,
+                         SourceArgGetter<Vs, Vd, Vs, Vs> arg_getter =
+                             CommonBinaryOpGetArg1<Vd, Vs, Vs>) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_dest_register = vector_size_in_bytes / sizeof(Vd);
+
+  // For kelvin, stripmining issues 4 contiguous vector ops.
+  auto num_ops = strip_mine ? 4 : 1;
+  auto vd = static_cast<RV32VectorDestinationOperand *>(inst->Destination(0));
+
+  for (int op_index = 0; op_index < num_ops; ++op_index) {
+    DataBuffer *dest_db = vd->AllocateDataBuffer(op_index);
+    absl::Span<Vd> dest_span = dest_db->template Get<Vd>();
+
+    for (int dst_element_index = 0; dst_element_index < elts_per_dest_register;
+         ++dst_element_index) {
+      auto arg = arg_getter(inst, false /* scalar */, num_ops, op_index,
+                            dst_element_index, 0 /* dst_reg_index */);
+      dest_span[dst_element_index] = op(arg);
+    }
+
+    dest_db->Submit();
+  }
+}
+
+template <typename T>
+void KelvinVAdd(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return vs1 + vs2.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 + vs2; }));
+}
+template void KelvinVAdd<int8_t>(bool, bool, Instruction *);
+template void KelvinVAdd<int16_t>(bool, bool, Instruction *);
+template void KelvinVAdd<int32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVSub(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return vs1 - vs2.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 - vs2; }));
+}
+template void KelvinVSub<int8_t>(bool, bool, Instruction *);
+template void KelvinVSub<int16_t>(bool, bool, Instruction *);
+template void KelvinVSub<int32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVRSub(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return vs2 - vs1.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs2 - vs1; }));
+}
+template void KelvinVRSub<int8_t>(bool, bool, Instruction *);
+template void KelvinVRSub<int16_t>(bool, bool, Instruction *);
+template void KelvinVRSub<int32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVEq(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return 1 if vs1 and vs2 are equal, else returns 0.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 == vs2; }));
+}
+template void KelvinVEq<int8_t>(bool, bool, Instruction *);
+template void KelvinVEq<int16_t>(bool, bool, Instruction *);
+template void KelvinVEq<int32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVNe(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return 1 if vs1 and vs2 are not equal, else return 0.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 != vs2; }));
+}
+template void KelvinVNe<int8_t>(bool, bool, Instruction *);
+template void KelvinVNe<int16_t>(bool, bool, Instruction *);
+template void KelvinVNe<int32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVLt(bool scalar, bool strip_mine, Instruction *inst) {
+  // Returns 1 if vs1 < vs2, else return 0.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 < vs2; }));
+}
+template void KelvinVLt<int8_t>(bool, bool, Instruction *);
+template void KelvinVLt<int16_t>(bool, bool, Instruction *);
+template void KelvinVLt<int32_t>(bool, bool, Instruction *);
+template void KelvinVLt<uint8_t>(bool, bool, Instruction *);
+template void KelvinVLt<uint16_t>(bool, bool, Instruction *);
+template void KelvinVLt<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVLe(bool scalar, bool strip_mine, Instruction *inst) {
+  // Returns 1 if vs1 <= vs2, else return 0.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 <= vs2; }));
+}
+template void KelvinVLe<int8_t>(bool, bool, Instruction *);
+template void KelvinVLe<int16_t>(bool, bool, Instruction *);
+template void KelvinVLe<int32_t>(bool, bool, Instruction *);
+template void KelvinVLe<uint8_t>(bool, bool, Instruction *);
+template void KelvinVLe<uint16_t>(bool, bool, Instruction *);
+template void KelvinVLe<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVGt(bool scalar, bool strip_mine, Instruction *inst) {
+  // Returns 1 if vs1 > vs2, else return 0.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 > vs2; }));
+}
+template void KelvinVGt<int8_t>(bool, bool, Instruction *);
+template void KelvinVGt<int16_t>(bool, bool, Instruction *);
+template void KelvinVGt<int32_t>(bool, bool, Instruction *);
+template void KelvinVGt<uint8_t>(bool, bool, Instruction *);
+template void KelvinVGt<uint16_t>(bool, bool, Instruction *);
+template void KelvinVGt<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVGe(bool scalar, bool strip_mine, Instruction *inst) {
+  // Returns 1 if vs1 >= vs2, else return 0.
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 >= vs2; }));
+}
+template void KelvinVGe<int8_t>(bool, bool, Instruction *);
+template void KelvinVGe<int16_t>(bool, bool, Instruction *);
+template void KelvinVGe<int32_t>(bool, bool, Instruction *);
+template void KelvinVGe<uint8_t>(bool, bool, Instruction *);
+template void KelvinVGe<uint16_t>(bool, bool, Instruction *);
+template void KelvinVGe<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVAbsd(bool scalar, bool strip_mine, Instruction *inst) {
+  // Returns the absolute difference between vs1 and vs2.
+  // Note: for signed(INTx_MAX - INTx_MIN) the result will be UINTx_MAX.
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */,
+                       typename std::make_unsigned<T>::type, T, T>(
+      inst, scalar, strip_mine,
+      std::function<typename std::make_unsigned<T>::type(T, T)>(
+          [](T vs1, T vs2) -> typename std::make_unsigned<T>::type {
+            T result = vs1 > vs2 ? vs1 - vs2 : vs2 - vs1;
+            return static_cast<typename std::make_unsigned<T>::type>(result);
+          }));
+}
+template void KelvinVAbsd<int8_t>(bool, bool, Instruction *);
+template void KelvinVAbsd<int16_t>(bool, bool, Instruction *);
+template void KelvinVAbsd<int32_t>(bool, bool, Instruction *);
+template void KelvinVAbsd<uint8_t>(bool, bool, Instruction *);
+template void KelvinVAbsd<uint16_t>(bool, bool, Instruction *);
+template void KelvinVAbsd<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVMax(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return the max of vs1 and vs2.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         return std::max(vs1, vs2);
+                       }));
+}
+template void KelvinVMax<int8_t>(bool, bool, Instruction *);
+template void KelvinVMax<int16_t>(bool, bool, Instruction *);
+template void KelvinVMax<int32_t>(bool, bool, Instruction *);
+template void KelvinVMax<uint8_t>(bool, bool, Instruction *);
+template void KelvinVMax<uint16_t>(bool, bool, Instruction *);
+template void KelvinVMax<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVMin(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return the min of vs1 and vs2.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         return std::min(vs1, vs2);
+                       }));
+}
+template void KelvinVMin<int8_t>(bool, bool, Instruction *);
+template void KelvinVMin<int16_t>(bool, bool, Instruction *);
+template void KelvinVMin<int32_t>(bool, bool, Instruction *);
+template void KelvinVMin<uint8_t>(bool, bool, Instruction *);
+template void KelvinVMin<uint16_t>(bool, bool, Instruction *);
+template void KelvinVMin<uint32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVAdd3(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return the summation of vd, vs1, and vs2.
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */, T, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T, T)>(
+          [](T vd, T vs1, T vs2) -> T { return vd + vs1 + vs2; }));
+}
+template void KelvinVAdd3<int8_t>(bool, bool, Instruction *);
+template void KelvinVAdd3<int16_t>(bool, bool, Instruction *);
+template void KelvinVAdd3<int32_t>(bool, bool, Instruction *);
+
+// Helper function for Vadds (saturated signed addition).
+// Uses unsigned arithmetic for the addition to avoid signed overflow, which,
+// when compiled with --config=asan, will trigger an exception.
+template <typename T>
+inline T VAddsHelper(T vs1, T vs2) {
+  using UT = typename std::make_unsigned<T>::type;
+  UT uvs1 = static_cast<UT>(vs1);
+  UT uvs2 = static_cast<UT>(vs2);
+  UT usum = uvs1 + uvs2;
+  T sum = static_cast<T>(usum);
+  if (((vs1 ^ vs2) >= 0) && ((sum ^ vs1) < 0)) {
+    return vs1 > 0 ? std::numeric_limits<T>::max()
+                   : std::numeric_limits<T>::min();
+  }
+  return sum;
+}
+
+template <typename T>
+void KelvinVAdds(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return saturated sum of vs1 and vs2.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>(VAddsHelper<T>));
+}
+template void KelvinVAdds<int8_t>(bool, bool, Instruction *);
+template void KelvinVAdds<int16_t>(bool, bool, Instruction *);
+template void KelvinVAdds<int32_t>(bool, bool, Instruction *);
+
+// Helper function for Vaddsu (saturated unsigned addition).
+template <typename T>
+inline T VAddsuHelper(T vs1, T vs2) {
+  T sum = vs1 + vs2;
+  if (sum < vs1) {
+    sum = std::numeric_limits<T>::max();
+  }
+  return sum;
+}
+
+template <typename T>
+void KelvinVAddsu(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return saturated sum of unsigned vs1 and vs2.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>(VAddsuHelper<T>));
+}
+template void KelvinVAddsu<uint8_t>(bool, bool, Instruction *);
+template void KelvinVAddsu<uint16_t>(bool, bool, Instruction *);
+template void KelvinVAddsu<uint32_t>(bool, bool, Instruction *);
+
+// Helper function for Vsubs (saturated signed subtraction).
+template <typename T>
+inline T VSubsHelper(T vs1, T vs2) {
+  using UT = typename std::make_unsigned<T>::type;
+  UT uvs1 = static_cast<UT>(vs1);
+  UT uvs2 = static_cast<UT>(vs2);
+  UT usub = uvs1 - uvs2;
+  T sub = static_cast<T>(usub);
+  if (((vs1 ^ vs2) < 0) && ((sub ^ vs2) >= 0)) {
+    return vs2 < 0 ? std::numeric_limits<T>::max()
+                   : std::numeric_limits<T>::min();
+  }
+  return sub;
+}
+
+template <typename T>
+void KelvinVSubs(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return saturated sub of vs1 and vs2.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>(VSubsHelper<T>));
+}
+template void KelvinVSubs<int8_t>(bool, bool, Instruction *);
+template void KelvinVSubs<int16_t>(bool, bool, Instruction *);
+template void KelvinVSubs<int32_t>(bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVSubsu(bool scalar, bool strip_mine, Instruction *inst) {
+  // Return saturated sub of unsigned vs1 and vs2.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         return vs1 < vs2 ? 0 : vs1 - vs2;
+                       }));
+}
+template void KelvinVSubsu<uint8_t>(bool, bool, Instruction *);
+template void KelvinVSubsu<uint16_t>(bool, bool, Instruction *);
+template void KelvinVSubsu<uint32_t>(bool, bool, Instruction *);
+
+template <typename Td, typename Ts>
+void KelvinVAddw(bool scalar, bool strip_mine, Instruction *inst) {
+  // Adds operands with widening.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<Td(Ts, Ts)>([](Ts vs1, Ts vs2) -> Td {
+                         return static_cast<Td>(vs1) + static_cast<Td>(vs2);
+                       }));
+}
+template void KelvinVAddw<int16_t, int8_t>(bool, bool, Instruction *);
+template void KelvinVAddw<int32_t, int16_t>(bool, bool, Instruction *);
+template void KelvinVAddw<uint16_t, uint8_t>(bool, bool, Instruction *);
+template void KelvinVAddw<uint32_t, uint16_t>(bool, bool, Instruction *);
+
+template <typename Td, typename Ts>
+void KelvinVSubw(bool scalar, bool strip_mine, Instruction *inst) {
+  // Subtracts operands with widening.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<Td(Ts, Ts)>([](Ts vs1, Ts vs2) -> Td {
+                         return static_cast<Td>(vs1) - static_cast<Td>(vs2);
+                       }));
+}
+template void KelvinVSubw<int16_t, int8_t>(bool, bool, Instruction *);
+template void KelvinVSubw<int32_t, int16_t>(bool, bool, Instruction *);
+template void KelvinVSubw<uint16_t, uint8_t>(bool, bool, Instruction *);
+template void KelvinVSubw<uint32_t, uint16_t>(bool, bool, Instruction *);
+
+template <typename Td, typename Ts2>
+void KelvinVAcc(bool scalar, bool strip_mine, Instruction *inst) {
+  // Accumulates operands with widening.
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<Td(Td, Ts2)>([](Td vs1, Ts2 vs2) -> Td {
+                         return vs1 + static_cast<Td>(vs2);
+                       }));
+}
+template void KelvinVAcc<int16_t, int8_t>(bool, bool, Instruction *);
+template void KelvinVAcc<int32_t, int16_t>(bool, bool, Instruction *);
+template void KelvinVAcc<uint16_t, uint8_t>(bool, bool, Instruction *);
+template void KelvinVAcc<uint32_t, uint16_t>(bool, bool, Instruction *);
+
+template <typename Vd, typename Vs1, typename Vs2>
+Vs1 PackedBinaryOpGetArg1(const Instruction *inst, bool scalar, int num_ops,
+                          int op_index, int dst_element_index,
+                          int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(Vs1);
+  auto src_element_index = op_index * elts_per_register +
+                           dst_element_index * sizeof(Vd) / sizeof(Vs1);
+  return GetInstructionSource<Vs1>(inst, 0, src_element_index);
+}
+
+template <typename Vd, typename Vs1, typename Vs2>
+Vs2 PackedBinaryOpGetArg2(const Instruction *inst, bool scalar, int num_ops,
+                          int op_index, int dst_element_index,
+                          int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(Vs2);
+  auto src_element_index = op_index * elts_per_register +
+                           dst_element_index * sizeof(Vd) / sizeof(Vs2) + 1;
+  return GetInstructionSource<Vs2>(inst, 0, src_element_index);
+}
+
+template <typename Td, typename Ts>
+void KelvinVPadd(bool strip_mine, Instruction *inst) {
+  // Adds lane pairs.
+  KelvinBinaryVectorOp<true /* halftype */, false /* widen_dst */, Td, Ts, Ts>(
+      inst, false /* scalar */, strip_mine,
+      std::function<Td(Ts, Ts)>([](Ts vs1, Ts vs2) -> Td {
+        return static_cast<Td>(vs1) + static_cast<Td>(vs2);
+      }),
+      SourceArgGetter<Ts, Td, Ts, Ts>(PackedBinaryOpGetArg1<Td, Ts, Ts>),
+      SourceArgGetter<Ts, Td, Ts, Ts>(PackedBinaryOpGetArg2<Td, Ts, Ts>));
+}
+template void KelvinVPadd<int16_t, int8_t>(bool, Instruction *);
+template void KelvinVPadd<int32_t, int16_t>(bool, Instruction *);
+template void KelvinVPadd<uint16_t, uint8_t>(bool, Instruction *);
+template void KelvinVPadd<uint32_t, uint16_t>(bool, Instruction *);
+
+template <typename Td, typename Ts>
+void KelvinVPsub(bool strip_mine, Instruction *inst) {
+  // Subtracts lane pairs.
+  KelvinBinaryVectorOp<true /* halftype */, false /* widen_dst */, Td, Ts, Ts>(
+      inst, false /* scalar */, strip_mine,
+      std::function<Td(Ts, Ts)>([](Ts vs1, Ts vs2) -> Td {
+        return static_cast<Td>(vs1) - static_cast<Td>(vs2);
+      }),
+      SourceArgGetter<Ts, Td, Ts, Ts>(PackedBinaryOpGetArg1<Td, Ts, Ts>),
+      SourceArgGetter<Ts, Td, Ts, Ts>(PackedBinaryOpGetArg2<Td, Ts, Ts>));
+}
+template void KelvinVPsub<int16_t, int8_t>(bool, Instruction *);
+template void KelvinVPsub<int32_t, int16_t>(bool, Instruction *);
+template void KelvinVPsub<uint16_t, uint8_t>(bool, Instruction *);
+template void KelvinVPsub<uint32_t, uint16_t>(bool, Instruction *);
+
+// Halving addition with optional rounding bit.
+template <typename T>
+T KelvinVHaddHelper(bool round, T vs1, T vs2) {
+  if (std::is_signed<T>::value) {
+    return static_cast<T>((static_cast<int64_t>(vs1) +
+                           static_cast<int64_t>(vs2) + (round ? 1 : 0)) >>
+                          1);
+  } else {
+    return static_cast<T>((static_cast<uint64_t>(vs1) +
+                           static_cast<uint64_t>(vs2) + (round ? 1 : 0)) >>
+                          1);
+  }
+}
+
+template <typename T>
+void KelvinVHadd(bool scalar, bool strip_mine, bool round, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>(absl::bind_front(&KelvinVHaddHelper<T>, round)));
+}
+template void KelvinVHadd<int8_t>(bool, bool, bool, Instruction *);
+template void KelvinVHadd<int16_t>(bool, bool, bool, Instruction *);
+template void KelvinVHadd<int32_t>(bool, bool, bool, Instruction *);
+template void KelvinVHadd<uint8_t>(bool, bool, bool, Instruction *);
+template void KelvinVHadd<uint16_t>(bool, bool, bool, Instruction *);
+template void KelvinVHadd<uint32_t>(bool, bool, bool, Instruction *);
+
+// Halving subtraction with optional rounding bit.
+template <typename T>
+T KelvinVHsubHelper(bool round, T vs1, T vs2) {
+  if (std::is_signed<T>::value) {
+    return static_cast<T>((static_cast<int64_t>(vs1) -
+                           static_cast<int64_t>(vs2) + (round ? 1 : 0)) >>
+                          1);
+  } else {
+    return static_cast<T>((static_cast<uint64_t>(vs1) -
+                           static_cast<uint64_t>(vs2) + (round ? 1 : 0)) >>
+                          1);
+  }
+}
+
+template <typename T>
+void KelvinVHsub(bool scalar, bool strip_mine, bool round, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>(absl::bind_front(&KelvinVHsubHelper<T>, round)));
+}
+template void KelvinVHsub<int8_t>(bool, bool, bool, Instruction *);
+template void KelvinVHsub<int16_t>(bool, bool, bool, Instruction *);
+template void KelvinVHsub<int32_t>(bool, bool, bool, Instruction *);
+template void KelvinVHsub<uint8_t>(bool, bool, bool, Instruction *);
+template void KelvinVHsub<uint16_t>(bool, bool, bool, Instruction *);
+template void KelvinVHsub<uint32_t>(bool, bool, bool, Instruction *);
+
+// Bitwise and.
+template <typename T>
+void KelvinVAnd(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 & vs2; }));
+}
+template void KelvinVAnd<uint8_t>(bool, bool, Instruction *);
+template void KelvinVAnd<uint16_t>(bool, bool, Instruction *);
+template void KelvinVAnd<uint32_t>(bool, bool, Instruction *);
+
+// Bitwise or.
+template <typename T>
+void KelvinVOr(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 | vs2; }));
+}
+template void KelvinVOr<uint8_t>(bool, bool, Instruction *);
+template void KelvinVOr<uint16_t>(bool, bool, Instruction *);
+template void KelvinVOr<uint32_t>(bool, bool, Instruction *);
+
+// Bitwise xor.
+template <typename T>
+void KelvinVXor(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 ^ vs2; }));
+}
+template void KelvinVXor<uint8_t>(bool, bool, Instruction *);
+template void KelvinVXor<uint16_t>(bool, bool, Instruction *);
+template void KelvinVXor<uint32_t>(bool, bool, Instruction *);
+
+// Generalized reverse using bit ladder.
+template <typename T>
+void KelvinVRev(bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, true /* scalar */, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T {
+        T r = vs1;
+        // TODO(leonidl): revisit after spec clarification.
+        // For now it's set to always use 5 lower bits, regardless of type.
+        T count = vs2 & 0b11111;
+        if (count & 1) r = ((r & 0x55555555) << 1) | ((r & 0xAAAAAAAA) >> 1);
+        if (count & 2) r = ((r & 0x33333333) << 2) | ((r & 0xCCCCCCCC) >> 2);
+        if (count & 4) r = ((r & 0x0F0F0F0F) << 4) | ((r & 0xF0F0F0F0) >> 4);
+        if (count & 8) r = ((r & 0x00FF00FF) << 8) | ((r & 0xFF00FF00) >> 8);
+        if (count & 16) r = ((r & 0x0000FFFF) << 16) | ((r & 0xFFFF0000) >> 16);
+        return r;
+      }));
+}
+template void KelvinVRev<uint8_t>(bool, Instruction *);
+template void KelvinVRev<uint16_t>(bool, Instruction *);
+template void KelvinVRev<uint32_t>(bool, Instruction *);
+
+// Cyclic rotation right using a bit ladder.
+template <typename T>
+void KelvinVRor(bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(inst, true /* scalar */, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         T r = vs1;
+                         T count = vs2 & static_cast<T>(sizeof(T) * 8 - 1);
+                         for (auto shift : {1, 2, 4, 8, 16}) {
+                           if (count & shift)
+                             r = (r >> shift) | (r << (sizeof(T) * 8 - shift));
+                         }
+                         return r;
+                       }));
+}
+template void KelvinVRor<uint8_t>(bool, Instruction *);
+template void KelvinVRor<uint16_t>(bool, Instruction *);
+template void KelvinVRor<uint32_t>(bool, Instruction *);
+
+// Returns Arg1 as either vs1 or vs2 based on dst_reg_index.
+template <typename Vd, typename Vs1, typename Vs2>
+Vs1 VMvpOpGetArg1(const Instruction *inst, bool scalar, int num_ops,
+                  int op_index, int dst_element_index, int dst_reg_index) {
+  return dst_reg_index == 0
+             ? CommonBinaryOpGetArg1<Vd, Vs1, Vs2>(
+                   inst, scalar, num_ops, op_index, dst_element_index, 0)
+             : CommonBinaryOpGetArg2<Vd, Vs1, Vs2>(
+                   inst, scalar, num_ops, op_index, dst_element_index, 0);
+}
+
+// Copies a pair of registers.
+template <typename T>
+void KelvinVMvp(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, true /* widen_dst */, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(VMvpOpGetArg1<T, T, T>),
+      // Arg2 isn't used. We provide a custom getter here because the default
+      // getter expects extra source registers for widening ops.
+      SourceArgGetter<T, T, T, T>(VMvpOpGetArg1<T, T, T>));
+}
+template void KelvinVMvp<uint8_t>(bool, bool, Instruction *);
+template void KelvinVMvp<uint16_t>(bool, bool, Instruction *);
+template void KelvinVMvp<uint32_t>(bool, bool, Instruction *);
+
+// Logical shift left.
+template <typename T>
+void KelvinVSll(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         size_t shift = vs2 & (sizeof(T) * 8 - 1);
+                         return vs1 << shift;
+                       }));
+}
+template void KelvinVSll<uint8_t>(bool, bool, Instruction *);
+template void KelvinVSll<uint16_t>(bool, bool, Instruction *);
+template void KelvinVSll<uint32_t>(bool, bool, Instruction *);
+
+// Arithmetic shift right.
+template <typename T>
+void KelvinVSra(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         size_t shift = vs2 & (sizeof(T) * 8 - 1);
+                         return vs1 >> shift;
+                       }));
+}
+template void KelvinVSra<int8_t>(bool, bool, Instruction *);
+template void KelvinVSra<int16_t>(bool, bool, Instruction *);
+template void KelvinVSra<int32_t>(bool, bool, Instruction *);
+
+// Logical shift right.
+template <typename T>
+void KelvinVSrl(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>([](T vs1, T vs2) -> T {
+                         size_t shift = vs2 & (sizeof(T) * 8 - 1);
+                         return vs1 >> shift;
+                       }));
+}
+template void KelvinVSrl<uint8_t>(bool, bool, Instruction *);
+template void KelvinVSrl<uint16_t>(bool, bool, Instruction *);
+template void KelvinVSrl<uint32_t>(bool, bool, Instruction *);
+
+// Logical and arithmetic left/right shift with saturating shift amount and
+// result.
+template <typename T>
+T KelvinVShiftHelper(bool round, T vs1, T vs2) {
+  if (std::is_signed<T>::value == true) {
+    constexpr int n = sizeof(T) * 8;
+    int shamt = vs2;
+    int64_t s = vs1;
+    if (!vs1) {
+      return 0;
+    } else if (vs1 < 0 && shamt >= n) {
+      s = -1 + round;
+    } else if (vs1 > 0 && shamt >= n) {
+      s = 0;
+    } else if (shamt > 0) {
+      s = (static_cast<int64_t>(vs1) + (round ? (1ll << (shamt - 1)) : 0)) >>
+          shamt;
+    } else {
+      s = static_cast<int64_t>(vs1) << (-shamt);
+    }
+    T neg_max = std::numeric_limits<T>::min();
+    T pos_max = std::numeric_limits<T>::max();
+    bool neg_sat = vs1 < 0 && (shamt <= -n || s < neg_max);
+    bool pos_sat = vs1 > 0 && (shamt <= -n || s > pos_max);
+    if (neg_sat) return neg_max;
+    if (pos_sat) return pos_max;
+    return s;
+  } else {
+    constexpr int n = sizeof(T) * 8;
+    int shamt = static_cast<typename std::make_signed<T>::type>(vs2);
+    uint64_t s = vs1;
+    if (!vs1) {
+      return 0;
+    } else if (shamt > n) {
+      s = 0;
+    } else if (shamt > 0) {
+      s = (static_cast<int64_t>(vs1) + (round ? (1ull << (shamt - 1)) : 0)) >>
+          shamt;
+    } else {
+      s = static_cast<int64_t>(vs1) << (-shamt);
+    }
+    T pos_max = std::numeric_limits<T>::max();
+    bool pos_sat = vs1 && (shamt < -n || s > pos_max);
+    if (pos_sat) return pos_max;
+    return s;
+  }
+}
+
+template <typename T>
+void KelvinVShift(bool round, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, false /* scalar */, strip_mine,
+      std::function<T(T, T)>(absl::bind_front(&KelvinVShiftHelper<T>, round)));
+}
+template void KelvinVShift<int8_t>(bool, bool, Instruction *);
+template void KelvinVShift<int16_t>(bool, bool, Instruction *);
+template void KelvinVShift<int32_t>(bool, bool, Instruction *);
+template void KelvinVShift<uint8_t>(bool, bool, Instruction *);
+template void KelvinVShift<uint16_t>(bool, bool, Instruction *);
+template void KelvinVShift<uint32_t>(bool, bool, Instruction *);
+
+// Bitwise not.
+template <typename T>
+void KelvinVNot(bool strip_mine, Instruction *inst) {
+  KelvinUnaryVectorOp(inst, strip_mine,
+                      std::function<T(T)>([](T vs) -> T { return ~vs; }));
+}
+template void KelvinVNot<int32_t>(bool, Instruction *);
+
+// Count the leading bits.
+template <typename T>
+void KelvinVClb(bool strip_mine, Instruction *inst) {
+  KelvinUnaryVectorOp(inst, strip_mine, std::function<T(T)>([](T vs) -> T {
+                        return (vs & (1u << (sizeof(T) * 8 - 1)))
+                                   ? absl::countl_one(vs)
+                                   : absl::countl_zero(vs);
+                      }));
+}
+template void KelvinVClb<uint8_t>(bool, Instruction *);
+template void KelvinVClb<uint16_t>(bool, Instruction *);
+template void KelvinVClb<uint32_t>(bool, Instruction *);
+
+// Count the leading zeros.
+template <typename T>
+void KelvinVClz(bool strip_mine, Instruction *inst) {
+  KelvinUnaryVectorOp(inst, strip_mine, std::function<T(T)>([](T vs) -> T {
+                        return absl::countl_zero(vs);
+                      }));
+}
+template void KelvinVClz<uint8_t>(bool, Instruction *);
+template void KelvinVClz<uint16_t>(bool, Instruction *);
+template void KelvinVClz<uint32_t>(bool, Instruction *);
+
+// Count the set bits.
+template <typename T>
+void KelvinVCpop(bool strip_mine, Instruction *inst) {
+  KelvinUnaryVectorOp(inst, strip_mine, std::function<T(T)>([](T vs) -> T {
+                        return absl::popcount(vs);
+                      }));
+}
+template void KelvinVCpop<uint8_t>(bool, Instruction *);
+template void KelvinVCpop<uint16_t>(bool, Instruction *);
+template void KelvinVCpop<uint32_t>(bool, Instruction *);
+
+// Move a register.
+template <typename T>
+void KelvinVMv(bool strip_mine, Instruction *inst) {
+  KelvinUnaryVectorOp(inst, strip_mine,
+                      std::function<T(T)>([](T vs) -> T { return vs; }));
+}
+template void KelvinVMv<int32_t>(bool, Instruction *);
+
+// Alternates Vs1 register used for odd/even destination indices.
+template <typename Vd, typename Vs1, typename Vs2>
+Vs1 VSransOpGetArg1(const Instruction *inst, bool scalar, int num_ops,
+                    int op_index, int dst_element_index, int dst_reg_index) {
+  static_assert(2 * sizeof(Vd) == sizeof(Vs1) || 4 * sizeof(Vd) == sizeof(Vs1));
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(Vs1);
+  auto src_element_index = op_index * elts_per_register +
+                           dst_element_index * sizeof(Vd) / sizeof(Vs1);
+
+  if (sizeof(Vs1) / sizeof(Vd) == 2) {
+    src_element_index +=
+        dst_element_index & 1 ? num_ops * elts_per_register : 0;
+  } else {  // sizeof(Vs1) / sizeof(Vd) == 4
+    const int interleave[4] = {0, 2, 1, 3};
+    src_element_index +=
+        interleave[dst_element_index & 3] * num_ops * elts_per_register;
+  }
+
+  return GetInstructionSource<Vs1>(inst, 0, src_element_index);
+}
+
+// Arithmetic right shift with rounding and signed/unsigned saturation.
+// Narrowing x2 or x4.
+template <typename Td, typename Ts>
+Td KelvinVSransHelper(bool round, Ts vs1, Td vs2) {
+  static_assert(2 * sizeof(Td) == sizeof(Ts) || 4 * sizeof(Td) == sizeof(Ts));
+  constexpr int src_bits = sizeof(Ts) * 8;
+  vs2 &= (src_bits - 1);
+
+  int64_t res =
+      (static_cast<int64_t>(vs1) + (vs2 && round ? (1ll << (vs2 - 1)) : 0)) >>
+      vs2;
+
+  bool neg_sat = res < std::numeric_limits<Td>::min();
+  bool pos_sat = res > std::numeric_limits<Td>::max();
+  bool zero = !vs1;
+  if (neg_sat) return std::numeric_limits<Td>::min();
+  if (pos_sat) return std::numeric_limits<Td>::max();
+  if (zero) return 0;
+  return res;
+}
+
+template <typename Td, typename Ts>
+void KelvinVSrans(bool round, bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<Td(Ts, Td)>(
+          absl::bind_front(&KelvinVSransHelper<Td, Ts>, round)),
+      SourceArgGetter<Ts, Td, Ts, Td>(VSransOpGetArg1<Td, Ts, Td>));
+}
+template void KelvinVSrans<int8_t, int16_t>(bool, bool, bool, Instruction *);
+template void KelvinVSrans<int16_t, int32_t>(bool, bool, bool, Instruction *);
+template void KelvinVSrans<uint8_t, uint16_t>(bool, bool, bool, Instruction *);
+template void KelvinVSrans<uint16_t, uint32_t>(bool, bool, bool, Instruction *);
+template void KelvinVSrans<int8_t, int32_t>(bool, bool, bool, Instruction *);
+template void KelvinVSrans<uint8_t, uint32_t>(bool, bool, bool, Instruction *);
+
+// Multiplication of vector elements.
+template <typename T>
+void KelvinVMul(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1 * vs2; }));
+}
+template void KelvinVMul<int8_t>(bool, bool, Instruction *);
+template void KelvinVMul<int16_t>(bool, bool, Instruction *);
+template void KelvinVMul<int32_t>(bool, bool, Instruction *);
+
+// Multiplication of vector elements with saturation.
+template <typename T>
+void KelvinVMuls(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine, std::function<T(T, T)>([](T vs1, T vs2) -> T {
+        if (std::is_signed<T>::value) {
+          int64_t result =
+              static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+          result = std::max(
+              static_cast<int64_t>(std::numeric_limits<T>::min()),
+              std::min(static_cast<int64_t>(std::numeric_limits<T>::max()),
+                       result));
+          return result;
+        } else {
+          uint64_t result =
+              static_cast<uint64_t>(vs1) * static_cast<uint64_t>(vs2);
+          result = std::min(
+              static_cast<uint64_t>(std::numeric_limits<T>::max()), result);
+          return result;
+        }
+      }));
+}
+template void KelvinVMuls<int8_t>(bool, bool, Instruction *);
+template void KelvinVMuls<int16_t>(bool, bool, Instruction *);
+template void KelvinVMuls<int32_t>(bool, bool, Instruction *);
+template void KelvinVMuls<uint8_t>(bool, bool, Instruction *);
+template void KelvinVMuls<uint16_t>(bool, bool, Instruction *);
+template void KelvinVMuls<uint32_t>(bool, bool, Instruction *);
+
+// Multiplication of vector elements with widening.
+template <typename Td, typename Ts>
+void KelvinVMulw(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<Td(Ts, Ts)>([](Ts vs1, Ts vs2) -> Td {
+                         return static_cast<Td>(vs1) * static_cast<Td>(vs2);
+                       }));
+}
+template void KelvinVMulw<int16_t, int8_t>(bool, bool, Instruction *);
+template void KelvinVMulw<int32_t, int16_t>(bool, bool, Instruction *);
+template void KelvinVMulw<uint16_t, uint8_t>(bool, bool, Instruction *);
+template void KelvinVMulw<uint32_t, uint16_t>(bool, bool, Instruction *);
+
+// Multiplication of vector elements with widening and optional rounding.
+// Returns high half.
+template <typename T>
+T KelvinVMulhHelper(bool round, T vs1, T vs2) {
+  constexpr int n = sizeof(T) * 8;
+  if (std::is_signed<T>::value) {
+    int64_t result = static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+    result += round ? 1ll << (n - 1) : 0;
+    return static_cast<uint64_t>(result) >> n;
+  } else {
+    uint64_t result = static_cast<uint64_t>(vs1) * static_cast<uint64_t>(vs2);
+    result += round ? 1ull << (n - 1) : 0;
+    return result >> n;
+  }
+}
+
+template <typename T>
+void KelvinVMulh(bool scalar, bool strip_mine, bool round, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>(absl::bind_front(&KelvinVMulhHelper<T>, round)));
+}
+template void KelvinVMulh<int8_t>(bool, bool, bool, Instruction *);
+template void KelvinVMulh<int16_t>(bool, bool, bool, Instruction *);
+template void KelvinVMulh<int32_t>(bool, bool, bool, Instruction *);
+template void KelvinVMulh<uint8_t>(bool, bool, bool, Instruction *);
+template void KelvinVMulh<uint16_t>(bool, bool, bool, Instruction *);
+template void KelvinVMulh<uint32_t>(bool, bool, bool, Instruction *);
+
+// Saturating signed doubling multiply returning high half with optional
+// rounding.
+template <typename T>
+T KelvinVDmulhHelper(bool round, bool round_neg, T vs1, T vs2) {
+  constexpr int n = sizeof(T) * 8;
+  int64_t result = static_cast<int64_t>(vs1) * static_cast<int64_t>(vs1);
+  if (round) {
+    int64_t rnd = 0x40000000ll >> (32 - n);
+    if (result < 0 && round_neg) {
+      rnd = (-0x40000000ll) >> (32 - n);
+    }
+    result += rnd;
+  }
+  result >>= (n - 1);
+  if (vs1 == std::numeric_limits<T>::min() &&
+      vs2 == std::numeric_limits<T>::min()) {
+    result = std::numeric_limits<T>::max();
+  }
+  return result;
+}
+template <typename T>
+void KelvinVDmulh(bool scalar, bool strip_mine, bool round, bool round_neg,
+                  Instruction *inst) {
+  KelvinBinaryVectorOp(inst, scalar, strip_mine,
+                       std::function<T(T, T)>(absl::bind_front(
+                           &KelvinVDmulhHelper<T>, round, round_neg)));
+}
+template void KelvinVDmulh<int8_t>(bool, bool, bool, bool, Instruction *);
+template void KelvinVDmulh<int16_t>(bool, bool, bool, bool, Instruction *);
+template void KelvinVDmulh<int32_t>(bool, bool, bool, bool, Instruction *);
+
+// Multiply accumulate.
+template <typename T>
+void KelvinVMacc(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */, T, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T, T)>([](T vd, T vs1, T vs2) -> T {
+        return static_cast<int64_t>(vd) +
+               static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+      }));
+}
+template void KelvinVMacc<int8_t>(bool, bool, Instruction *);
+template void KelvinVMacc<int16_t>(bool, bool, Instruction *);
+template void KelvinVMacc<int32_t>(bool, bool, Instruction *);
+
+// Multiply add.
+template <typename T>
+void KelvinVMadd(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */, T, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T, T)>([](T vd, T vs1, T vs2) -> T {
+        return static_cast<int64_t>(vs1) +
+               static_cast<int64_t>(vd) * static_cast<int64_t>(vs2);
+      }));
+}
+template void KelvinVMadd<int8_t>(bool, bool, Instruction *);
+template void KelvinVMadd<int16_t>(bool, bool, Instruction *);
+template void KelvinVMadd<int32_t>(bool, bool, Instruction *);
+
+// Computes slide index for next register and takes result from either vs1 or
+// vs2.
+template <typename T>
+T VSlidenOpGetArg1(bool horizontal, int index, const Instruction *inst,
+                   bool scalar, int num_ops, int op_index,
+                   int dst_element_index, int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  using Interleave = struct {
+    int register_num;
+    int source_arg;
+  };
+  const Interleave interleave_start[2][4] = {{{3, 0}, {2, 0}, {1, 0}, {0, 0}},
+                                             {{3, 0}, {2, 0}, {1, 0}, {0, 0}}};
+  const Interleave interleave_end[2][4] = {{{3, 1}, {2, 1}, {1, 1}, {0, 1}},
+                                           {{0, 1}, {3, 0}, {2, 0}, {1, 0}}};
+
+  if (dst_element_index + index < elts_per_register) {
+    auto src_element_index =
+        interleave_start[horizontal][op_index].register_num *
+            elts_per_register +
+        dst_element_index + index;
+    return GetInstructionSource<T>(
+        inst, interleave_start[horizontal][op_index].source_arg,
+        src_element_index);
+  }
+
+  auto src_element_index =
+      interleave_end[horizontal][op_index].register_num * elts_per_register +
+      dst_element_index + index - elts_per_register;
+  return GetInstructionSource<T>(
+      inst, interleave_end[horizontal][op_index].source_arg, src_element_index);
+}
+
+// Slide next register vertically by index.
+template <typename T>
+void KelvinVSlidevn(int index, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, false /* scalar */, true /* strip_mine */,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(absl::bind_front(
+          VSlidenOpGetArg1<T>, false /* horizontal */, index)));
+}
+template void KelvinVSlidevn<int8_t>(int, Instruction *);
+template void KelvinVSlidevn<int16_t>(int, Instruction *);
+template void KelvinVSlidevn<int32_t>(int, Instruction *);
+
+// Slide next register horizontally by index.
+template <typename T>
+void KelvinVSlidehn(int index, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, false /* scalar */, true /* strip_mine */,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(
+          absl::bind_front(VSlidenOpGetArg1<T>, true /* horizontal */, index)));
+}
+template void KelvinVSlidehn<int8_t>(int, Instruction *);
+template void KelvinVSlidehn<int16_t>(int, Instruction *);
+template void KelvinVSlidehn<int32_t>(int, Instruction *);
+
+// Computes slide index for previous register and takes result from either vs1
+// or vs2.
+template <typename T>
+T VSlidepOpGetArg1(bool horizontal, int index, const Instruction *inst,
+                   bool scalar, int num_ops, int op_index,
+                   int dst_element_index, int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  auto elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  using Interleave = struct {
+    int register_num;
+    int source_arg;
+  };
+  const Interleave interleave_start[2][4] = {{{3, 0}, {2, 0}, {1, 0}, {0, 0}},
+                                             {{3, 0}, {2, 0}, {1, 0}, {0, 0}}};
+  const Interleave interleave_end[2][4] = {{{2, 0}, {1, 0}, {0, 0}, {3, 1}},
+                                           {{0, 1}, {3, 0}, {2, 0}, {1, 0}}};
+
+  if (dst_element_index >= index) {
+    auto src_element_index =
+        interleave_start[horizontal][op_index].register_num *
+            elts_per_register +
+        dst_element_index - index;
+    return GetInstructionSource<T>(
+        inst, interleave_start[horizontal][op_index].source_arg,
+        src_element_index);
+  }
+
+  auto src_element_index =
+      interleave_end[horizontal][op_index].register_num * elts_per_register +
+      elts_per_register + dst_element_index - index;
+  return GetInstructionSource<T>(
+      inst, interleave_end[horizontal][op_index].source_arg, src_element_index);
+}
+
+// Slide previous register vertically by index.
+template <typename T>
+void KelvinVSlidevp(int index, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, false /* scalar */, true /* strip_mine */,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(absl::bind_front(
+          VSlidepOpGetArg1<T>, false /* horizontal */, index)));
+}
+template void KelvinVSlidevp<int8_t>(int, Instruction *);
+template void KelvinVSlidevp<int16_t>(int, Instruction *);
+template void KelvinVSlidevp<int32_t>(int, Instruction *);
+
+// Slide previous register horizontally by index.
+template <typename T>
+void KelvinVSlidehp(int index, Instruction *inst) {
+  KelvinBinaryVectorOp(
+      inst, false /* scalar */, true /* strip_mine */,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(
+          absl::bind_front(VSlidepOpGetArg1<T>, true /* horizontal */, index)));
+}
+template void KelvinVSlidehp<int8_t>(int, Instruction *);
+template void KelvinVSlidehp<int16_t>(int, Instruction *);
+template void KelvinVSlidehp<int32_t>(int, Instruction *);
+
+template <typename T>
+void KelvinVSel(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSel(bool scalar, bool strip_mine, Instruction *inst) {
+  // Select lanes from two operands with vector selection boolean.
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */, T, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T, T)>(
+          [](T vd, T vs1, T vs2) -> T { return vs1 & 1 ? vd : vs2; }));
+}
+template void KelvinVSel<int8_t>(bool, bool, Instruction *);
+template void KelvinVSel<int16_t>(bool, bool, Instruction *);
+template void KelvinVSel<int32_t>(bool, bool, Instruction *);
+
+// Returns even elements of concatenated registers.
+template <typename T>
+T VEvnOpGetArg1(const Instruction *inst, bool scalar, int num_ops, int op_index,
+                int dst_element_index, int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  const int elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  auto src_element_index =
+      op_index * elts_per_register * 2 + dst_element_index * 2;
+  const int elts_per_src = elts_per_register * num_ops;
+
+  if (src_element_index < elts_per_src) {
+    return GetInstructionSource<T>(inst, 0, src_element_index);
+  }
+
+  return GetInstructionSource<T>(inst, 1,
+                                 scalar ? 0 : src_element_index - elts_per_src);
+}
+
+template <typename T>
+void KelvinVEvn(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(VEvnOpGetArg1<T>),
+      SourceArgGetter<T, T, T, T>(VEvnOpGetArg1<T>));
+}
+template void KelvinVEvn<int8_t>(bool, bool, Instruction *);
+template void KelvinVEvn<int16_t>(bool, bool, Instruction *);
+template void KelvinVEvn<int32_t>(bool, bool, Instruction *);
+
+// Returns odd elements of concatenated registers.
+template <typename T>
+T VOddOpGetArg1(const Instruction *inst, bool scalar, int num_ops, int op_index,
+                int dst_element_index, int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  const int elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  auto src_element_index =
+      op_index * elts_per_register * 2 + dst_element_index * 2 + 1;
+  const int elts_per_src = elts_per_register * num_ops;
+
+  if (src_element_index < elts_per_src) {
+    return GetInstructionSource<T>(inst, 0, src_element_index);
+  }
+
+  return GetInstructionSource<T>(inst, 1,
+                                 scalar ? 0 : src_element_index - elts_per_src);
+}
+
+template <typename T>
+void KelvinVOdd(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, false /* widen_dst */, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(VOddOpGetArg1<T>),
+      SourceArgGetter<T, T, T, T>(VOddOpGetArg1<T>));
+}
+template void KelvinVOdd<int8_t>(bool, bool, Instruction *);
+template void KelvinVOdd<int16_t>(bool, bool, Instruction *);
+template void KelvinVOdd<int32_t>(bool, bool, Instruction *);
+
+// Returns evn/odd elements of concatenated registers based on dst_reg_index.
+template <typename T>
+T VEvnoddOpGetArg1(const Instruction *inst, bool scalar, int num_ops,
+                   int op_index, int dst_element_index, int dst_reg_index) {
+  return dst_reg_index == 0
+             ? VEvnOpGetArg1<T>(inst, scalar, num_ops, op_index,
+                                dst_element_index, dst_reg_index)
+             : VOddOpGetArg1<T>(inst, scalar, num_ops, op_index,
+                                dst_element_index, dst_reg_index);
+}
+
+template <typename T>
+void KelvinVEvnodd(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, true /* widen_dst */, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(VEvnoddOpGetArg1<T>),
+      SourceArgGetter<T, T, T, T>(VEvnoddOpGetArg1<T>));
+}
+template void KelvinVEvnodd<int8_t>(bool, bool, Instruction *);
+template void KelvinVEvnodd<int16_t>(bool, bool, Instruction *);
+template void KelvinVEvnodd<int32_t>(bool, bool, Instruction *);
+
+// Interleave even/odd lanes of two operands.
+// Returns odd elements of concatenated registers.
+template <typename T>
+T VZipOpGetArg1(const Instruction *inst, bool scalar, int num_ops, int op_index,
+                int dst_element_index, int dst_reg_index) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  const int elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  auto src_element_index = op_index * elts_per_register +
+                           dst_element_index / 2 +
+                           dst_reg_index * elts_per_register / 2;
+
+  if (dst_element_index & 1) {
+    return GetInstructionSource<T>(inst, 1, scalar ? 0 : src_element_index);
+  } else {
+    return GetInstructionSource<T>(inst, 0, src_element_index);
+  }
+}
+
+template <typename T>
+void KelvinVZip(bool scalar, bool strip_mine, Instruction *inst) {
+  KelvinBinaryVectorOp<false /* halftype */, true /* widen_dst */, T, T, T>(
+      inst, scalar, strip_mine,
+      std::function<T(T, T)>([](T vs1, T vs2) -> T { return vs1; }),
+      SourceArgGetter<T, T, T, T>(VZipOpGetArg1<T>),
+      SourceArgGetter<T, T, T, T>(VZipOpGetArg1<T>));
+}
+template void KelvinVZip<int8_t>(bool, bool, Instruction *);
+template void KelvinVZip<int16_t>(bool, bool, Instruction *);
+template void KelvinVZip<int32_t>(bool, bool, Instruction *);
+}  // namespace kelvin::sim
diff --git a/sim/kelvin_vector_instructions.h b/sim/kelvin_vector_instructions.h
new file mode 100644
index 0000000..447dcc4
--- /dev/null
+++ b/sim/kelvin_vector_instructions.h
@@ -0,0 +1,181 @@
+#ifndef SIM_KELVIN_VECTOR_INSTRUCTIONS_H_
+#define SIM_KELVIN_VECTOR_INSTRUCTIONS_H_
+
+#include "mpact/sim/generic/instruction.h"
+
+namespace kelvin::sim {
+
+using mpact::sim::generic::Instruction;
+
+// Vector 2-arg .vv, .vx arithmetic operations.
+template <typename T>
+void KelvinVAdd(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSub(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVRSub(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVEq(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVNe(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVLt(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVLe(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVGt(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVGe(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVAbsd(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMax(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMin(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVAdd3(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVAdds(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVAddsu(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSubs(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSubsu(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts>
+void KelvinVAddw(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts>
+void KelvinVSubw(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts2>
+void KelvinVAcc(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts>
+void KelvinVPadd(bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts>
+void KelvinVPsub(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVHadd(bool scalar, bool strip_mine, bool round, Instruction *inst);
+
+template <typename T>
+void KelvinVHsub(bool scalar, bool strip_mine, bool round, Instruction *inst);
+
+template <typename T>
+void KelvinVAnd(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVOr(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVXor(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVRev(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVRor(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMvp(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSll(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSra(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSrl(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVShift(bool round, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVNot(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVClb(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVClz(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVCpop(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMv(bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts>
+void KelvinVSrans(bool round, bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMul(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMuls(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename Td, typename Ts>
+void KelvinVMulw(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMulh(bool scalar, bool strip_mine, bool round, Instruction *inst);
+
+template <typename T>
+void KelvinVDmulh(bool scalar, bool strip_mine, bool round, bool round_neg,
+                  Instruction *inst);
+
+template <typename T>
+void KelvinVMacc(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVMadd(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSlidevn(int index, Instruction *inst);
+
+template <typename T>
+void KelvinVSlidehn(int index, Instruction *inst);
+
+template <typename T>
+void KelvinVSlidevp(int index, Instruction *inst);
+
+template <typename T>
+void KelvinVSlidehp(int index, Instruction *inst);
+
+template <typename T>
+void KelvinVSel(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVEvn(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVOdd(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVEvnodd(bool scalar, bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVZip(bool scalar, bool strip_mine, Instruction *inst);
+}  // namespace kelvin::sim
+
+#endif  // SIM_KELVIN_VECTOR_INSTRUCTIONS_H_
diff --git a/sim/kelvin_vector_memory_instructions.cc b/sim/kelvin_vector_memory_instructions.cc
new file mode 100644
index 0000000..4072892
--- /dev/null
+++ b/sim/kelvin_vector_memory_instructions.cc
@@ -0,0 +1,282 @@
+#include "sim/kelvin_vector_memory_instructions.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+
+#include "sim/kelvin_state.h"
+#include "absl/types/span.h"
+#include "riscv/riscv_register.h"
+#include "mpact/sim/generic/data_buffer.h"
+#include "mpact/sim/generic/instruction.h"
+
+namespace kelvin::sim {
+
+using mpact::sim::generic::DataBuffer;
+using mpact::sim::generic::GetInstructionSource;
+using mpact::sim::generic::Instruction;
+using mpact::sim::riscv::LoadContext;
+using mpact::sim::riscv::RV32VectorDestinationOperand;
+using mpact::sim::riscv::RV32VectorSourceOperand;
+
+// Vector load instruction with optional data length, stride and address
+// register post-increment.
+template <typename T>
+void KelvinVLd(bool has_length, bool has_stride, bool strip_mine,
+               Instruction *inst) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  const uint32_t elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  const auto num_ops = strip_mine ? 4 : 1;
+  auto addr = GetInstructionSource<uint32_t>(inst, 0, 0);
+
+  uint32_t elts_to_load = num_ops * elts_per_register;
+  if (has_length) {
+    auto length_arg = GetInstructionSource<uint32_t>(inst, 1, 0);
+    elts_to_load = std::min(length_arg, elts_to_load);
+  }
+
+  uint32_t stride_elts = elts_per_register;
+  if (has_stride) {
+    auto stride_arg = GetInstructionSource<uint32_t>(inst, 1, 0);
+    stride_elts = stride_arg;
+  }
+
+  auto *db_factory = inst->state()->db_factory();
+  auto *address_db = db_factory->Allocate<uint64_t>(elts_to_load);
+  auto *mask_db = db_factory->Allocate<bool>(elts_to_load);
+  // Allocate the value data buffer that the loaded data is returned in.
+  auto *value_db = db_factory->Allocate<T>(elts_to_load);
+
+  auto addresses = address_db->Get<uint64_t>();
+  auto masks = mask_db->Get<bool>();
+  auto base = addr;
+  auto elts_left = elts_to_load;
+  for (int op_num = 0; op_num < num_ops; ++op_num) {
+    uint32_t count = std::min(elts_left, elts_per_register);
+    for (int i = 0; i < count; ++i) {
+      addresses[op_num * elts_per_register + i] = base + i * sizeof(T);
+      masks[op_num * elts_per_register + i] = true;
+    }
+    elts_left -= count;
+    base += stride_elts * sizeof(T);
+  }
+  auto *context = new LoadContext(value_db);
+  value_db->set_latency(0);
+  state->LoadMemory(inst, address_db, mask_db, sizeof(T), value_db,
+                    inst->child(), context);
+
+  // Release the context and address_db. The others will be released elsewhere.
+  context->DecRef();
+  address_db->DecRef();
+  mask_db->DecRef();
+
+  const bool post_increment = inst->DestinationsSize() == 1;
+  if (post_increment) {
+    auto *reg =
+        static_cast<
+            mpact::sim::generic::RegisterDestinationOperand<uint32_t> *>(
+            inst->Destination(0))
+            ->GetRegister();
+
+    if (elts_to_load > 0) {
+      if (has_length && has_stride) {  // .tp
+        addr += vector_size_in_bytes;
+      } else if (!has_length && !has_stride &&
+                 inst->SourcesSize() == 1) {  // .p.x
+        addr += vector_size_in_bytes * num_ops;
+      } else if (has_length) {  // .lp
+        addr += elts_to_load * sizeof(T);
+      } else if (has_stride) {  // .sp
+        addr += stride_elts * sizeof(T) * num_ops;
+      } else {  // .p.xx
+        addr += GetInstructionSource<uint32_t>(inst, 1, 0) * sizeof(T);
+      }
+    }
+
+    reg->data_buffer()->template Set<uint32_t>(0, addr);
+  }
+}
+template void KelvinVLd<int8_t>(bool, bool, bool, Instruction *);
+template void KelvinVLd<int16_t>(bool, bool, bool, Instruction *);
+template void KelvinVLd<int32_t>(bool, bool, bool, Instruction *);
+
+// VLd child instruction which writes data loaded to destination register(s).
+template <typename T>
+void KelvinVLdRegWrite(bool strip_mine, Instruction *inst) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  const uint32_t elts_per_register = vector_size_in_bytes / sizeof(T);
+  const auto num_ops = strip_mine ? 4 : 1;
+
+  auto *context = static_cast<LoadContext *>(inst->context());
+  auto values = context->value_db->template Get<T>();
+
+  auto vd = static_cast<RV32VectorDestinationOperand *>(inst->Destination(0));
+  for (int op_index = 0; op_index < num_ops; ++op_index) {
+    DataBuffer *dest_db = vd->AllocateDataBuffer(op_index);
+    absl::Span<T> dest_span = dest_db->template Get<T>();
+
+    for (int dst_element_index = 0; dst_element_index < elts_per_register;
+         ++dst_element_index) {
+      auto value_index = op_index * elts_per_register + dst_element_index;
+      dest_span[dst_element_index] =
+          value_index < context->value_db->template size<T>()
+              ? values[value_index]
+              : 0;
+    }
+
+    dest_db->Submit();
+  }
+}
+template void KelvinVLdRegWrite<int8_t>(bool, Instruction *);
+template void KelvinVLdRegWrite<int16_t>(bool, Instruction *);
+template void KelvinVLdRegWrite<int32_t>(bool, Instruction *);
+
+// Vector store instruction with the optional data length, stride and address
+// register post-increment.
+// Quad store stores either a quarter of the vector register content or the full
+// register with xs2 stride.
+template <typename T>
+void VectorStoreHelper(bool has_length, bool has_stride, bool strip_mine,
+                       bool is_quad, Instruction *inst) {
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  const uint32_t elts_per_register = vector_size_in_bytes / sizeof(T);
+
+  const auto num_ops = strip_mine ? 4 : 1;
+  auto mem_addr = GetInstructionSource<uint32_t>(inst, 1, 0);
+  auto vs = static_cast<RV32VectorSourceOperand *>(inst->Source(0));
+
+  auto base_addr = mem_addr;
+
+  uint32_t elts_to_store = num_ops * elts_per_register;
+  if (has_length) {
+    auto length_arg = GetInstructionSource<uint32_t>(inst, 2, 0);
+    elts_to_store = std::min(length_arg, elts_to_store);
+  }
+
+  uint32_t stride_elts = elts_per_register;
+  if (has_stride) {
+    auto stride_arg = GetInstructionSource<uint32_t>(inst, 2, 0);
+    stride_elts = stride_arg;
+  }
+
+  // Allocate the store memory
+  auto *value_db = state->db_factory()->Allocate(elts_to_store * sizeof(T));
+  auto *address_db = state->db_factory()->Allocate<uint64_t>(elts_to_store);
+  auto *mask_db = state->db_factory()->Allocate<bool>(elts_to_store);
+  auto addresses = address_db->Get<uint64_t>();
+  auto value = value_db->Get<T>();
+  auto mask = mask_db->Get<bool>();
+
+  int address_index = 0;
+  for (int op_num = 0; op_num < num_ops; op_num++) {
+    auto source_span = vs->GetRegister(op_num)->data_buffer()->Get<T>();
+    if (is_quad) {
+      const uint32_t quad_size = elts_per_register / 4;
+      for (int i = 0; i < 4; ++i) {
+        for (int j = 0; j < quad_size && address_index < elts_to_store; ++j) {
+          addresses[address_index] =
+              base_addr + (i * quad_size + j) * sizeof(T);
+          value[address_index] = source_span[i * quad_size + j];
+          mask[address_index++] = true;
+        }
+        // Stride increase per quad_size.
+        base_addr += stride_elts * sizeof(T);
+      }
+    } else {
+      for (int i = 0; i < elts_per_register && address_index < elts_to_store;
+           ++i) {
+        addresses[address_index] = base_addr + i * sizeof(T);
+        value[address_index] = source_span[i];
+        mask[address_index++] = true;
+      }
+      base_addr += stride_elts * sizeof(T);
+    }
+  }
+  state->StoreMemory(inst, address_db, mask_db, sizeof(T), value_db);
+  value_db->DecRef();
+  address_db->DecRef();
+  mask_db->DecRef();
+
+  const bool post_increment = inst->DestinationsSize() == 1;
+  if (post_increment) {
+    auto *reg =
+        static_cast<
+            mpact::sim::generic::RegisterDestinationOperand<uint32_t> *>(
+            inst->Destination(0))
+            ->GetRegister();
+    if (elts_to_store > 0) {
+      if (has_length && has_stride) {  // .tp
+        mem_addr += vector_size_in_bytes;
+      } else if (!has_length && !has_stride &&
+                 inst->SourcesSize() == 2) {  // .p.x
+        mem_addr += vector_size_in_bytes * num_ops;
+      } else if (has_length) {  // .lp
+        mem_addr += elts_to_store * sizeof(T);
+      } else if (has_stride) {  // .sp
+        const uint32_t quad_scale = is_quad ? 4 : 1;
+        mem_addr += stride_elts * sizeof(T) * num_ops * quad_scale;
+      } else {  // .p.xx
+        mem_addr += GetInstructionSource<uint32_t>(inst, 2, 0) * sizeof(T);
+      }
+    }
+    reg->data_buffer()->template Set<uint32_t>(0, mem_addr);
+  }
+}
+
+template <typename T>
+void KelvinVSt(bool has_length, bool has_stride, bool strip_mine,
+               Instruction *inst) {
+  VectorStoreHelper<T>(has_length, has_stride, strip_mine, /*is_quad=*/false,
+                       inst);
+}
+
+template void KelvinVSt<int8_t>(bool, bool, bool, Instruction *);
+template void KelvinVSt<int16_t>(bool, bool, bool, Instruction *);
+template void KelvinVSt<int32_t>(bool, bool, bool, Instruction *);
+
+template <typename T>
+void KelvinVStQ(bool strip_mine, Instruction *inst) {
+  VectorStoreHelper<T>(/*has_length=*/false, /*has_stride=*/true, strip_mine,
+                       /*is_quad=*/true, inst);
+}
+
+template void KelvinVStQ<int8_t>(bool, Instruction *);
+template void KelvinVStQ<int16_t>(bool, Instruction *);
+template void KelvinVStQ<int32_t>(bool, Instruction *);
+
+// Return the supported vl length. It starts with the maximum value based on
+// vector_length and then is capped to the minimum by the additional inputs.
+template <typename T>
+void KelvinGetVl(bool strip_mine, bool is_rs1, bool is_rs2,
+                 const mpact::sim::generic::Instruction *inst) {
+  auto *dest_reg =
+      static_cast<mpact::sim::generic::RegisterDestinationOperand<uint32_t> *>(
+          inst->Destination(0))
+          ->GetRegister();
+  auto state = static_cast<KelvinState *>(inst->state());
+  const int vector_size_in_bytes = state->vector_length() / 8;
+  uint32_t vlen = vector_size_in_bytes / sizeof(T);
+  if (strip_mine) {
+    vlen *= 4;
+  }
+
+  if (is_rs1) {
+    uint32_t rs1 = mpact::sim::generic::GetInstructionSource<uint32_t>(inst, 0);
+    vlen = std::min(vlen, rs1);
+  }
+  if (is_rs2) {
+    uint32_t rs2 = mpact::sim::generic::GetInstructionSource<uint32_t>(inst, 1);
+    vlen = std::min(vlen, rs2);
+  }
+  dest_reg->data_buffer()->Set<uint32_t>(0, vlen);
+}
+template void KelvinGetVl<int8_t>(bool, bool, bool, const Instruction *);
+template void KelvinGetVl<int16_t>(bool, bool, bool, const Instruction *);
+template void KelvinGetVl<int32_t>(bool, bool, bool, const Instruction *);
+
+}  // namespace kelvin::sim
diff --git a/sim/kelvin_vector_memory_instructions.h b/sim/kelvin_vector_memory_instructions.h
new file mode 100644
index 0000000..f62a9c5
--- /dev/null
+++ b/sim/kelvin_vector_memory_instructions.h
@@ -0,0 +1,30 @@
+#ifndef SIM_KELVIN_VECTOR_MEMORY_INSTRUCTIONS_H_
+#define SIM_KELVIN_VECTOR_MEMORY_INSTRUCTIONS_H_
+
+#include "mpact/sim/generic/instruction.h"
+
+namespace kelvin::sim {
+
+using mpact::sim::generic::Instruction;
+
+template <typename T>
+void KelvinVLd(bool has_length, bool has_stride, bool strip_mine,
+               Instruction *inst);
+
+template <typename T>
+void KelvinVLdRegWrite(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinVSt(bool has_length, bool has_stride, bool strip_mine,
+               Instruction *inst);
+
+template <typename T>
+void KelvinVStQ(bool strip_mine, Instruction *inst);
+
+template <typename T>
+void KelvinGetVl(bool strip_mine, bool is_rs1, bool is_rs2,
+                 const mpact::sim::generic::Instruction *inst);
+
+}  // namespace kelvin::sim
+
+#endif  // SIM_KELVIN_VECTOR_MEMORY_INSTRUCTIONS_H_
diff --git a/sim/test/BUILD b/sim/test/BUILD
new file mode 100644
index 0000000..735c876
--- /dev/null
+++ b/sim/test/BUILD
@@ -0,0 +1,123 @@
+# Unit tests for kelvin simulator.
+
+exports_files([
+    "testfiles/hello_world_rv32imf.elf",
+    "testfiles/rv32i.elf",
+    "testfiles/rv32m.elf",
+    "testfiles/rv32soft_fp.elf",
+])
+
+cc_test(
+    name = "kelvin_encoding_test",
+    size = "small",
+    srcs = [
+        "kelvin_encoding_test.cc",
+    ],
+    deps = [
+        "//sim:kelvin_decoder",
+        "//sim:kelvin_state",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "kelvin_decoder_test",
+    size = "small",
+    srcs = [
+        "kelvin_decoder_test.cc",
+    ],
+    data = [
+        "testfiles/hello_world_rv32imf.elf",
+    ],
+    deps = [
+        "//sim:kelvin_decoder",
+        "//sim:kelvin_state",
+        "@com_github_serge1_elfio//:elfio",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/log:check",
+        "@com_google_googletest//:gtest_main",
+        "@com_google_mpact-sim//mpact/sim/generic:instruction",
+        "@com_google_mpact-sim//mpact/sim/util/memory",
+        "@com_google_mpact-sim//mpact/sim/util/program_loader:elf_loader",
+    ],
+)
+
+cc_test(
+    name = "kelvin_top_test",
+    size = "small",
+    srcs = [
+        "kelvin_top_test.cc",
+    ],
+    data = [
+        "testfiles/hello_world_mpause.elf",
+        "testfiles/hello_world_rv32imf.elf",
+        "testfiles/rv32i.elf",
+        "testfiles/rv32m.elf",
+        "testfiles/rv32soft_fp.elf",
+    ],
+    deps = [
+        "//sim:kelvin_top",
+        "@com_google_absl//absl/flags:flag",
+        "@com_google_absl//absl/log:check",
+        "@com_google_absl//absl/status",
+        "@com_google_googletest//:gtest_main",
+        "@com_google_mpact-sim//mpact/sim/generic:core",
+        "@com_google_mpact-sim//mpact/sim/util/memory",
+        "@com_google_mpact-sim//mpact/sim/util/program_loader:elf_loader",
+    ],
+)
+
+cc_library(
+    name = "kelvin_vector_instructions_test_base",
+    testonly = True,
+    hdrs = ["kelvin_vector_instructions_test_base.h"],
+    copts = [
+        "-Werror",
+        "-Wvla-extension",
+    ],
+    deps = [
+        "//sim:kelvin_state",
+        "@com_google_absl//absl/random",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/types:span",
+        "@com_google_mpact-riscv//riscv:riscv_state",
+        "@com_google_mpact-sim//mpact/sim/generic:arch_state",
+        "@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",
+        "@com_google_mpact-sim//mpact/sim/util/memory",
+    ],
+)
+
+cc_test(
+    name = "kelvin_vector_instructions_test",
+    srcs = ["kelvin_vector_instructions_test.cc"],
+    copts = [
+        "-Werror",
+        "-Wvla-extension",
+    ],
+    deps = [
+        ":kelvin_vector_instructions_test_base",
+        "//sim:kelvin_instructions",
+        "@com_google_absl//absl/functional:bind_front",
+        "@com_google_absl//absl/strings",
+        "@com_google_googletest//:gtest_main",
+        "@com_google_mpact-sim//mpact/sim/generic:instruction",
+    ],
+)
+
+cc_test(
+    name = "kelvin_log_instructions_test",
+    srcs = ["kelvin_log_instructions_test.cc"],
+    copts = [
+        "-Werror",
+        "-Wvla-extension",
+    ],
+    deps = [
+        ":kelvin_vector_instructions_test_base",
+        "//sim:kelvin_instructions",
+        "@com_google_absl//absl/functional:bind_front",
+        "@com_google_googletest//:gtest_main",
+        "@com_google_mpact-sim//mpact/sim/generic:instruction",
+    ],
+)
diff --git a/sim/test/kelvin_decoder_test.cc b/sim/test/kelvin_decoder_test.cc
new file mode 100644
index 0000000..9404238
--- /dev/null
+++ b/sim/test/kelvin_decoder_test.cc
@@ -0,0 +1,101 @@
+#include <ios>
+#include <string>
+
+#include "sim/decoder.h"
+#include "sim/kelvin_state.h"
+#include "googletest/include/gtest/gtest.h"
+#include "absl/log/check.h"
+#include "absl/log/log.h"
+#include "elfio/elfio.hpp"
+#include "elfio/elfio_section.hpp"
+#include "elfio/elfio_symbols.hpp"
+#include "mpact/sim/generic/instruction.h"
+#include "mpact/sim/util/memory/flat_demand_memory.h"
+#include "mpact/sim/util/program_loader/elf_program_loader.h"
+
+namespace {
+
+using ::mpact::sim::riscv::RiscVXlen;
+
+constexpr char kFileName[] = "hello_world_rv32imf.elf";
+
+// The depot path to the test directory.
+constexpr char kDepotPath[] = "sim/test/";
+
+using SymbolAccessor = ELFIO::symbol_section_accessor_template<ELFIO::section>;
+
+class KelvinDecoderTest : public testing::Test {
+ protected:
+  KelvinDecoderTest()
+      : state_("kelvin_decoder_test", RiscVXlen::RV32),
+        memory_(0),
+        loader_(&memory_),
+        decoder_(&state_, &memory_) {
+    const std::string input_file =
+        absl::StrCat(kDepotPath, "testfiles/", kFileName);
+    auto result = loader_.LoadProgram(input_file);
+    CHECK_OK(result.status());
+    elf_reader_.load(input_file);
+    auto *symtab = elf_reader_.sections[".symtab"];
+    CHECK_NE(symtab, nullptr);
+    symbol_accessor_ = new SymbolAccessor(elf_reader_, symtab);
+  }
+
+  ~KelvinDecoderTest() override { delete symbol_accessor_; }
+
+  ELFIO::elfio elf_reader_;
+  kelvin::sim::KelvinState state_;
+  mpact::sim::util::FlatDemandMemory memory_;
+  mpact::sim::util::ElfProgramLoader loader_;
+  kelvin::sim::KelvinDecoder decoder_;
+  SymbolAccessor *symbol_accessor_;
+};
+
+// This test is really pretty simple. It decodes the instructions in "main".
+// The goal of this test is not so much to ensure that the decoder is accurate,
+// but that the decoder returns a non-null instruction object for each address
+// in main, and that executing this instruction does not generate an error.
+TEST_F(KelvinDecoderTest, HelloWorldMain) {
+  ELFIO::Elf64_Addr value;
+  ELFIO::Elf_Xword size;
+  unsigned char bind;
+  unsigned char type;
+  ELFIO::Elf_Half section_index;
+  unsigned char other;
+  bool success = symbol_accessor_->get_symbol("main", value, size, bind, type,
+                                              section_index, other);
+  ASSERT_TRUE(success);
+  uint64_t address = value;
+  while (address < value + size) {
+    LOG(INFO) << "Address: " << std::hex << address;
+    EXPECT_FALSE(state_.program_error_controller()->HasError());
+    auto *inst = decoder_.DecodeInstruction(address);
+    ASSERT_NE(inst, nullptr);
+    inst->Execute(nullptr);
+    if (state_.program_error_controller()->HasError()) {
+      auto errvec = state_.program_error_controller()->GetUnmaskedErrorNames();
+      for (auto &err : errvec) {
+        LOG(INFO) << "Error: " << err;
+        auto msgvec = state_.program_error_controller()->GetErrorMessages(err);
+        for (auto &msg : msgvec) {
+          LOG(INFO) << "    " << msg;
+        }
+      }
+    }
+    EXPECT_FALSE(state_.program_error_controller()->HasError());
+    state_.program_error_controller()->ClearAll();
+    address += inst->size();
+    inst->DecRef();
+    state_.AdvanceDelayLines();
+  }
+}
+
+// Even with a bad address, a valid instruction object should be returned.
+TEST_F(KelvinDecoderTest, BadAddress) {
+  auto *inst = decoder_.DecodeInstruction(0x4321);
+  ASSERT_NE(inst, nullptr);
+  inst->Execute(nullptr);
+  inst->DecRef();
+}
+
+}  // namespace
diff --git a/sim/test/kelvin_encoding_test.cc b/sim/test/kelvin_encoding_test.cc
new file mode 100644
index 0000000..96a3db4
--- /dev/null
+++ b/sim/test/kelvin_encoding_test.cc
@@ -0,0 +1,290 @@
+#include "sim/kelvin_encoding.h"
+
+#include "sim/kelvin_state.h"
+#include "googletest/include/gtest/gtest.h"
+
+namespace {
+
+using kelvin::sim::KelvinState;
+using kelvin::sim::isa32::KelvinEncoding;
+using SlotEnum = kelvin::sim::isa32::SlotEnum;
+using OpcodeEnum = kelvin::sim::isa32::OpcodeEnum;
+
+// RV32I
+constexpr uint32_t kLui = 0b0000000000000000000000000'0110111;
+constexpr uint32_t kAuipc = 0b0000000000000000000000000'0010111;
+constexpr uint32_t kJal = 0b00000000000000000000'00000'1101111;
+constexpr uint32_t kJalr = 0b00000000000'00000'000'00000'1100111;
+constexpr uint32_t kBeq = 0b0000000'00000'00000'000'00000'1100011;
+constexpr uint32_t kBne = 0b0000000'00000'00000'001'00000'1100011;
+constexpr uint32_t kBlt = 0b0000000'00000'00000'100'00000'1100011;
+constexpr uint32_t kBge = 0b0000000'00000'00000'101'00000'1100011;
+constexpr uint32_t kBltu = 0b0000000'00000'00000'110'00000'1100011;
+constexpr uint32_t kBgeu = 0b0000000'00000'00000'111'00000'1100011;
+constexpr uint32_t kLb = 0b000000000000'00000'000'00000'0000011;
+constexpr uint32_t kLh = 0b000000000000'00000'001'00000'0000011;
+constexpr uint32_t kLw = 0b000000000000'00000'010'00000'0000011;
+constexpr uint32_t kLbu = 0b000000000000'00000'100'00000'0000011;
+constexpr uint32_t kLhu = 0b000000000000'00000'101'00000'0000011;
+constexpr uint32_t kSb = 0b0000000'00000'00000'000'00000'0100011;
+constexpr uint32_t kSh = 0b0000000'00000'00000'001'00000'0100011;
+constexpr uint32_t kSw = 0b0000000'00000'00000'010'00000'0100011;
+constexpr uint32_t kAddi = 0b000000000000'00000'000'00000'0010011;
+constexpr uint32_t kSlti = 0b000000000000'00000'010'00000'0010011;
+constexpr uint32_t kSltiu = 0b000000000000'00000'011'00000'0010011;
+constexpr uint32_t kXori = 0b000000000000'00000'100'00000'0010011;
+constexpr uint32_t kOri = 0b000000000000'00000'110'00000'0010011;
+constexpr uint32_t kAndi = 0b000000000000'00000'111'00000'0010011;
+constexpr uint32_t kSlli = 0b0000000'00000'00000'001'00000'0010011;
+constexpr uint32_t kSrli = 0b0000000'00000'00000'101'00000'0010011;
+constexpr uint32_t kSrai = 0b0100000'00000'00000'101'00000'0010011;
+constexpr uint32_t kAdd = 0b0000000'00000'00000'000'00000'0110011;
+constexpr uint32_t kSub = 0b0100000'00000'00000'000'00000'0110011;
+constexpr uint32_t kSll = 0b0000000'00000'00000'001'00000'0110011;
+constexpr uint32_t kSlt = 0b0000000'00000'00000'010'00000'0110011;
+constexpr uint32_t kSltu = 0b0000000'00000'00000'011'00000'0110011;
+constexpr uint32_t kXor = 0b0000000'00000'00000'100'00000'0110011;
+constexpr uint32_t kSrl = 0b0000000'00000'00000'101'00000'0110011;
+constexpr uint32_t kSra = 0b0100000'00000'00000'101'00000'0110011;
+constexpr uint32_t kOr = 0b0000000'00000'00000'110'00000'0110011;
+constexpr uint32_t kAnd = 0b0000000'00000'00000'111'00000'0110011;
+constexpr uint32_t kFence = 0b000000000000'00000'000'00000'0001111;
+constexpr uint32_t kEcall = 0b000000000000'00000'000'00000'1110011;
+constexpr uint32_t kEbreak = 0b000000000001'00000'000'00000'1110011;
+constexpr uint32_t kMpause = 0b000010000000'00000'000'00000'1110011;
+// Kelvin Memory ops
+constexpr uint32_t kFlushall = 0b001001100000'00000'000'00000'1110111;
+constexpr uint32_t kFlushat = 0b001001100000'00000'000'00000'1110111;
+// RV32 Zifencei
+constexpr uint32_t kFencei = 0b000000000000'00000'001'00000'0001111;
+// RV32 Zicsr
+constexpr uint32_t kCsrw = 0b000000000000'00000'001'00000'1110011;
+constexpr uint32_t kCsrs = 0b000000000000'00000'010'00000'1110011;
+constexpr uint32_t kCsrc = 0b000000000000'00000'011'00000'1110011;
+constexpr uint32_t kCsrwi = 0b000000000000'00000'101'00000'1110011;
+constexpr uint32_t kCsrsi = 0b000000000000'00000'110'00000'1110011;
+constexpr uint32_t kCsrci = 0b000000000000'00000'111'00000'1110011;
+// RV32M
+constexpr uint32_t kMul = 0b0000001'00000'00000'000'00000'0110011;
+constexpr uint32_t kMulh = 0b0000001'00000'00000'001'00000'0110011;
+constexpr uint32_t kMulhsu = 0b0000001'00000'00000'010'00000'0110011;
+constexpr uint32_t kMulhu = 0b0000001'00000'00000'011'00000'0110011;
+constexpr uint32_t kDiv = 0b0000001'00000'00000'100'00000'0110011;
+constexpr uint32_t kDivu = 0b0000001'00000'00000'101'00000'0110011;
+constexpr uint32_t kRem = 0b0000001'00000'00000'110'00000'0110011;
+constexpr uint32_t kRemu = 0b0000001'00000'00000'111'00000'0110011;
+
+// Kelvin System Op
+constexpr uint32_t kGetMaxVl = 0b0001'0'00'00000'00000'000'00000'111'0111;
+
+// Kelvin Logging Op
+constexpr uint32_t kFLog = 0b011'1100'00000'00000'000'00000'111'0111;
+
+class KelvinEncodingTest : public testing::Test {
+ protected:
+  KelvinEncodingTest() {
+    state_ = new KelvinState("test", mpact::sim::riscv::RiscVXlen::RV32);
+    enc_ = new KelvinEncoding(state_);
+  }
+  ~KelvinEncodingTest() override {
+    delete enc_;
+    delete state_;
+  }
+
+  KelvinState *state_;
+  KelvinEncoding *enc_;
+};
+
+constexpr int kRdValue = 1;
+constexpr int kSuccValue = 0xf;
+constexpr int kPredValue = 0xf;
+
+static uint32_t SetRd(uint32_t iword, uint32_t rdval) {
+  return (iword | ((rdval & 0x1f) << 7));
+}
+
+static uint32_t SetRs1(uint32_t iword, uint32_t rsval) {
+  return (iword | ((rsval & 0x1f) << 15));
+}
+
+static uint32_t SetRs2(uint32_t iword, uint32_t rsval) {
+  return (iword | ((rsval & 0x1f) << 20));
+}
+
+static uint32_t SetPred(uint32_t iword, uint32_t pred) {
+  return (iword | ((pred & 0xf) << 24));
+}
+
+static uint32_t SetSucc(uint32_t iword, uint32_t succ) {
+  return (iword | ((succ & 0xf) << 20));
+}
+
+TEST_F(KelvinEncodingTest, RV32IOpcodes) {
+  enc_->ParseInstruction(SetRd(kLui, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLui);
+  enc_->ParseInstruction(SetRd(kAuipc, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kAuipc);
+  enc_->ParseInstruction(SetRd(kJal, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kJal);
+  enc_->ParseInstruction(SetRd(kJalr, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kJalr);
+  enc_->ParseInstruction(kBeq);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kBeq);
+  enc_->ParseInstruction(kBne);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kBne);
+  enc_->ParseInstruction(kBlt);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kBlt);
+  enc_->ParseInstruction(kBge);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kBge);
+  enc_->ParseInstruction(kBltu);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kBltu);
+  enc_->ParseInstruction(kBgeu);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kBgeu);
+  enc_->ParseInstruction(SetRd(kLb, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLb);
+  enc_->ParseInstruction(SetRd(kLh, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLh);
+  enc_->ParseInstruction(SetRd(kLw, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLw);
+  enc_->ParseInstruction(SetRd(kLbu, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLbu);
+  enc_->ParseInstruction(SetRd(kLhu, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kLhu);
+  enc_->ParseInstruction(SetRd(kSb, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSb);
+  enc_->ParseInstruction(SetRd(kSh, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSh);
+  enc_->ParseInstruction(SetRd(kSw, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSw);
+  enc_->ParseInstruction(SetRd(kAddi, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kAddi);
+  enc_->ParseInstruction(SetRd(kSlti, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSlti);
+  enc_->ParseInstruction(SetRd(kSltiu, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSltiu);
+  enc_->ParseInstruction(SetRd(kXori, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kXori);
+  enc_->ParseInstruction(SetRd(kOri, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kOri);
+  enc_->ParseInstruction(SetRd(kAndi, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kAndi);
+  enc_->ParseInstruction(SetRd(kSlli, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSlli);
+  enc_->ParseInstruction(SetRd(kSrli, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSrli);
+  enc_->ParseInstruction(SetRd(kSrai, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSrai);
+  enc_->ParseInstruction(SetRd(kAdd, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kAdd);
+  enc_->ParseInstruction(SetRd(kSub, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSub);
+  enc_->ParseInstruction(SetRd(kSll, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSll);
+  enc_->ParseInstruction(SetRd(kSlt, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSlt);
+  enc_->ParseInstruction(SetRd(kSltu, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSltu);
+  enc_->ParseInstruction(SetRd(kXor, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kXor);
+  enc_->ParseInstruction(SetRd(kSrl, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSrl);
+  enc_->ParseInstruction(SetRd(kSra, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSra);
+  enc_->ParseInstruction(SetRd(kOr, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kOr);
+  enc_->ParseInstruction(SetRd(kAnd, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kAnd);
+  enc_->ParseInstruction(SetSucc(SetPred(kFence, kPredValue), kSuccValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kFence);
+  enc_->ParseInstruction(kEcall);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kEcall);
+  enc_->ParseInstruction(kEbreak);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kEbreak);
+  enc_->ParseInstruction(kMpause);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kMpause);
+}
+
+TEST_F(KelvinEncodingTest, KelvinMemoryOpcodes) {
+  enc_->ParseInstruction(kFlushall);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kFlushall);
+  enc_->ParseInstruction(SetRs1(kFlushat, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kFlushat);
+}
+
+TEST_F(KelvinEncodingTest, KelvinSystemOpcodes) {
+  enc_->ParseInstruction(SetRd(kGetMaxVl, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kGetmaxvlB);
+  enc_->ParseInstruction(SetRd(SetRs1(kGetMaxVl, kRdValue), kRdValue) |
+                         (0b1) << 25);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kGetvlHX);
+  enc_->ParseInstruction(
+      SetRd(SetRs1(SetRs2(kGetMaxVl, kRdValue), kRdValue), kRdValue) |
+      (0b10 << 25));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kGetvlWXx);
+}
+
+TEST_F(KelvinEncodingTest, KelvinLogOpcodes) {
+  enc_->ParseInstruction(SetRs1(kFLog, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kFlog);
+  enc_->ParseInstruction(SetRs1(kFLog, kRdValue) | (0b01 << 12));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kSlog);
+  enc_->ParseInstruction(SetRs1(kFLog, kRdValue) | (0b10 << 12));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kClog);
+  enc_->ParseInstruction(SetRs1(kFLog, kRdValue) | (0b11 << 12));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kKlog);
+}
+
+TEST_F(KelvinEncodingTest, ZifenceiOpcodes) {
+  // RV32 Zifencei
+  enc_->ParseInstruction(kFencei);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kFencei);
+}
+
+TEST_F(KelvinEncodingTest, ZicsrOpcodes) {
+  // RV32 Zicsr
+  enc_->ParseInstruction(SetRd(kCsrw, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrw);
+  enc_->ParseInstruction(SetRd(SetRs1(kCsrs, kRdValue), kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrs);
+  enc_->ParseInstruction(SetRd(SetRs1(kCsrc, kRdValue), kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrc);
+  enc_->ParseInstruction(kCsrw);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrwNr);
+  enc_->ParseInstruction(kCsrs);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrsNw);
+  enc_->ParseInstruction(kCsrc);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrcNw);
+  enc_->ParseInstruction(SetRd(kCsrwi, kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrwi);
+  enc_->ParseInstruction(SetRd(SetRs1(kCsrsi, kRdValue), kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrsi);
+  enc_->ParseInstruction(SetRd(SetRs1(kCsrci, kRdValue), kRdValue));
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrci);
+  enc_->ParseInstruction(kCsrwi);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrwiNr);
+  enc_->ParseInstruction(kCsrsi);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrsiNw);
+  enc_->ParseInstruction(kCsrci);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kCsrrciNw);
+}
+
+TEST_F(KelvinEncodingTest, RV32MOpcodes) {
+  // RV32M
+  enc_->ParseInstruction(kMul);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kMul);
+  enc_->ParseInstruction(kMulh);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kMulh);
+  enc_->ParseInstruction(kMulhsu);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kMulhsu);
+  enc_->ParseInstruction(kMulhu);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kMulhu);
+  enc_->ParseInstruction(kDiv);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kDiv);
+  enc_->ParseInstruction(kDivu);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kDivu);
+  enc_->ParseInstruction(kRem);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kRem);
+  enc_->ParseInstruction(kRemu);
+  EXPECT_EQ(enc_->GetOpcode(SlotEnum::kKelvin, 0), OpcodeEnum::kRemu);
+}
+}  // namespace
diff --git a/sim/test/kelvin_log_instructions_test.cc b/sim/test/kelvin_log_instructions_test.cc
new file mode 100644
index 0000000..093b610
--- /dev/null
+++ b/sim/test/kelvin_log_instructions_test.cc
@@ -0,0 +1,176 @@
+#include <sys/types.h>
+
+#include <array>
+#include <cstdint>
+#include <string>
+
+#include "sim/kelvin_instructions.h"
+#include "sim/test/kelvin_vector_instructions_test_base.h"
+#include "googletest/include/gtest/gtest.h"
+#include "absl/functional/bind_front.h"
+#include "mpact/sim/generic/instruction.h"
+
+// Test Kelvin logging instruction functionality
+
+namespace {
+
+// Semantic function
+using kelvin::sim::KelvinLogInstruction;
+
+constexpr uint32_t kMemAddress = 0x1000;
+
+class KelvinLogInstructionsTest
+    : public kelvin::sim::test::KelvinVectorInstructionsTestBase {};
+
+TEST_F(KelvinLogInstructionsTest, SimplePrint) {
+  constexpr char kHelloString[] = "Hello World!\n";
+
+  // Initialize memory.
+  auto *db = state_->db_factory()->Allocate<char>(sizeof(kHelloString));
+  for (int i = 0; i < sizeof(kHelloString); ++i) {
+    db->Set<char>(i, kHelloString[i]);
+  }
+  db->DecRef();
+
+  auto instruction = CreateInstruction();
+  state_->StoreMemory(instruction.get(), kMemAddress, db);
+  AppendRegisterOperands(instruction.get(), {kelvin::sim::test::kRs1Name}, {});
+  SetRegisterValues<uint32_t>({{kelvin::sim::test::kRs1Name, kMemAddress}});
+  instruction->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/0));
+
+  // Execute the instruction and check the stdout.
+  testing::internal::CaptureStdout();
+  instruction->Execute(nullptr);
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ(kHelloString, stdout_str);
+}
+
+TEST_F(KelvinLogInstructionsTest, PrintNumer) {
+  constexpr char kFormatString[] = "Hello %d\n";
+  constexpr uint32_t kPrintNum = 1337;
+
+  // Initialize memory.
+  auto *db = state_->db_factory()->Allocate<char>(sizeof(kFormatString));
+  for (int i = 0; i < sizeof(kFormatString); ++i) {
+    db->Set<char>(i, kFormatString[i]);
+  }
+  db->DecRef();
+
+  std::array<InstructionPtr, 2> instructions = {CreateInstruction(),
+                                                CreateInstruction()};
+
+  AppendRegisterOperands(instructions[0].get(), {kelvin::sim::test::kRs1Name},
+                         {});
+  instructions[0]->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/1));  // scalar log
+
+  // Set the second instruction for the actual print out.
+  state_->StoreMemory(instructions[1].get(), kMemAddress, db);
+  AppendRegisterOperands(instructions[1].get(), {kelvin::sim::test::kRs2Name},
+                         {});
+  instructions[1]->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/0));
+
+  SetRegisterValues<uint32_t>({{kelvin::sim::test::kRs1Name, kPrintNum},
+                               {kelvin::sim::test::kRs2Name, kMemAddress}});
+
+  testing::internal::CaptureStdout();
+  for (int i = 0; i < instructions.size(); ++i) {
+    instructions[i]->Execute(nullptr);
+  }
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("Hello 1337\n", stdout_str);
+}
+
+TEST_F(KelvinLogInstructionsTest, PrintCharacterStream) {
+  constexpr char kFormatString[] = "%s World\n";
+  constexpr uint32_t kCharStream[] = {0x6c6c6548, 0x0000006f};  // "Hello"
+
+  // Initialize memory.
+  auto *db = state_->db_factory()->Allocate<char>(sizeof(kFormatString));
+  for (int i = 0; i < sizeof(kFormatString); ++i) {
+    db->Set<char>(i, kFormatString[i]);
+  }
+  db->DecRef();
+  std::array<InstructionPtr, 3> instructions = {
+      CreateInstruction(), CreateInstruction(), CreateInstruction()};
+  AppendRegisterOperands(instructions[0].get(), {kelvin::sim::test::kRs1Name},
+                         {});
+  AppendRegisterOperands(instructions[1].get(), {kelvin::sim::test::kRs2Name},
+                         {});
+  for (int i = 0; i < 2; ++i) {
+    instructions[i]->set_semantic_function(
+        absl::bind_front(&KelvinLogInstruction, /*mode=*/2));  // character log
+  }
+
+  constexpr char kRs3Name[] = "x3";
+  state_->StoreMemory(instructions[2].get(), kMemAddress, db);
+  AppendRegisterOperands(instructions[2].get(), {kRs3Name}, {});
+  instructions[2]->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/0));
+
+  SetRegisterValues<uint32_t>({{kelvin::sim::test::kRs1Name, kCharStream[0]},
+                               {kelvin::sim::test::kRs2Name, kCharStream[1]},
+                               {kRs3Name, kMemAddress}});
+
+  testing::internal::CaptureStdout();
+  for (int i = 0; i < instructions.size(); ++i) {
+    instructions[i]->Execute(nullptr);
+  }
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("Hello World\n", stdout_str);
+}
+
+TEST_F(KelvinLogInstructionsTest, PrintTwoArguments) {
+  constexpr char kFormatString[] = "%s World %d\n";
+  constexpr uint32_t kCharStream = 0x00006948;  // "Hi"
+  constexpr uint32_t kPrintNum = 1337;
+
+  // Initialize memory.
+  auto *db = state_->db_factory()->Allocate<char>(sizeof(kFormatString));
+  for (int i = 0; i < sizeof(kFormatString); ++i) {
+    db->Set<char>(i, kFormatString[i]);
+  }
+  db->DecRef();
+
+  std::array<InstructionPtr, 3> instructions = {
+      CreateInstruction(), CreateInstruction(), CreateInstruction()};
+
+  // Also store the kCharStream elsewhere in the memory.
+  auto *str_db = state_->db_factory()->Allocate<uint32_t>(sizeof(1));
+  str_db->Set<uint32_t>(0, kCharStream);
+  str_db->DecRef();
+
+  constexpr uint32_t kStrMemAddress = kMemAddress + 20;
+  state_->StoreMemory(instructions[0].get(), kStrMemAddress, str_db);
+  AppendRegisterOperands(instructions[0].get(), {kelvin::sim::test::kRs1Name},
+                         {});
+  instructions[0]->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/3));
+
+  AppendRegisterOperands(instructions[1].get(), {kelvin::sim::test::kRs2Name},
+                         {});
+  instructions[1]->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/1));
+
+  constexpr char kRs3Name[] = "x3";
+  state_->StoreMemory(instructions[2].get(), kMemAddress, db);
+  AppendRegisterOperands(instructions[2].get(), {kRs3Name}, {});
+  instructions[2]->set_semantic_function(
+      absl::bind_front(&KelvinLogInstruction, /*mode=*/0));
+
+  SetRegisterValues<uint32_t>({{kelvin::sim::test::kRs1Name, kStrMemAddress},
+                               {kelvin::sim::test::kRs2Name, kPrintNum},
+                               {kRs3Name, kMemAddress}});
+
+  // Execute the instructions.
+  testing::internal::CaptureStdout();
+  for (int i = 0; i < instructions.size(); ++i) {
+    instructions[i]->Execute(nullptr);
+  }
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("Hi World 1337\n", stdout_str);
+}
+
+}  // namespace
diff --git a/sim/test/kelvin_top_test.cc b/sim/test/kelvin_top_test.cc
new file mode 100644
index 0000000..d8f1546
--- /dev/null
+++ b/sim/test/kelvin_top_test.cc
@@ -0,0 +1,316 @@
+#include "sim/kelvin_top.h"
+
+#include <cstdint>
+#include <string>
+
+#include "googlemock/include/gmock/gmock.h"
+#include "googletest/include/gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/log/check.h"
+#include "absl/status/status.h"
+#include "mpact/sim/generic/core_debug_interface.h"
+#include "mpact/sim/util/memory/flat_demand_memory.h"
+#include "mpact/sim/util/program_loader/elf_program_loader.h"
+
+namespace {
+
+#ifndef EXPECT_OK
+#define EXPECT_OK(x) EXPECT_TRUE(x.ok())
+#endif
+
+using ::kelvin::sim::KelvinTop;
+using ::mpact::sim::util::ElfProgramLoader;
+using ::mpact::sim::util::FlatDemandMemory;
+
+using HaltReason = ::mpact::sim::generic::CoreDebugInterface::HaltReason;
+constexpr char kMpauseElfFileName[] = "hello_world_mpause.elf";
+constexpr char kRV32imfElfFileName[] = "hello_world_rv32imf.elf";
+constexpr char kRV32iElfFileName[] = "rv32i.elf";
+constexpr char kRV32mElfFileName[] = "rv32m.elf";
+constexpr char kRV32SoftFloatElfFileName[] = "rv32soft_fp.elf";
+
+// The depot path to the test directory.
+constexpr char kDepotPath[] = "sim/test/";
+
+class KelvinTopTest : public testing::Test {
+ protected:
+  KelvinTopTest() {
+    memory_ = new FlatDemandMemory();
+    kelvin_top_ = new KelvinTop("Kelvin");
+    // Set up the elf loader.
+    loader_ = new ElfProgramLoader(kelvin_top_->memory());
+  }
+
+  ~KelvinTopTest() override {
+    delete loader_;
+    delete kelvin_top_;
+    delete memory_;
+  }
+
+  void LoadFile(const std::string file_name) {
+    const std::string input_file_name =
+        absl::StrCat(kDepotPath, "testfiles/", file_name);
+    auto result = loader_->LoadProgram(input_file_name);
+    CHECK_OK(result);
+    entry_point_ = result.value();
+  }
+
+  uint32_t entry_point_;
+  KelvinTop *kelvin_top_ = nullptr;
+  ElfProgramLoader *loader_ = nullptr;
+  FlatDemandMemory *memory_ = nullptr;
+};
+
+// Runs the program from beginning to end.
+TEST_F(KelvinTopTest, RunHelloProgram) {
+  LoadFile(kRV32imfElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSoftwareBreakpoint));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("Hit breakpoint or program exits with fault\n", stdout_str);
+}
+
+// Runs the program from beginning to end. Enable arm semihosting.
+TEST_F(KelvinTopTest, RunHelloProgramSemihost) {
+  absl::SetFlag(&FLAGS_use_semihost, true);
+  LoadFile(kRV32imfElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSemihostHaltRequest));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("Hello, World! 7\n", stdout_str);
+  absl::SetFlag(&FLAGS_use_semihost, false);
+}
+
+// Runs the program ended with mpause from beginning to end.
+TEST_F(KelvinTopTest, RunHelloMpauseProgram) {
+  LoadFile(kMpauseElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSoftwareBreakpoint));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("Program exits properly\n", stdout_str);
+}
+
+// Runs the rv32i program with arm semihosting.
+TEST_F(KelvinTopTest, RunRV32IProgram) {
+  absl::SetFlag(&FLAGS_use_semihost, true);
+  LoadFile(kRV32iElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSemihostHaltRequest));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("5+5=10;5-5=0\n", stdout_str);
+  absl::SetFlag(&FLAGS_use_semihost, false);
+}
+
+// Runs the rv32m program with arm semihosting.
+TEST_F(KelvinTopTest, RunRV32MProgram) {
+  absl::SetFlag(&FLAGS_use_semihost, true);
+  LoadFile(kRV32mElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSemihostHaltRequest));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("5*5=25;5/5=1\n", stdout_str);
+  absl::SetFlag(&FLAGS_use_semihost, false);
+}
+
+// Runs the rv32 soft float program with arm semihosting.
+TEST_F(KelvinTopTest, RunRV32SoftFProgram) {
+  absl::SetFlag(&FLAGS_use_semihost, true);
+  LoadFile(kRV32SoftFloatElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSemihostHaltRequest));
+  const std::string stdout_str = testing::internal::GetCapturedStdout();
+  EXPECT_EQ("7.00+3.00=10.00;7.00-3.00=4.00;7.00*3.00=21.00;7.00/3.00=2.33\n",
+            stdout_str);
+  absl::SetFlag(&FLAGS_use_semihost, false);
+}
+
+// Steps through the program from beginning to end.
+TEST_F(KelvinTopTest, StepProgram) {
+  LoadFile(kRV32imfElfFileName);
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+
+  auto res = kelvin_top_->Step(10000);
+  EXPECT_OK(res.status());
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSoftwareBreakpoint));
+
+  EXPECT_EQ("Hit breakpoint or program exits with fault\n",
+            testing::internal::GetCapturedStdout());
+}
+
+// Sets/Clears breakpoints without executing the program.
+TEST_F(KelvinTopTest, SetAndClearBreakpoint) {
+  LoadFile(kRV32imfElfFileName);
+  auto result = loader_->GetSymbol("printf");
+  EXPECT_OK(result);
+  auto address = result.value().first;
+  EXPECT_EQ(kelvin_top_->ClearSwBreakpoint(address).code(),
+            absl::StatusCode::kNotFound);
+  EXPECT_OK(kelvin_top_->SetSwBreakpoint(address));
+  EXPECT_EQ(kelvin_top_->SetSwBreakpoint(address).code(),
+            absl::StatusCode::kAlreadyExists);
+  EXPECT_OK(kelvin_top_->ClearSwBreakpoint(address));
+  EXPECT_EQ(kelvin_top_->ClearSwBreakpoint(address).code(),
+            absl::StatusCode::kNotFound);
+  EXPECT_OK(kelvin_top_->SetSwBreakpoint(address));
+  EXPECT_OK(kelvin_top_->ClearAllSwBreakpoints());
+  EXPECT_EQ(kelvin_top_->ClearSwBreakpoint(address).code(),
+            absl::StatusCode::kNotFound);
+}
+
+// Runs program with breakpoint at printf with arm semihosting.
+TEST_F(KelvinTopTest, RunWithBreakpoint) {
+  absl::SetFlag(&FLAGS_use_semihost, true);
+  LoadFile(kRV32imfElfFileName);
+
+  // Set breakpoint at printf.
+  auto result = loader_->GetSymbol("printf");
+  EXPECT_OK(result);
+  auto address = result.value().first;
+  EXPECT_OK(kelvin_top_->SetSwBreakpoint(address));
+
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+
+  // Run to printf.
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+
+  // Should be stopped at breakpoint, but nothing printed.
+  auto halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSoftwareBreakpoint));
+  EXPECT_EQ(testing::internal::GetCapturedStdout().size(), 0);
+
+  // Run to the end of the program.
+  testing::internal::CaptureStdout();
+  EXPECT_OK(kelvin_top_->Run());
+  EXPECT_OK(kelvin_top_->Wait());
+
+  // Should be stopped due to semihost halt request. Captured 'Hello World!
+  // 7\n'.
+  halt_result = kelvin_top_->GetLastHaltReason();
+  CHECK_OK(halt_result);
+  EXPECT_EQ(static_cast<int>(halt_result.value()),
+            static_cast<int>(HaltReason::kSemihostHaltRequest));
+  EXPECT_EQ("Hello, World! 7\n", testing::internal::GetCapturedStdout());
+  absl::SetFlag(&FLAGS_use_semihost, false);
+}
+
+// Memory read/write test.
+TEST_F(KelvinTopTest, Memory) {
+  uint8_t byte_data = 0xab;
+  uint16_t half_data = 0xabcd;
+  uint32_t word_data = 0xba5eba11;
+  uint64_t dword_data = 0x5ca1ab1e'0ddball;
+  EXPECT_OK(kelvin_top_->WriteMemory(0x1000, &byte_data, sizeof(byte_data)));
+  EXPECT_OK(kelvin_top_->WriteMemory(0x1004, &half_data, sizeof(half_data)));
+  EXPECT_OK(kelvin_top_->WriteMemory(0x1008, &word_data, sizeof(word_data)));
+  EXPECT_OK(kelvin_top_->WriteMemory(0x1010, &dword_data, sizeof(dword_data)));
+
+  uint8_t byte_value;
+  uint16_t half_value;
+  uint32_t word_value;
+  uint64_t dword_value;
+
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1000, &byte_value, sizeof(byte_value)));
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1004, &half_value, sizeof(half_value)));
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1008, &word_value, sizeof(word_value)));
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1010, &dword_value, sizeof(dword_value)));
+
+  EXPECT_EQ(byte_data, byte_value);
+  EXPECT_EQ(half_data, half_value);
+  EXPECT_EQ(word_data, word_value);
+  EXPECT_EQ(dword_data, dword_value);
+
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1000, &byte_value, sizeof(byte_value)));
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1000, &half_value, sizeof(half_value)));
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1000, &word_value, sizeof(word_value)));
+  EXPECT_OK(kelvin_top_->ReadMemory(0x1000, &dword_value, sizeof(dword_value)));
+
+  EXPECT_EQ(byte_data, byte_value);
+  EXPECT_EQ(byte_data, half_value);
+  EXPECT_EQ(byte_data, word_value);
+  EXPECT_EQ(0x0000'abcd'0000'00ab, dword_value);
+}
+
+// Register name test.
+TEST_F(KelvinTopTest, RegisterNames) {
+  // Test x-names and numbers.
+  uint32_t word_value;
+  for (int i = 0; i < 32; i++) {
+    std::string name = absl::StrCat("x", i);
+    auto result = kelvin_top_->ReadRegister(name);
+    EXPECT_OK(result.status());
+    word_value = result.value();
+    EXPECT_OK(kelvin_top_->WriteRegister(name, word_value));
+  }
+  // Test d-names and numbers.
+  uint64_t dword_value;
+  for (int i = 0; i < 32; i++) {
+    std::string name = absl::StrCat("f", i);
+    auto result = kelvin_top_->ReadRegister(name);
+    EXPECT_OK(result.status());
+    dword_value = result.value();
+    EXPECT_OK(kelvin_top_->WriteRegister(name, dword_value));
+  }
+  // Not found.
+  EXPECT_EQ(kelvin_top_->ReadRegister("x32").status().code(),
+            absl::StatusCode::kNotFound);
+  EXPECT_EQ(kelvin_top_->WriteRegister("x32", word_value).code(),
+            absl::StatusCode::kNotFound);
+  // Aliases.
+  for (auto &[name, alias] : {std::tuple<std::string, std::string>{"x1", "ra"},
+                              {"x4", "tp"},
+                              {"x8", "s0"}}) {
+    uint32_t write_value = 0xba5eba11;
+    EXPECT_OK(kelvin_top_->WriteRegister(name, write_value));
+    uint32_t read_value;
+    auto result = kelvin_top_->ReadRegister(alias);
+    EXPECT_OK(result.status());
+    read_value = result.value();
+    EXPECT_EQ(read_value, write_value);
+  }
+}
+
+}  // namespace
diff --git a/sim/test/kelvin_vector_instructions_test.cc b/sim/test/kelvin_vector_instructions_test.cc
new file mode 100644
index 0000000..250ffab
--- /dev/null
+++ b/sim/test/kelvin_vector_instructions_test.cc
@@ -0,0 +1,2072 @@
+#include "sim/kelvin_vector_instructions.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "sim/kelvin_vector_memory_instructions.h"
+#include "sim/test/kelvin_vector_instructions_test_base.h"
+#include "googletest/include/gtest/gtest.h"
+#include "absl/functional/bind_front.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "mpact/sim/generic/instruction.h"
+
+// This file contains the tests for testing kelvin vector instructions.
+
+namespace {
+
+using mpact::sim::generic::Instruction;
+
+// Semantic functions.
+using kelvin::sim::KelvinGetVl;
+using kelvin::sim::KelvinVAbsd;
+using kelvin::sim::KelvinVAcc;
+using kelvin::sim::KelvinVAdd;
+using kelvin::sim::KelvinVAdd3;
+using kelvin::sim::KelvinVAdds;
+using kelvin::sim::KelvinVAddsu;
+using kelvin::sim::KelvinVAddw;
+using kelvin::sim::KelvinVAnd;
+using kelvin::sim::KelvinVClb;
+using kelvin::sim::KelvinVClz;
+using kelvin::sim::KelvinVCpop;
+using kelvin::sim::KelvinVDmulh;
+using kelvin::sim::KelvinVEq;
+using kelvin::sim::KelvinVEvn;
+using kelvin::sim::KelvinVEvnodd;
+using kelvin::sim::KelvinVGe;
+using kelvin::sim::KelvinVGt;
+using kelvin::sim::KelvinVHadd;
+using kelvin::sim::KelvinVHsub;
+using kelvin::sim::KelvinVLd;
+using kelvin::sim::KelvinVLdRegWrite;
+using kelvin::sim::KelvinVLe;
+using kelvin::sim::KelvinVLt;
+using kelvin::sim::KelvinVMacc;
+using kelvin::sim::KelvinVMadd;
+using kelvin::sim::KelvinVMax;
+using kelvin::sim::KelvinVMin;
+using kelvin::sim::KelvinVMul;
+using kelvin::sim::KelvinVMulh;
+using kelvin::sim::KelvinVMuls;
+using kelvin::sim::KelvinVMulw;
+using kelvin::sim::KelvinVMv;
+using kelvin::sim::KelvinVMvp;
+using kelvin::sim::KelvinVNe;
+using kelvin::sim::KelvinVNot;
+using kelvin::sim::KelvinVOdd;
+using kelvin::sim::KelvinVOr;
+using kelvin::sim::KelvinVPadd;
+using kelvin::sim::KelvinVPsub;
+using kelvin::sim::KelvinVRev;
+using kelvin::sim::KelvinVRor;
+using kelvin::sim::KelvinVRSub;
+using kelvin::sim::KelvinVSel;
+using kelvin::sim::KelvinVShift;
+using kelvin::sim::KelvinVSlidehn;
+using kelvin::sim::KelvinVSlidehp;
+using kelvin::sim::KelvinVSlidevn;
+using kelvin::sim::KelvinVSlidevp;
+using kelvin::sim::KelvinVSll;
+using kelvin::sim::KelvinVSra;
+using kelvin::sim::KelvinVSrans;
+using kelvin::sim::KelvinVSrl;
+using kelvin::sim::KelvinVSt;
+using kelvin::sim::KelvinVStQ;
+using kelvin::sim::KelvinVSub;
+using kelvin::sim::KelvinVSubs;
+using kelvin::sim::KelvinVSubsu;
+using kelvin::sim::KelvinVSubw;
+using kelvin::sim::KelvinVXor;
+using kelvin::sim::KelvinVZip;
+
+constexpr bool kIsScalar = true;
+constexpr bool kNonScalar = false;
+constexpr bool kIsStripmine = true;
+constexpr bool kNonStripmine = false;
+constexpr bool kUnsigned = false;
+constexpr bool kHalftypeOp = true;
+constexpr bool kNonHalftypeOp = false;
+constexpr bool kVmvpOp = true;
+constexpr bool kNonVmvpOp = false;
+constexpr bool kIsRounding = true;
+constexpr bool kNonRounding = false;
+constexpr bool kHorizontal = true;
+constexpr bool kVertical = false;
+constexpr bool kNonWidenDst = false;
+constexpr bool kWidenDst = true;
+
+class KelvinVectorInstructionsTest
+    : public kelvin::sim::test::KelvinVectorInstructionsTestBase {
+ public:
+  template <typename T>
+  absl::string_view KelvinTestTypeSuffix() {
+    absl::string_view type_suffix = "Unknown";
+    switch (sizeof(T)) {
+      case 4:
+        type_suffix = "W";
+        break;
+      case 2:
+        type_suffix = "H";
+        break;
+      case 1:
+        type_suffix = "B";
+        break;
+    }
+    return type_suffix;
+  }
+
+  template <template <typename, typename, typename> class F, typename TD,
+            typename TS1, typename TS2>
+  void KelvinVectorBinaryOpHelper(absl::string_view name) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<TD>());
+
+    // Vector OP type vector-vector.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kNonScalar, kNonStripmine),
+        absl::StrCat(name_with_type, "VV"), kNonScalar, kNonStripmine,
+        F<TD, TS1, TS2>::Op);
+
+    // Vector OP type vector-vector stripmined.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kNonScalar, kIsStripmine),
+        absl::StrCat(name_with_type, "VVM"), kNonScalar, kIsStripmine,
+        F<TD, TS1, TS2>::Op);
+
+    // Vector OP type vector-scalar.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kIsScalar, kNonStripmine),
+        absl::StrCat(name_with_type, "VX"), kIsScalar, kNonStripmine,
+        F<TD, TS1, TS2>::Op);
+
+    // Vector OP type vector-scalar stripmined.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kIsScalar, kIsStripmine),
+        absl::StrCat(name_with_type, "VXM"), kIsScalar, kIsStripmine,
+        F<TD, TS1, TS2>::Op);
+  }
+
+  template <template <typename, typename, typename> class F, typename TD,
+            typename TS1, typename TS2, typename TNext1, typename... TNext>
+  void KelvinVectorBinaryOpHelper(absl::string_view name) {
+    KelvinVectorBinaryOpHelper<F, TD, TS1, TS2>(name);
+    KelvinVectorBinaryOpHelper<F, TNext1, TNext...>(name);
+  }
+
+  template <template <typename, typename, typename> class F,
+            bool is_signed = true>
+  void KelvinVectorBinaryOpHelper(absl::string_view name) {
+    if (is_signed) {
+      KelvinVectorBinaryOpHelper<F, int8_t, int8_t, int8_t, int16_t, int16_t,
+                                 int16_t, int32_t, int32_t, int32_t>(name);
+    } else {
+      KelvinVectorBinaryOpHelper<F, uint8_t, uint8_t, uint8_t, uint16_t,
+                                 uint16_t, uint16_t, uint32_t, uint32_t,
+                                 uint32_t>(name);
+    }
+  }
+
+  template <template <typename, typename, typename> class F, typename TD,
+            typename TS1, typename TS2>
+  void KelvinHalftypeVectorBinaryOpHelper(absl::string_view name) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<TD>());
+
+    // Vector OP single vector.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kNonStripmine),
+        absl::StrCat(name_with_type, "V"), kNonScalar, kNonStripmine,
+        F<TD, TS1, TS2>::Op, kHalftypeOp);
+
+    // Vector OP single vector stripmined.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kIsStripmine),
+        absl::StrCat(name_with_type, "VM"), kNonScalar, kIsStripmine,
+        F<TD, TS1, TS2>::Op, kHalftypeOp);
+  }
+
+  template <template <typename, typename, typename> class F, typename TD,
+            typename TS1, typename TS2, typename TNext1, typename... TNext>
+  void KelvinHalftypeVectorBinaryOpHelper(absl::string_view name) {
+    KelvinHalftypeVectorBinaryOpHelper<F, TD, TS1, TS2>(name);
+    KelvinHalftypeVectorBinaryOpHelper<F, TNext1, TNext...>(name);
+  }
+
+  template <template <typename, typename, typename> class F, typename TD,
+            typename TS1, typename TS2>
+  void KelvinVectorVXBinaryOpHelper(absl::string_view name) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<TD>());
+
+    // Vector OP vector-scalar.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kNonStripmine),
+        absl::StrCat(name_with_type, "VX"), kIsScalar, kNonStripmine,
+        F<TD, TS1, TS2>::Op);
+
+    // Vector OP vector-scalar stripmined.
+    BinaryOpTestHelper<TD, TS1, TS2>(
+        absl::bind_front(F<TD, TS1, TS2>::KelvinOp, kIsStripmine),
+        absl::StrCat(name_with_type, "VXM"), kIsScalar, kIsStripmine,
+        F<TD, TS1, TS2>::Op);
+  }
+
+  template <template <typename, typename, typename> class F, typename TD,
+            typename TS1, typename TS2, typename TNext1, typename... TNext>
+  void KelvinVectorVXBinaryOpHelper(absl::string_view name) {
+    KelvinVectorVXBinaryOpHelper<F, TD, TS1, TS2>(name);
+    KelvinVectorVXBinaryOpHelper<F, TNext1, TNext...>(name);
+  }
+
+  template <template <typename, typename, typename> class F, typename T>
+  void KelvinVectorShiftBinaryOpHelper(absl::string_view name) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<T>());
+
+    // Vector OP vector-vector.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T, T, T>::KelvinOp, kNonRounding, kNonStripmine),
+        absl::StrCat(name_with_type, "VV"), kNonScalar, kNonStripmine,
+        absl::bind_front(F<T, T, T>::Op, kNonRounding));
+
+    // Vector OP vector-vector stripmined.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T, T, T>::KelvinOp, kNonRounding, kIsStripmine),
+        absl::StrCat(name_with_type, "VVM"), kNonScalar, kIsStripmine,
+        absl::bind_front(F<T, T, T>::Op, kNonRounding));
+
+    // Vector OP vector-vector with rounding.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T, T, T>::KelvinOp, kIsRounding, kNonStripmine),
+        absl::StrCat(name_with_type, "RVV"), kNonScalar, kNonStripmine,
+        absl::bind_front(F<T, T, T>::Op, kIsRounding));
+
+    // Vector OP vector-vector stripmined with rounding.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T, T, T>::KelvinOp, kIsRounding, kIsStripmine),
+        absl::StrCat(name_with_type, "RVVM"), kNonScalar, kIsStripmine,
+        absl::bind_front(F<T, T, T>::Op, kIsRounding));
+  }
+
+  template <template <typename, typename, typename> class F, typename T,
+            typename TNext1, typename... TNext>
+  void KelvinVectorShiftBinaryOpHelper(absl::string_view name) {
+    KelvinVectorShiftBinaryOpHelper<F, T>(name);
+    KelvinVectorShiftBinaryOpHelper<F, TNext1, TNext...>(name);
+  }
+
+  template <template <typename, typename> class F, typename TD, typename TS>
+  void KelvinVectorUnaryOpHelper(absl::string_view name) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<TD>());
+
+    // Vector OP single vector.
+    UnaryOpTestHelper<TD, TS>(
+        absl::bind_front(F<TD, TS>::KelvinOp, kNonStripmine),
+        absl::StrCat(name_with_type, "V"), kNonStripmine, F<TD, TS>::Op);
+
+    // Vector OP single vector stripmined.
+    UnaryOpTestHelper<TD, TS>(
+        absl::bind_front(F<TD, TS>::KelvinOp, kIsStripmine),
+        absl::StrCat(name_with_type, "VM"), kIsStripmine, F<TD, TS>::Op);
+  }
+
+  template <template <typename, typename> class F, typename TD, typename TS,
+            typename TNext1, typename... TNext>
+  void KelvinVectorUnaryOpHelper(absl::string_view name) {
+    KelvinVectorUnaryOpHelper<F, TD, TS>(name);
+    KelvinVectorUnaryOpHelper<F, TNext1, TNext...>(name);
+  }
+
+  template <template <typename> class F, typename T>
+  void KelvinSlideOpHelper(absl::string_view name, bool horizontal) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<T>());
+
+    for (int i = 1; i < 5; ++i) {
+      BinaryOpTestHelper<T, T, T>(
+          absl::bind_front(F<T>::KelvinOp, i),
+          absl::StrCat(name_with_type, i, "VM"), kNonScalar, kIsStripmine,
+          F<T>::Op, absl::bind_front(F<T>::kArgsGetter, horizontal, i),
+          kNonHalftypeOp, kNonVmvpOp, kNonWidenDst);
+    }
+  }
+
+  template <template <typename> class F, typename T, typename TNext1,
+            typename... TNext>
+  void KelvinSlideOpHelper(absl::string_view name, bool horizontal) {
+    KelvinSlideOpHelper<F, T>(name, horizontal);
+    KelvinSlideOpHelper<F, TNext1, TNext...>(name, horizontal);
+  }
+
+  template <template <typename> class F, typename T>
+  void KelvinShuffleOpHelper(absl::string_view name, bool widen_dst) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<T>());
+
+    // Vector OP type vector-vector.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T>::KelvinOp, kNonScalar, kNonStripmine),
+        absl::StrCat(name_with_type, "VV"), kNonScalar, kNonStripmine, F<T>::Op,
+        F<T>::kArgsGetter, kNonHalftypeOp, kNonVmvpOp, widen_dst);
+
+    // Vector OP type vector-vector stripmined.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T>::KelvinOp, kNonScalar, kIsStripmine),
+        absl::StrCat(name_with_type, "VVM"), kNonScalar, kIsStripmine, F<T>::Op,
+        F<T>::kArgsGetter, kNonHalftypeOp, kNonVmvpOp, widen_dst);
+
+    // Vector OP type vector-scalar.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T>::KelvinOp, kIsScalar, kNonStripmine),
+        absl::StrCat(name_with_type, "VX"), kIsScalar, kNonStripmine, F<T>::Op,
+        F<T>::kArgsGetter, kNonHalftypeOp, kNonVmvpOp, widen_dst);
+
+    // Vector OP type vector-scalar stripmined.
+    BinaryOpTestHelper<T, T, T>(
+        absl::bind_front(F<T>::KelvinOp, kIsScalar, kIsStripmine),
+        absl::StrCat(name_with_type, "VXM"), kIsScalar, kIsStripmine, F<T>::Op,
+        F<T>::kArgsGetter, kNonHalftypeOp, kNonVmvpOp, widen_dst);
+  }
+
+  template <template <typename> class F, typename T, typename TNext1,
+            typename... TNext>
+  void KelvinShuffleOpHelper(absl::string_view name, bool widen_dst = false) {
+    KelvinShuffleOpHelper<F, T>(name, widen_dst);
+    KelvinShuffleOpHelper<F, TNext1, TNext...>(name, widen_dst);
+  }
+};
+
+// Vector add.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAddOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 + vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAdd<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VAdd) {
+  KelvinVectorBinaryOpHelper<VAddOp>("VAdd");
+}
+
+// Vector subtract.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSubOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 - vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSub<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VSub) {
+  KelvinVectorBinaryOpHelper<VSubOp>("VSub");
+}
+
+// Vector reverse subtract.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VRSubOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs2 - vs1; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVRSub<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VRsub) {
+  KelvinVectorBinaryOpHelper<VRSubOp>("VRsub");
+}
+
+// Vector equal.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VEqOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 == vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVEq<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VEq) {
+  KelvinVectorBinaryOpHelper<VEqOp>("VEq");
+}
+
+// Vector not equal.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VNeOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 != vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVNe<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VNe) {
+  KelvinVectorBinaryOpHelper<VNeOp>("VNe");
+}
+
+// Vector less than.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VLtOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 < vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVLt<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VLt) {
+  KelvinVectorBinaryOpHelper<VLtOp>("VLt");
+}
+
+// Vector less than unsigned.
+TEST_F(KelvinVectorInstructionsTest, VLtu) {
+  KelvinVectorBinaryOpHelper<VLtOp, kUnsigned>("VLtu");
+}
+
+// Vector less than or equal.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VLeOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 <= vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVLe<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VLe) {
+  KelvinVectorBinaryOpHelper<VLeOp>("VLe");
+}
+
+// Vector less than or equal unsigned.
+TEST_F(KelvinVectorInstructionsTest, VLeu) {
+  KelvinVectorBinaryOpHelper<VLeOp, kUnsigned>("VLeu");
+}
+
+// Vector greater than.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VGtOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 > vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVGt<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VGt) {
+  KelvinVectorBinaryOpHelper<VGtOp>("VGt");
+}
+
+// Vector greater than unsigned.
+TEST_F(KelvinVectorInstructionsTest, VGtu) {
+  KelvinVectorBinaryOpHelper<VGtOp, kUnsigned>("VGtu");
+}
+
+// Vector greater than or equal.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VGeOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 >= vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVGe<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VGe) {
+  KelvinVectorBinaryOpHelper<VGeOp>("VGe");
+}
+
+// Vector greater than or equal unsigned.
+TEST_F(KelvinVectorInstructionsTest, VGeu) {
+  KelvinVectorBinaryOpHelper<VGeOp, kUnsigned>("VGeu");
+}
+
+// Vector absolute difference.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAbsdOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    Vs1 result = vs1 > vs2 ? vs1 - vs2 : vs2 - vs1;
+    return static_cast<Vd>(result);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAbsd<Vs1>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VAbsd) {
+  KelvinVectorBinaryOpHelper<VAbsdOp, uint8_t, int8_t, int8_t, uint16_t,
+                             int16_t, int16_t, uint32_t, int32_t, int32_t>(
+      "VAbsd");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VAbsdu) {
+  KelvinVectorBinaryOpHelper<VAbsdOp, kUnsigned>("VAbsdu");
+}
+
+// Vector max.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMaxOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return std::max(vs1, vs2); }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMax<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VMax) {
+  KelvinVectorBinaryOpHelper<VMaxOp>("VMax");
+}
+
+// Vector max unsigned.
+TEST_F(KelvinVectorInstructionsTest, VMaxu) {
+  KelvinVectorBinaryOpHelper<VMaxOp, kUnsigned>("VMaxu");
+}
+
+// Vector min.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMinOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return std::min(vs1, vs2); }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMin<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VMin) {
+  KelvinVectorBinaryOpHelper<VMinOp>("VMin");
+}
+
+// Vector min unsigned.
+TEST_F(KelvinVectorInstructionsTest, VMinu) {
+  KelvinVectorBinaryOpHelper<VMinOp, kUnsigned>("VMinu");
+}
+
+// Vector add3.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAdd3Op {
+  static Vd Op(Vd vd, Vs1 vs1, Vs2 vs2) { return vd + vs1 + vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAdd3<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VAdd3) {
+  KelvinVectorBinaryOpHelper<VAdd3Op>("VAdd3");
+}
+
+// Vector saturated add.
+
+// Uses unsigned arithmetic for the addition to avoid signed overflow, which,
+// when compiled with --config=asan, will trigger an exception.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAddsOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    using UT = typename std::make_unsigned<Vd>::type;
+    UT uvs1 = static_cast<UT>(vs1);
+    UT uvs2 = static_cast<UT>(vs2);
+    UT usum = uvs1 + uvs2;
+    Vd sum = static_cast<Vd>(usum);
+    if (((vs1 ^ vs2) >= 0) && ((sum ^ vs1) < 0)) {
+      return vs1 > 0 ? std::numeric_limits<Vd>::max()
+                     : std::numeric_limits<Vd>::min();
+    }
+    return sum;
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAdds<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VAdds) {
+  KelvinVectorBinaryOpHelper<VAddsOp>("VAdds");
+}
+
+// Vector saturated unsigned add.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAddsuOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    Vd sum = vs1 + vs2;
+    if (sum < vs1) {
+      sum = std::numeric_limits<Vd>::max();
+    }
+    return sum;
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAddsu<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VAddsu) {
+  KelvinVectorBinaryOpHelper<VAddsuOp, kUnsigned>("VAddsu");
+}
+
+// Vector saturated sub.
+
+// Uses unsigned arithmetic for the addition to avoid signed overflow, which,
+// when compiled with --config=asan, will trigger an exception.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSubsOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    using UT = typename std::make_unsigned<Vd>::type;
+    UT uvs1 = static_cast<UT>(vs1);
+    UT uvs2 = static_cast<UT>(vs2);
+    UT usub = uvs1 - uvs2;
+    Vd sub = static_cast<Vd>(usub);
+    if (((vs1 ^ vs2) < 0) && ((sub ^ vs2) >= 0)) {
+      return vs2 < 0 ? std::numeric_limits<Vd>::max()
+                     : std::numeric_limits<Vd>::min();
+    }
+    return sub;
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSubs<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSubs) {
+  KelvinVectorBinaryOpHelper<VSubsOp>("VSubs");
+}
+
+// Vector saturated unsigned sub.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSubsuOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 < vs2 ? 0 : vs1 - vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSubsu<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSubsu) {
+  KelvinVectorBinaryOpHelper<VSubsuOp, kUnsigned>("VSubsu");
+}
+
+// Vector addition with widening.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAddwOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return static_cast<Vd>(vs1) + static_cast<Vd>(vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAddw<Vd, Vs1>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VAddw) {
+  KelvinVectorBinaryOpHelper<VAddwOp, int16_t, int8_t, int8_t, int32_t, int16_t,
+                             int16_t>("VAddwOp");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VAddwu) {
+  KelvinVectorBinaryOpHelper<VAddwOp, uint16_t, uint8_t, uint8_t, uint32_t,
+                             uint16_t, uint16_t>("VAddwuOp");
+}
+
+// Vector subtraction with widening.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSubwOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return static_cast<Vd>(vs1) - static_cast<Vd>(vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSubw<Vd, Vs1>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSubw) {
+  KelvinVectorBinaryOpHelper<VSubwOp, int16_t, int8_t, int8_t, int32_t, int16_t,
+                             int16_t>("VSubwOp");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VSubwu) {
+  KelvinVectorBinaryOpHelper<VSubwOp, uint16_t, uint8_t, uint8_t, uint32_t,
+                             uint16_t, uint16_t>("VSubwuOp");
+}
+
+// Vector accumulate with widening.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAccOp {
+  static Vd Op(Vd vs1, Vs2 vs2) { return vs1 + static_cast<Vd>(vs2); }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAcc<Vd, Vs2>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VAcc) {
+  KelvinVectorBinaryOpHelper<VAccOp, int16_t, int16_t, int8_t, int32_t, int32_t,
+                             int16_t>("VAccOp");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VAccu) {
+  KelvinVectorBinaryOpHelper<VAccOp, uint16_t, uint16_t, uint8_t, uint32_t,
+                             uint32_t, uint16_t>("VAccuOp");
+}
+
+// Vector packed add
+template <typename Vd, typename Vs1, typename Vs2>
+struct VPaddOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return static_cast<Vd>(vs1) + static_cast<Vd>(vs2);
+  }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVPadd<Vd, Vs2>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VPadd) {
+  KelvinHalftypeVectorBinaryOpHelper<VPaddOp, int16_t, int8_t, int8_t, int32_t,
+                                     int16_t, int16_t>("VPaddOp");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VPaddu) {
+  KelvinHalftypeVectorBinaryOpHelper<VPaddOp, uint16_t, uint8_t, uint8_t,
+                                     uint32_t, uint16_t, uint16_t>("VPaddOp");
+}
+
+// Vector packed sub
+template <typename Vd, typename Vs1, typename Vs2>
+struct VPsubOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return static_cast<Vd>(vs1) - static_cast<Vd>(vs2);
+  }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVPsub<Vd, Vs2>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VPsub) {
+  KelvinHalftypeVectorBinaryOpHelper<VPsubOp, int16_t, int8_t, int8_t, int32_t,
+                                     int16_t, int16_t>("VPsubOp");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VPsubu) {
+  KelvinHalftypeVectorBinaryOpHelper<VPsubOp, uint16_t, uint8_t, uint8_t,
+                                     uint32_t, uint16_t, uint16_t>("VPsubOp");
+}
+
+// Vector halving addition.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VHaddOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    if (std::is_signed<Vd>::value) {
+      return static_cast<Vd>(
+          (static_cast<int64_t>(vs1) + static_cast<int64_t>(vs2)) >> 1);
+    } else {
+      return static_cast<Vd>(
+          (static_cast<uint64_t>(vs1) + static_cast<uint64_t>(vs2)) >> 1);
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVHadd<Vd>(scalar, strip_mine, false /* round */, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VHadd) {
+  KelvinVectorBinaryOpHelper<VHaddOp>("VHadd");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VHaddu) {
+  KelvinVectorBinaryOpHelper<VHaddOp, kUnsigned>("VHaddu");
+}
+
+// Vector halving addition with rounding.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VHaddrOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    if (std::is_signed<Vd>::value) {
+      return static_cast<Vd>(
+          (static_cast<int64_t>(vs1) + static_cast<int64_t>(vs2) + 1) >> 1);
+    } else {
+      return static_cast<Vd>(
+          (static_cast<uint64_t>(vs1) + static_cast<uint64_t>(vs2) + 1) >> 1);
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVHadd<Vd>(scalar, strip_mine, true /* round */, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VHaddr) {
+  KelvinVectorBinaryOpHelper<VHaddrOp>("VHaddr");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VHaddur) {
+  KelvinVectorBinaryOpHelper<VHaddrOp, kUnsigned>("VHaddur");
+}
+
+// Vector halving subtraction.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VHsubOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    if (std::is_signed<Vd>::value) {
+      return static_cast<Vd>(
+          (static_cast<int64_t>(vs1) - static_cast<int64_t>(vs2)) >> 1);
+    } else {
+      return static_cast<Vd>(
+          (static_cast<uint64_t>(vs1) - static_cast<uint64_t>(vs2)) >> 1);
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVHsub<Vd>(scalar, strip_mine, false /* round */, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VHsub) {
+  KelvinVectorBinaryOpHelper<VHsubOp>("VHsub");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VHsubu) {
+  KelvinVectorBinaryOpHelper<VHsubOp, kUnsigned>("VHsubu");
+}
+
+// Vector halving subtraction with rounding.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VHsubrOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    if (std::is_signed<Vd>::value) {
+      return static_cast<Vd>(
+          (static_cast<int64_t>(vs1) - static_cast<int64_t>(vs2) + 1) >> 1);
+    } else {
+      return static_cast<Vd>(
+          (static_cast<uint64_t>(vs1) - static_cast<uint64_t>(vs2) + 1) >> 1);
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVHsub<Vd>(scalar, strip_mine, true /* round */, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VHsubr) {
+  KelvinVectorBinaryOpHelper<VHsubrOp>("VHsubr");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VHsubur) {
+  KelvinVectorBinaryOpHelper<VHsubrOp, kUnsigned>("VHsubur");
+}
+
+// Vector bitwise and.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VAndOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 & vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVAnd<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VAnd) {
+  KelvinVectorBinaryOpHelper<VAndOp, kUnsigned>("VAnd");
+}
+
+// Vector bitwise or.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VOrOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 | vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVOr<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VOr) {
+  KelvinVectorBinaryOpHelper<VOrOp, kUnsigned>("VOr");
+}
+
+// Vector bitwise xor.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VXorOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 ^ vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVXor<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VXor) {
+  KelvinVectorBinaryOpHelper<VXorOp, kUnsigned>("VXor");
+}
+
+// Vector logical shift left.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSllOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 << (vs2 & (sizeof(Vd) * 8 - 1)); }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSll<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSll) {
+  KelvinVectorBinaryOpHelper<VSllOp, kUnsigned>("VSll");
+}
+
+// Vector logical shift right.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSrlOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 >> (vs2 & (sizeof(Vd) * 8 - 1)); }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSrl<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSrl) {
+  KelvinVectorBinaryOpHelper<VSrlOp, kUnsigned>("VSrl");
+}
+
+// Vector arithmetic shift right.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSraOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 >> (vs2 & (sizeof(Vd) * 8 - 1)); }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSra<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSra) {
+  KelvinVectorBinaryOpHelper<VSraOp>("VSra");
+}
+
+// Vector reverse using bit ladder.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VRevOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    Vs1 r = vs1;
+    Vs2 count = vs2 & 0b11111;
+    if (count & 1) r = ((r & 0x55555555) << 1) | ((r & 0xAAAAAAAA) >> 1);
+    if (count & 2) r = ((r & 0x33333333) << 2) | ((r & 0xCCCCCCCC) >> 2);
+    if (count & 4) r = ((r & 0x0F0F0F0F) << 4) | ((r & 0xF0F0F0F0) >> 4);
+    if (count & 8) r = ((r & 0x00FF00FF) << 8) | ((r & 0xFF00FF00) >> 8);
+    if (count & 16) r = ((r & 0x0000FFFF) << 16) | ((r & 0xFFFF0000) >> 16);
+    return r;
+  }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVRev<Vd>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VRev) {
+  KelvinVectorVXBinaryOpHelper<VRevOp, uint8_t, uint8_t, uint8_t, uint16_t,
+                               uint16_t, uint16_t, uint32_t, uint32_t,
+                               uint32_t>("VRevOp");
+}
+
+// Cyclic rotation right using a bit ladder.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VRorOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    Vs1 r = vs1;
+    Vd count = vs2 & static_cast<Vd>(sizeof(Vd) * 8 - 1);
+    for (auto shift : {1, 2, 4, 8, 16}) {
+      if (count & shift) r = (r >> shift) | (r << (sizeof(Vd) * 8 - shift));
+    }
+    return r;
+  }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVRor<Vd>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VRor) {
+  KelvinVectorVXBinaryOpHelper<VRorOp, uint8_t, uint8_t, uint8_t, uint16_t,
+                               uint16_t, uint16_t, uint32_t, uint32_t,
+                               uint32_t>("VRorOp");
+}
+
+// Vector move pair.
+template <typename T>
+struct VMvpOp {
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMvp<T>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VMvp) {
+  BinaryOpTestHelper<uint32_t, uint32_t, uint32_t>(
+      absl::bind_front(VMvpOp<uint32_t>::KelvinOp, kNonScalar, kNonStripmine),
+      "VMvpVV", kNonScalar, kNonStripmine, VMvpOp<uint32_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint32_t, uint32_t, uint32_t>(
+      absl::bind_front(VMvpOp<uint32_t>::KelvinOp, kNonScalar, kIsStripmine),
+      "VMvpVVM", kNonScalar, kIsStripmine, VMvpOp<uint32_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint32_t, uint32_t, uint32_t>(
+      absl::bind_front(VMvpOp<uint32_t>::KelvinOp, kIsScalar, kNonStripmine),
+      "VMvpWVX", kIsScalar, kNonStripmine, VMvpOp<uint32_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint32_t, uint32_t, uint32_t>(
+      absl::bind_front(VMvpOp<uint32_t>::KelvinOp, kIsScalar, kIsStripmine),
+      "VMvpWVXM", kIsScalar, kIsStripmine, VMvpOp<uint32_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint16_t, uint16_t, uint16_t>(
+      absl::bind_front(VMvpOp<uint16_t>::KelvinOp, kIsScalar, kNonStripmine),
+      "VMvpHVX", kIsScalar, kNonStripmine, VMvpOp<uint16_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint16_t, uint16_t, uint16_t>(
+      absl::bind_front(VMvpOp<uint16_t>::KelvinOp, kIsScalar, kIsStripmine),
+      "VMvpHVXM", kIsScalar, kIsStripmine, VMvpOp<uint16_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint8_t, uint8_t, uint8_t>(
+      absl::bind_front(VMvpOp<uint8_t>::KelvinOp, kIsScalar, kNonStripmine),
+      "VMvpBVX", kIsScalar, kNonStripmine, VMvpOp<uint8_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+
+  BinaryOpTestHelper<uint8_t, uint8_t, uint8_t>(
+      absl::bind_front(VMvpOp<uint8_t>::KelvinOp, kIsScalar, kIsStripmine),
+      "VMvpBVXM", kIsScalar, kIsStripmine, VMvpOp<uint8_t>::Op, kNonHalftypeOp,
+      kVmvpOp);
+}
+
+// Left/right shift with saturating shift amount and result.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VShiftOp {
+  static Vd Op(bool round, Vs1 vs1, Vs2 vs2) {
+    if (std::is_signed<Vd>::value == true) {
+      constexpr int n = sizeof(Vd) * 8;
+      int shamt = 0;
+      if (sizeof(Vd) == 1) shamt = static_cast<int8_t>(vs2);
+      if (sizeof(Vd) == 2) shamt = static_cast<int16_t>(vs2);
+      if (sizeof(Vd) == 4) shamt = static_cast<int32_t>(vs2);
+      int64_t s = vs1;
+      if (!vs1) {
+        return 0;
+      } else if (vs1 < 0 && shamt >= n) {
+        s = -1 + round;
+      } else if (vs1 > 0 && shamt >= n) {
+        s = 0;
+      } else if (shamt > 0) {
+        s = (static_cast<int64_t>(vs1) + (round ? (1ll << (shamt - 1)) : 0)) >>
+            shamt;
+      } else {
+        s = static_cast<int64_t>(vs1) << (-shamt);
+      }
+      int64_t neg_max = (-1ull) << (n - 1);
+      int64_t pos_max = (1ll << (n - 1)) - 1;
+      bool neg_sat = vs1 < 0 && (shamt <= -n || s < neg_max);
+      bool pos_sat = vs1 > 0 && (shamt <= -n || s > pos_max);
+      if (neg_sat) return neg_max;
+      if (pos_sat) return pos_max;
+      return s;
+    } else {
+      constexpr int n = sizeof(Vd) * 8;
+      int shamt = 0;
+      if (sizeof(Vd) == 1) shamt = static_cast<int8_t>(vs2);
+      if (sizeof(Vd) == 2) shamt = static_cast<int16_t>(vs2);
+      if (sizeof(Vd) == 4) shamt = static_cast<int32_t>(vs2);
+      uint64_t s = vs1;
+      if (!vs1) {
+        return 0;
+      } else if (shamt > n) {
+        s = 0;
+      } else if (shamt > 0) {
+        s = (static_cast<uint64_t>(vs1) +
+             (round ? (1ull << (shamt - 1)) : 0)) >>
+            shamt;
+      } else {
+        s = static_cast<uint64_t>(vs1) << (-shamt);
+      }
+      uint64_t pos_max = (1ull << n) - 1;
+      bool pos_sat = vs1 && (shamt < -n || s >= (1ull << n));
+      if (pos_sat) return pos_max;
+      return s;
+    }
+  }
+
+  static void KelvinOp(bool round, bool strip_mine, Instruction *inst) {
+    KelvinVShift<Vd>(round, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VShift) {
+  KelvinVectorShiftBinaryOpHelper<VShiftOp, int8_t, int16_t, int32_t, uint8_t,
+                                  uint16_t, uint32_t>("VShift");
+}
+
+// Vector bitwise not.
+template <typename Vd, typename Vs>
+struct VNotOp {
+  static Vd Op(Vs vs) { return ~vs; }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVNot<Vs>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VNot) {
+  KelvinVectorUnaryOpHelper<VNotOp, int32_t, int32_t>("VNot");
+}
+
+// Count the leading bits.
+template <typename Vd, typename Vs>
+struct VClbOp {
+  static Vd Op(Vs vs) {
+    constexpr int n = sizeof(Vs) * 8;
+    if (vs & (1u << (n - 1))) {
+      vs = ~vs;
+    }
+    for (int count = 0; count < n; count++) {
+      if ((vs << count) >> (n - 1)) {
+        return count;
+      }
+    }
+    return n;
+  }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVClb<Vs>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VClb) {
+  KelvinVectorUnaryOpHelper<VClbOp, uint8_t, uint8_t, uint16_t, uint16_t,
+                            uint32_t, uint32_t>("VClb");
+}
+
+// Count the leading zeros.
+template <typename Vd, typename Vs>
+struct VClzOp {
+  static Vd Op(Vs vs) {
+    constexpr int n = sizeof(Vs) * 8;
+    for (int count = 0; count < n; count++) {
+      if ((vs << count) >> (n - 1)) {
+        return count;
+      }
+    }
+    return n;
+  }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVClz<Vs>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VClz) {
+  KelvinVectorUnaryOpHelper<VClzOp, uint8_t, uint8_t, uint16_t, uint16_t,
+                            uint32_t, uint32_t>("VClz");
+}
+
+// Count the set bits.
+template <typename Vd, typename Vs>
+struct VCpopOp {
+  static Vd Op(Vs vs) { return absl::popcount(vs); }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVCpop<Vs>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VCpop) {
+  KelvinVectorUnaryOpHelper<VCpopOp, uint8_t, uint8_t, uint16_t, uint16_t,
+                            uint32_t, uint32_t>("VCpop");
+}
+
+// Count the set bits.
+template <typename Vd, typename Vs>
+struct VMvOp {
+  static Vd Op(Vs vs) { return vs; }
+  static void KelvinOp(bool strip_mine, Instruction *inst) {
+    KelvinVMv<Vs>(strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMv) {
+  KelvinVectorUnaryOpHelper<VMvOp, int32_t, int32_t>("VMv");
+}
+
+// Arithmetic right shift without rounding and signed/unsigned saturation.
+// Narrowing x2 or x4.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSransOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    static_assert(2 * sizeof(Vd) == sizeof(Vs1) ||
+                  4 * sizeof(Vd) == sizeof(Vs1));
+    constexpr int src_bits = sizeof(Vs1) * 8;
+    vs2 &= (src_bits - 1);
+
+    int64_t res = (static_cast<int64_t>(vs1)) >> vs2;
+
+    bool neg_sat = res < std::numeric_limits<Vd>::min();
+    bool pos_sat = res > std::numeric_limits<Vd>::max();
+    bool zero = !vs1;
+    if (neg_sat) return std::numeric_limits<Vd>::min();
+    if (pos_sat) return std::numeric_limits<Vd>::max();
+    if (zero) return 0;
+    return res;
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSrans<Vd, Vs1>(kNonRounding, scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSrans) {
+  KelvinVectorBinaryOpHelper<VSransOp, int8_t, int16_t, int8_t, int16_t,
+                             int32_t, int16_t, uint8_t, uint16_t, uint8_t,
+                             uint16_t, uint32_t, uint16_t>("VSrans");
+}
+
+// Arithmetic right shift with rounding and signed/unsigned saturation.
+// Narrowing x2 or x4.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSransrOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    static_assert(2 * sizeof(Vd) == sizeof(Vs1) ||
+                  4 * sizeof(Vd) == sizeof(Vs1));
+    constexpr int src_bits = sizeof(Vs1) * 8;
+    vs2 &= (src_bits - 1);
+
+    int64_t res =
+        (static_cast<int64_t>(vs1) + (vs2 ? (1ll << (vs2 - 1)) : 0)) >> vs2;
+
+    bool neg_sat = res < std::numeric_limits<Vd>::min();
+    bool pos_sat = res > std::numeric_limits<Vd>::max();
+    bool zero = !vs1;
+    if (neg_sat) return std::numeric_limits<Vd>::min();
+    if (pos_sat) return std::numeric_limits<Vd>::max();
+    if (zero) return 0;
+    return res;
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSrans<Vd, Vs1>(kIsRounding, scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSransr) {
+  KelvinVectorBinaryOpHelper<VSransrOp, int8_t, int16_t, int8_t, int16_t,
+                             int32_t, int16_t, uint8_t, uint16_t, uint8_t,
+                             uint16_t, uint32_t, uint16_t>("VSransr");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VSraqs) {
+  KelvinVectorBinaryOpHelper<VSransOp, int8_t, int32_t, int8_t, uint8_t,
+                             uint32_t, uint8_t>("VSraqs");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VSraqsr) {
+  KelvinVectorBinaryOpHelper<VSransrOp, int8_t, int32_t, int8_t, uint8_t,
+                             uint32_t, uint8_t>("VSraqsr");
+}
+
+// Vector elements multiplication.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMulOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) { return vs1 * vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMul<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VMul) {
+  KelvinVectorBinaryOpHelper<VMulOp>("VMul");
+}
+
+// Vector elements multiplication with saturation.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMulsOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    if (std::is_signed<Vd>::value) {
+      int64_t m = static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+      m = std::max(
+          static_cast<int64_t>(std::numeric_limits<Vd>::min()),
+          std::min(static_cast<int64_t>(std::numeric_limits<Vd>::max()), m));
+      return m;
+    } else {
+      uint64_t m = static_cast<uint64_t>(vs1) * static_cast<uint64_t>(vs2);
+      m = std::min(static_cast<uint64_t>(std::numeric_limits<Vd>::max()), m);
+      return m;
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMuls<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMuls) {
+  KelvinVectorBinaryOpHelper<VMulsOp>("VMuls");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VMulsu) {
+  KelvinVectorBinaryOpHelper<VMulsOp, kUnsigned>("VMulsu");
+}
+
+// Vector elements multiplication with widening.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMulwOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return static_cast<Vd>(vs1) * static_cast<Vd>(vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMulw<Vd, Vs1>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMulw) {
+  KelvinVectorBinaryOpHelper<VMulwOp, int16_t, int8_t, int8_t, int32_t, int16_t,
+                             int16_t>("VMulwOp");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VMulwu) {
+  KelvinVectorBinaryOpHelper<VMulwOp, uint16_t, uint8_t, uint8_t, uint32_t,
+                             uint16_t, uint16_t>("VMulwuOp");
+}
+
+// Vector elements multiplication with widening. Returns high half.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMulhOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    constexpr int n = sizeof(Vd) * 8;
+    if (std::is_signed<Vs1>::value) {
+      int64_t result = static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+      return static_cast<uint64_t>(result) >> n;
+    } else {
+      uint64_t result = static_cast<uint64_t>(vs1) * static_cast<uint64_t>(vs2);
+      return result >> n;
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMulh<Vd>(scalar, strip_mine, false /* round */, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMulh) {
+  KelvinVectorBinaryOpHelper<VMulhOp>("VMulh");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VMulhu) {
+  KelvinVectorBinaryOpHelper<VMulhOp, kUnsigned>("VMulhu");
+}
+
+// Vector elements multiplication with rounding and widening. Returns high
+// half.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMulhrOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    constexpr int n = sizeof(Vd) * 8;
+    if (std::is_signed<Vs1>::value) {
+      int64_t result = static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+      result += 1ll << (n - 1);
+      return static_cast<uint64_t>(result) >> n;
+    } else {
+      uint64_t result = static_cast<uint64_t>(vs1) * static_cast<uint64_t>(vs2);
+      result += 1ull << (n - 1);
+      return result >> n;
+    }
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMulh<Vd>(scalar, strip_mine, true /* round */, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMulhr) {
+  KelvinVectorBinaryOpHelper<VMulhrOp>("VMulhr");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VMulhur) {
+  KelvinVectorBinaryOpHelper<VMulhrOp, kUnsigned>("VMulhur");
+}
+
+// Saturating signed doubling multiply returning high half with optional
+// rounding.
+template <typename T>
+T KelvinVDmulhHelper(bool round, bool round_neg, T vs1, T vs2) {
+  constexpr int n = sizeof(T) * 8;
+  int64_t result = static_cast<int64_t>(vs1) * static_cast<int64_t>(vs1);
+  if (round) {
+    int64_t rnd = 0x40000000ll >> (32 - n);
+    if (result < 0 && round_neg) {
+      rnd = (-0x40000000ll) >> (32 - n);
+    }
+    result += rnd;
+  }
+  result >>= (n - 1);
+  if (vs1 == std::numeric_limits<T>::min() &&
+      vs2 == std::numeric_limits<T>::min()) {
+    result = std::numeric_limits<T>::max();
+  }
+  return result;
+}
+
+template <typename Vd, typename Vs1, typename Vs2>
+struct VDmulhOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return KelvinVDmulhHelper<Vd>(kNonRounding, false /* round_neg*/, vs1, vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVDmulh<Vd>(scalar, strip_mine, kNonRounding, false /* round_neg*/,
+                     inst);
+  }
+};
+
+template <typename Vd, typename Vs1, typename Vs2>
+struct VDmulhrOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return KelvinVDmulhHelper<Vd>(kIsRounding, false /* round_neg*/, vs1, vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVDmulh<Vd>(scalar, strip_mine, kIsRounding, false /* round_neg*/,
+                     inst);
+  }
+};
+
+template <typename Vd, typename Vs1, typename Vs2>
+struct VDmulhrnOp {
+  static Vd Op(Vs1 vs1, Vs2 vs2) {
+    return KelvinVDmulhHelper<Vd>(kIsRounding, true /* round_neg*/, vs1, vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVDmulh<Vd>(scalar, strip_mine, kIsRounding, true /* round_neg*/,
+                     inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VDmulh) {
+  KelvinVectorBinaryOpHelper<VDmulhOp>("VDmulh");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VDmulhr) {
+  KelvinVectorBinaryOpHelper<VDmulhrOp>("VDmulhr");
+}
+
+TEST_F(KelvinVectorInstructionsTest, VDmulhrn) {
+  KelvinVectorBinaryOpHelper<VDmulhrnOp>("VDmulhrn");
+}
+
+// Multiply accumulate.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMaccOp {
+  static Vd Op(Vd vd, Vs1 vs1, Vs2 vs2) {
+    return static_cast<int64_t>(vd) +
+           static_cast<int64_t>(vs1) * static_cast<int64_t>(vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMacc<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMacc) {
+  KelvinVectorBinaryOpHelper<VMaccOp>("VMacc");
+}
+
+// Multiply add.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VMaddOp {
+  static Vd Op(Vd vd, Vs1 vs1, Vs2 vs2) {
+    return static_cast<int64_t>(vs1) +
+           static_cast<int64_t>(vd) * static_cast<int64_t>(vs2);
+  }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVMadd<Vd>(scalar, strip_mine, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VMadd) {
+  KelvinVectorBinaryOpHelper<VMaddOp>("VMadd");
+}
+
+// Slide next register by index.
+template <typename T>
+static std::pair<T, T> SlidenArgsGetter(
+    bool horizontal, int index, int num_ops, int op_num, int dest_reg_sub_index,
+    int element_index, int vd_size, bool widen_dst, int src1_widen_factor,
+    int vs1_size, const std::vector<T> &vs1_value, int vs2_size, bool s2_scalar,
+    const std::vector<T> &vs2_value, T rs2_value, bool halftype_op,
+    bool vmvp_op) {
+  assert(!s2_scalar && !halftype_op && !vmvp_op && dest_reg_sub_index == 0);
+
+  using Interleave = struct {
+    int register_num;
+    int source_arg;
+  };
+  const Interleave interleave_start[2][4] = {{{3, 0}, {2, 0}, {1, 0}, {0, 0}},
+                                             {{3, 0}, {2, 0}, {1, 0}, {0, 0}}};
+  const Interleave interleave_end[2][4] = {{{3, 1}, {2, 1}, {1, 1}, {0, 1}},
+                                           {{0, 1}, {3, 0}, {2, 0}, {1, 0}}};
+
+  T arg1;
+  if (element_index + index < vd_size) {
+    auto src_element_index =
+        interleave_start[horizontal][op_num].register_num * vd_size +
+        element_index + index;
+    arg1 = interleave_start[horizontal][op_num].source_arg
+               ? vs2_value[src_element_index]
+               : vs1_value[src_element_index];
+  } else {
+    auto src_element_index =
+        interleave_end[horizontal][op_num].register_num * vd_size +
+        element_index + index - vd_size;
+
+    arg1 = interleave_end[horizontal][op_num].source_arg
+               ? vs2_value[src_element_index]
+               : vs1_value[src_element_index];
+  }
+
+  return {arg1, 0};
+}
+
+// Slide next register horizontally by index.
+template <typename T>
+struct VSlidehnOp {
+  static constexpr auto kArgsGetter = SlidenArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(int index, Instruction *inst) {
+    KelvinVSlidehn<T>(index, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSlidehnOp) {
+  KelvinSlideOpHelper<VSlidehnOp, int8_t, int16_t, int32_t>("VSlidehnOp",
+                                                            kHorizontal);
+}
+
+// Slide next register vertically by index.
+template <typename T>
+struct VSlidevnOp {
+  static constexpr auto kArgsGetter = SlidenArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(int index, Instruction *inst) {
+    KelvinVSlidevn<T>(index, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSlidevnOp) {
+  KelvinSlideOpHelper<VSlidevnOp, int8_t, int16_t, int32_t>("VSlidevnOp",
+                                                            kVertical);
+}
+
+// Slide previous register by index.
+template <typename T>
+static std::pair<T, T> SlidepArgsGetter(
+    bool horizontal, int index, int num_ops, int op_num, int dest_reg_sub_index,
+    int element_index, int vd_size, bool widen_dst, int src1_widen_factor,
+    int vs1_size, const std::vector<T> &vs1_value, int vs2_size, bool s2_scalar,
+    const std::vector<T> &vs2_value, T rs2_value, bool halftype_op,
+    bool vmvp_op) {
+  assert(!s2_scalar && !halftype_op && !vmvp_op && dest_reg_sub_index == 0);
+
+  using Interleave = struct {
+    int register_num;
+    int source_arg;
+  };
+  const Interleave interleave_start[2][4] = {{{3, 0}, {2, 0}, {1, 0}, {0, 0}},
+                                             {{3, 0}, {2, 0}, {1, 0}, {0, 0}}};
+  const Interleave interleave_end[2][4] = {{{2, 0}, {1, 0}, {0, 0}, {3, 1}},
+                                           {{0, 1}, {3, 0}, {2, 0}, {1, 0}}};
+
+  T arg1;
+  if (element_index >= index) {
+    auto src_element_index =
+        interleave_start[horizontal][op_num].register_num * vd_size +
+        element_index - index;
+    arg1 = interleave_start[horizontal][op_num].source_arg
+               ? vs2_value[src_element_index]
+               : vs1_value[src_element_index];
+  } else {
+    auto src_element_index =
+        interleave_end[horizontal][op_num].register_num * vd_size +
+        element_index - index + vd_size;
+
+    arg1 = interleave_end[horizontal][op_num].source_arg
+               ? vs2_value[src_element_index]
+               : vs1_value[src_element_index];
+  }
+
+  return {arg1, 0};
+}
+
+// Slide previous register horizontally by index.
+template <typename T>
+struct VSlidehpOp {
+  static constexpr auto kArgsGetter = SlidepArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(int index, Instruction *inst) {
+    KelvinVSlidehp<T>(index, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSlidehpOp) {
+  KelvinSlideOpHelper<VSlidehpOp, int8_t, int16_t, int32_t>("VSlidehpOp",
+                                                            kHorizontal);
+}
+
+// Slide previous register vertically by index.
+template <typename T>
+struct VSlidevpOp {
+  static constexpr auto kArgsGetter = SlidepArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(int index, Instruction *inst) {
+    KelvinVSlidevp<T>(index, inst);
+  }
+};
+
+TEST_F(KelvinVectorInstructionsTest, VSlidevpOp) {
+  KelvinSlideOpHelper<VSlidevpOp, int8_t, int16_t, int32_t>("VSlidevpOp",
+                                                            kVertical);
+}
+
+// Select lanes from two operands with vector selection boolean.
+template <typename Vd, typename Vs1, typename Vs2>
+struct VSelOp {
+  static Vd Op(Vd vd, Vs1 vs1, Vs2 vs2) { return vs1 & 1 ? vd : vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVSel<Vd>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VSel) {
+  KelvinVectorBinaryOpHelper<VSelOp>("VSel");
+}
+
+// Select even/odd elements of concatenated registers.
+template <typename T>
+static std::pair<T, T> EvnOddOpArgsGetter(
+    int num_ops, int op_num, int dest_reg_sub_index, int element_index,
+    int vd_size, bool widen_dst, int src1_widen_factor, int vs1_size,
+    const std::vector<T> &vs1_value, int vs2_size, bool s2_scalar,
+    const std::vector<T> &vs2_value, T rs2_value, bool halftype_op,
+    bool vmvp_op) {
+  const int combined_element_index = (op_num * vs1_size + element_index) * 2;
+  const int elts_per_src = num_ops * vs1_size;
+  T even, odd;
+
+  if (combined_element_index < elts_per_src) {
+    even = vs1_value[combined_element_index];
+    odd = vs1_value[combined_element_index + 1];
+  } else {
+    even = s2_scalar ? rs2_value
+                     : vs2_value[combined_element_index - elts_per_src];
+    odd = s2_scalar ? rs2_value
+                    : vs2_value[combined_element_index - elts_per_src + 1];
+  }
+
+  return {dest_reg_sub_index == 0 ? even : odd, odd};
+}
+
+template <typename T>
+struct VEvnOp {
+  static constexpr auto kArgsGetter = EvnOddOpArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVEvn<T>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VEvn) {
+  KelvinShuffleOpHelper<VEvnOp, int8_t, int16_t, int32_t>("VEvn");
+}
+
+template <typename T>
+struct VOddOp {
+  static constexpr auto kArgsGetter = EvnOddOpArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs2; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVOdd<T>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VOdd) {
+  KelvinShuffleOpHelper<VOddOp, int8_t, int16_t, int32_t>("VOdd");
+}
+
+template <typename T>
+struct VEvnoddOp {
+  static constexpr auto kArgsGetter = EvnOddOpArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVEvnodd<T>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VEvnodd) {
+  KelvinShuffleOpHelper<VEvnoddOp, int8_t, int16_t, int32_t>("VEvnodd",
+                                                             kWidenDst);
+}
+
+// Select even/odd elements of concatenated registers.
+template <typename T>
+static std::pair<T, T> ZipOpArgsGetter(
+    int num_ops, int op_num, int dest_reg_sub_index, int element_index,
+    int vd_size, bool widen_dst, int src1_widen_factor, int vs1_size,
+    const std::vector<T> &vs1_value, int vs2_size, bool s2_scalar,
+    const std::vector<T> &vs2_value, T rs2_value, bool halftype_op,
+    bool vmvp_op) {
+  auto src_index =
+      op_num * vs1_size + element_index / 2 + dest_reg_sub_index * vs1_size / 2;
+
+  T arg1;
+  if (element_index & 1) {
+    arg1 = s2_scalar ? rs2_value : vs2_value[src_index];
+  } else {
+    arg1 = vs1_value[src_index];
+  }
+  return {arg1, 0};
+}
+
+template <typename T>
+struct VZipOp {
+  static constexpr auto kArgsGetter = ZipOpArgsGetter<T>;
+  static T Op(T vs1, T vs2) { return vs1; }
+  static void KelvinOp(bool scalar, bool strip_mine, Instruction *inst) {
+    KelvinVZip<T>(scalar, strip_mine, inst);
+  }
+};
+TEST_F(KelvinVectorInstructionsTest, VZip) {
+  KelvinShuffleOpHelper<VZipOp, int8_t, int16_t, int32_t>("VZip", kWidenDst);
+}
+
+class KelvinVectorInstructionsMemoryTest : public KelvinVectorInstructionsTest {
+ public:
+  template <typename T>
+  void MemoryLoadStoreOpTestHelper(absl::string_view name, bool has_length,
+                                   bool has_stride, bool strip_mine,
+                                   bool post_increment, bool x_variant,
+                                   bool is_load, bool is_quad) {
+    InstructionPtr child_instruction(
+        new Instruction(next_instruction_address_, state_),
+        [](Instruction *inst) { inst->DecRef(); });
+    child_instruction->set_size(4);
+    auto instruction = CreateInstruction();
+
+    if (is_load) {
+      child_instruction->set_semantic_function(
+          absl::bind_front(&KelvinVLdRegWrite<T>, strip_mine));
+      instruction->set_semantic_function(
+          absl::bind_front(&KelvinVLd<T>, has_length, has_stride, strip_mine));
+      instruction->AppendChild(child_instruction.get());
+    } else {
+      if (is_quad) {
+        instruction->set_semantic_function(
+            absl::bind_front(&KelvinVStQ<T>, strip_mine));
+      } else {
+        instruction->set_semantic_function(absl::bind_front(
+            &KelvinVSt<T>, has_length, has_stride, strip_mine));
+      }
+    }
+
+    // Setup source and child instruction operands.
+    const uint32_t num_ops = strip_mine ? 4 : 1;
+    if (is_load) {
+      AppendVectorRegisterOperands(
+          child_instruction.get(), num_ops, 1 /* src1_widen_factor */, {}, {},
+          false /* widen_dst */, {kelvin::sim::test::kVd});
+    } else {  // Store
+      AppendVectorRegisterOperands(
+          instruction.get(), num_ops, 1 /* src1_widen_factor */,
+          kelvin::sim::test::kVd, {}, false /* widen_dst */, {});
+    }
+    AppendRegisterOperands(instruction.get(), {kelvin::sim::test::kRs1Name},
+                           {});
+    if (!x_variant) {
+      AppendRegisterOperands(instruction.get(), {kelvin::sim::test::kRs2Name},
+                             {});
+    }
+
+    if (post_increment) {
+      AppendRegisterOperands(instruction.get(), {},
+                             {kelvin::sim::test::kRs1Name});
+    }
+
+    // x variant can't have length or stride fields.
+    if (x_variant && (has_length || has_stride)) {
+      GTEST_FAIL();
+    }
+
+    // xx variant can't have no length, no stride, and no post_increment
+    // encoding
+    if (!x_variant && !has_length && !has_stride && !post_increment) {
+      GTEST_FAIL();
+    }
+
+    // length and stride fields can't coexist without post_increment
+    if (has_length && has_stride && !post_increment) {
+      GTEST_FAIL();
+    }
+
+    // Quad store need to have stride specified and no length
+    if (is_quad && is_load) {
+      GTEST_FAIL();
+    }
+    if ((is_quad && has_length) || (is_quad && !has_stride)) {
+      GTEST_FAIL();
+    }
+    const uint32_t vector_length_in_bytes = state_->vector_length() / 8;
+    const uint32_t vd_size = vector_length_in_bytes / sizeof(T);
+    const uint32_t len_or_strides[] = {0,       1,           vd_size - 1,
+                                       vd_size, 2 * vd_size, 4 * vd_size};
+
+    // Check with different values for length and stride if applicable.
+    for (int test = 0;
+         test < (has_length || has_stride ? std::size(len_or_strides) : 1);
+         test++) {
+      // Store stride can't be smaller than vd_size
+      if ((is_quad && len_or_strides[test] < vd_size / 4) ||
+          (!is_load && has_stride && len_or_strides[test] < vd_size)) {
+        continue;
+      }
+      // Set input register values.
+      SetRegisterValues<uint32_t>(
+          {{kelvin::sim::test::kRs1Name, kelvin::sim::test::kDataLoadAddress}});
+
+      if (!x_variant) {
+        SetRegisterValues<uint32_t>(
+            {{kelvin::sim::test::kRs2Name, len_or_strides[test]}});
+      }
+
+      // Fill vector register(s) with random values.
+      std::vector<T> vd_value(vector_length_in_bytes / sizeof(T) * num_ops);
+      auto vd_span = absl::Span<T>(vd_value);
+      FillArrayWithRandomValues<T>(vd_span);
+      for (int i = 0; i < num_ops; i++) {
+        auto vd_name = absl::StrCat("v", kelvin::sim::test::kVd + i);
+        SetVectorRegisterValues<T>(
+            {{vd_name, vd_span.subspan(vd_size * i, vd_size)}});
+      }
+
+      // Execute instruction.
+      instruction->Execute();
+
+      // Compute memory values. For load test it is the expected output; for
+      // store test it is the actual output.
+      std::vector<T> memory_values(vd_size * num_ops);
+      uint32_t addr = kelvin::sim::test::kDataLoadAddress;
+      uint32_t rs2_value = len_or_strides[test];
+      uint32_t count = vd_size * num_ops;
+      if (has_length) {
+        count = std::min(count, rs2_value);
+      }
+      uint32_t left = count;
+      for (int op_num = 0; op_num < num_ops; op_num++) {
+        const int n = std::min(vd_size, left);
+        if (is_quad) {
+          const uint32_t quad_size = vd_size / 4;
+          for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < quad_size; ++j) {
+              memory_values[op_num * vd_size + i * quad_size + j] =
+                  GetSavedMemoryValue<T>(addr +
+                                         (i * quad_size + j) * sizeof(T));
+            }
+            // Stride increase per quad_size.
+            addr += rs2_value * sizeof(T);
+          }
+        } else {
+          for (int i = 0; i < vd_size; ++i) {
+            if (is_load) {
+              memory_values[op_num * vd_size + i] =
+                  i < n ? GetDefaultMemoryValue<T>(addr + i * sizeof(T)) : 0;
+            } else {
+              memory_values[op_num * vd_size + i] =
+                  i < n ? GetSavedMemoryValue<T>(addr + i * sizeof(T)) : 0;
+            }
+          }
+          left -= n;
+          if (has_stride) {
+            addr += rs2_value * sizeof(T);
+          } else {
+            addr += n * sizeof(T);
+          }
+        }
+      }
+
+      uint32_t expected_rs1_value = kelvin::sim::test::kDataLoadAddress;
+      if (post_increment && count) {
+        if (has_length && has_stride) {  // .tp
+          expected_rs1_value += vd_size * sizeof(T);
+        } else if (!has_length && !has_stride && x_variant) {  // .p.x
+          expected_rs1_value += vd_size * sizeof(T) * num_ops;
+        } else if (has_length) {  // .lp
+          expected_rs1_value += count * sizeof(T);
+        } else if (has_stride) {  // .sp
+          const uint32_t quad_scale = is_quad ? 4 : 1;
+          expected_rs1_value += rs2_value * sizeof(T) * num_ops * quad_scale;
+        } else {  // .p.xx
+          expected_rs1_value += rs2_value * sizeof(T);
+        }
+      }
+
+      // Check result
+      left = count;
+      for (int op_num = 0; op_num < num_ops; op_num++) {
+        auto vreg_num = kelvin::sim::test::kVd + op_num;
+        auto test_vreg = vreg_[vreg_num];
+        auto vreg_span = test_vreg->data_buffer()->Get<T>();
+        if (is_load) {
+          for (int element_index = 0; element_index < vd_size;
+               element_index++) {
+            auto vreg_element_index = op_num * vd_size + element_index;
+            EXPECT_EQ(memory_values[vreg_element_index],
+                      vreg_span[element_index])
+                << absl::StrCat(name, "[", vreg_element_index, "] != reg[",
+                                vreg_num, "*", element_index, "]");
+          }
+        } else {  // Store
+          const int n = std::min(vd_size, left);
+          for (int element_index = 0;
+               element_index < vd_size && element_index < n; element_index++) {
+            auto total_element_index = op_num * vd_size + element_index;
+            EXPECT_EQ(memory_values[total_element_index],
+                      vreg_span[element_index])
+                << absl::StrCat(name, " mem at ", total_element_index,
+                                " != vreg[", vreg_num, "][", element_index,
+                                "]");
+          }
+          left -= n;
+        }
+      }
+
+      if (post_increment) {
+        // Check rs1 value.
+        auto *reg = state_
+                        ->GetRegister<kelvin::sim::test::RV32Register>(
+                            kelvin::sim::test::kRs1Name)
+                        .first;
+        EXPECT_EQ(expected_rs1_value, reg->data_buffer()->Get<uint32_t>()[0])
+            << absl::StrCat(name, " post incremented rs1 is incorrect.");
+      }
+    }
+  }
+
+  template <typename T>
+  void MemoryLoadStoreOpTestHelper(absl::string_view name, bool is_load) {
+    constexpr bool kNoLength = false;
+    constexpr bool kLength = true;
+    constexpr bool kNoStride = false;
+    constexpr bool kStride = true;
+    constexpr bool kPostIncrement = true;
+    constexpr bool kXVariant = true;
+    constexpr bool kNotXVariant = false;
+    constexpr bool kNotQuad = false;
+
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<T>());
+
+    for (auto strip_mine : {false, true}) {
+      for (auto post_increment : {false, true}) {
+        // .x variants.
+        auto subname = absl::StrCat(name_with_type, post_increment ? "P" : "",
+                                    "X", strip_mine ? "M" : "");
+        MemoryLoadStoreOpTestHelper<T>(subname, kNoLength, kNoStride,
+                                       strip_mine, post_increment, kXVariant,
+                                       is_load, kNotQuad);
+      }
+      // .xx variants
+      for (auto len_stride_post :
+           {std::tuple(false, false, true), std::tuple(false, true, false),
+            std::tuple(false, true, true), std::tuple(true, false, false),
+            std::tuple(true, false, true)}) {
+        auto has_length = std::get<0>(len_stride_post);
+        auto has_stride = std::get<1>(len_stride_post);
+        auto post_increment = std::get<2>(len_stride_post);
+        auto subname = absl::StrCat(name_with_type,
+                                    has_length   ? "L"
+                                    : has_stride ? "S"
+                                                 : "",
+                                    post_increment ? "P" : "", "XX",
+                                    strip_mine ? "M" : "");
+        MemoryLoadStoreOpTestHelper<T>(subname, has_length, has_stride,
+                                       strip_mine, post_increment, kNotXVariant,
+                                       is_load, kNotQuad);
+      }
+
+      // .tp variants.
+      auto subname =
+          absl::StrCat(name_with_type, "TP", "XX", strip_mine ? "M" : "");
+      MemoryLoadStoreOpTestHelper<T>(subname, kLength, kStride, strip_mine,
+                                     kPostIncrement, kNotXVariant, is_load,
+                                     kNotQuad);
+    }
+  }
+
+  template <typename T>
+  void StoreQuadOpTestHelper(absl::string_view name) {
+    const auto name_with_type = absl::StrCat(name, KelvinTestTypeSuffix<T>());
+    constexpr bool kNotLength = false;
+    constexpr bool kStride = true;
+    constexpr bool kNotXVariant = false;
+    constexpr bool kNotLoad = false;
+    constexpr bool kIsQuad = true;
+    for (auto strip_mine : {false, true}) {
+      for (auto post_increment : {false, true}) {
+        auto subname =
+            absl::StrCat(name_with_type, "S", post_increment ? "P" : "", "XX",
+                         strip_mine ? "M" : "");
+        MemoryLoadStoreOpTestHelper<T>(subname, kNotLength, kStride, strip_mine,
+                                       post_increment, kNotXVariant, kNotLoad,
+                                       kIsQuad);
+      }
+    }
+  }
+
+  template <typename T1, typename TNext1, typename... TNext>
+  void MemoryLoadStoreOpTestHelper(absl::string_view name, bool is_load) {
+    MemoryLoadStoreOpTestHelper<T1>(name, is_load);
+    MemoryLoadStoreOpTestHelper<TNext1, TNext...>(name, is_load);
+  }
+
+  template <typename T1, typename TNext1, typename... TNext>
+  void StoreQuadOpTestHelper(absl::string_view name) {
+    StoreQuadOpTestHelper<T1>(name);
+    StoreQuadOpTestHelper<TNext1, TNext...>(name);
+  }
+
+ protected:
+  template <typename T>
+  T GetDefaultMemoryValue(int address) {
+    T value = 0;
+    uint8_t *ptr = reinterpret_cast<uint8_t *>(&value);
+    for (int j = 0; j < sizeof(T); j++) {
+      ptr[j] = (address + j) & 0xff;
+    }
+    return value;
+  }
+
+  template <typename T>
+  T GetSavedMemoryValue(int address) {
+    auto *db = state_->db_factory()->Allocate<T>(1);
+    memory_->Load(address, db, nullptr, nullptr);
+    T data = db->template Get<T>(0);
+    db->DecRef();
+    return data;
+  }
+};
+
+TEST_F(KelvinVectorInstructionsMemoryTest, VLd) {
+  MemoryLoadStoreOpTestHelper<int8_t, int16_t, int32_t>("VLd",
+                                                        /*is_load=*/true);
+}
+
+TEST_F(KelvinVectorInstructionsMemoryTest, VSt) {
+  MemoryLoadStoreOpTestHelper<int8_t, int16_t, int32_t>("VSt",
+                                                        /*is_load=*/false);
+}
+
+TEST_F(KelvinVectorInstructionsMemoryTest, VStQ) {
+  StoreQuadOpTestHelper<int8_t, int16_t, int32_t>("VStQ");
+}
+
+class KelvinGetVlInstructionTest : public KelvinVectorInstructionsTest {
+ public:
+  template <typename T>
+  void GetVlTestHelper() {
+    constexpr char kRdName[] = "x8";
+    constexpr uint32_t kMaxVlenInBytes = kelvin::sim::kVectorLengthInBits / 8;
+    auto instruction = CreateInstruction();
+    AppendRegisterOperands(
+        instruction.get(),
+        {kelvin::sim::test::kRs1Name, kelvin::sim::test::kRs2Name}, {kRdName});
+    for (auto strip_mine : {false, true}) {
+      for (auto is_rs1 : {false, true}) {
+        for (auto is_rs2 : {false, true}) {
+          uint32_t rs1_value = RandomValue();
+          uint32_t rs2_value = RandomValue();
+          SetRegisterValues<uint32_t>({{kelvin::sim::test::kRs1Name, rs1_value},
+                                       {kelvin::sim::test::kRs2Name, rs2_value},
+                                       {kRdName, UINT32_MAX}});
+          instruction->set_semantic_function(
+              absl::bind_front(&KelvinGetVl<T>, strip_mine, is_rs1, is_rs2));
+          uint32_t expected_vlen =
+              kMaxVlenInBytes / sizeof(T) * (strip_mine ? 4 : 1);
+          if (is_rs1) {
+            expected_vlen = std::min(expected_vlen, rs1_value);
+          }
+          if (is_rs2) {
+            expected_vlen = std::min(expected_vlen, rs2_value);
+          }
+          // Execute instruction.
+          instruction->Execute(nullptr);
+          EXPECT_EQ(xreg_[8]->data_buffer()->Get<uint32_t>(0), expected_vlen)
+              << "Test failed with type "
+              << (sizeof(T) == 4 ? "W" : (sizeof(T) == 2 ? "H" : "B"))
+              << ", strip_mine: " << strip_mine << ", rs1_set: " << is_rs1
+              << ", rs2_set: " << is_rs2;
+        }
+      }
+    }
+  }
+
+  template <typename T1, typename TNext1, typename... TNext>
+  void GetVlTestHelper() {
+    GetVlTestHelper<T1>();
+    GetVlTestHelper<TNext1, TNext...>();
+  }
+
+ protected:
+  // Create a random value in the valid range for the type.
+  uint32_t RandomValue() {
+    return absl::Uniform(absl::IntervalClosed, bitgen_,
+                         std::numeric_limits<uint32_t>::lowest(),
+                         std::numeric_limits<uint32_t>::max());
+  }
+};
+
+TEST_F(KelvinGetVlInstructionTest, GetVl) {
+  GetVlTestHelper<int8_t, int16_t, int32_t>();
+}
+
+}  // namespace
diff --git a/sim/test/kelvin_vector_instructions_test_base.h b/sim/test/kelvin_vector_instructions_test_base.h
new file mode 100644
index 0000000..9afde0b
--- /dev/null
+++ b/sim/test/kelvin_vector_instructions_test_base.h
@@ -0,0 +1,459 @@
+#ifndef SIM_TEST_KELVIN_VECTOR_INSTRUCTIONS_TEST_BASE_H_
+#define SIM_TEST_KELVIN_VECTOR_INSTRUCTIONS_TEST_BASE_H_
+
+#include <sys/types.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "sim/kelvin_state.h"
+#include "googletest/include/gtest/gtest.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+#include "riscv/riscv_register.h"
+#include "riscv/riscv_state.h"
+#include "mpact/sim/generic/instruction.h"
+#include "mpact/sim/generic/register.h"
+#include "mpact/sim/generic/state_item.h"
+#include "mpact/sim/generic/type_helpers.h"
+#include "mpact/sim/util/memory/flat_demand_memory.h"
+
+namespace kelvin::sim::test {
+
+using absl::Span;
+using mpact::sim::generic::Instruction;
+using mpact::sim::generic::RegisterBase;
+using mpact::sim::riscv::RV32Register;
+using mpact::sim::riscv::RV32VectorDestinationOperand;
+using mpact::sim::riscv::RV32VectorSourceOperand;
+using mpact::sim::riscv::RVFpRegister;
+using mpact::sim::riscv::RVVectorRegister;
+using mpact::sim::util::FlatDemandMemory;
+
+// Constants used in the tests.
+constexpr uint32_t kInstAddress = 0x1000;
+constexpr uint32_t kDataLoadAddress = 0x1'0000;
+constexpr uint32_t kNumVectorRegister = 64;
+constexpr char kRs1Name[] = "x1";
+constexpr char kRs2Name[] = "x2";
+constexpr int kRs1 = 1;
+constexpr int kVd = 32;
+constexpr int kVs1 = 8;
+constexpr int kVs2 = 24;
+
+// This is the base class for vector instruction test fixtures. It implements
+// generic methods for testing and supporting testing of the RiscV vector
+// instructions.
+class KelvinVectorInstructionsTestBase : public testing::Test {
+ public:
+  KelvinVectorInstructionsTestBase() {
+    memory_ = new FlatDemandMemory(0);
+    state_ =
+        new KelvinState("test", mpact::sim::riscv::RiscVXlen::RV32, memory_);
+    // Initialize a portion of memory with a known pattern.
+    auto *db = state_->db_factory()->Allocate(8192);
+    auto span = db->Get<uint8_t>();
+    for (int i = 0; i < 8192; i++) {
+      span[i] = i & 0xff;
+    }
+    memory_->Store(kDataLoadAddress - 4096, db);
+    db->DecRef();
+    for (int i = 1; i < 32; i++) {
+      xreg_[i] = state_->GetRegister<RV32Register>(absl::StrCat("x", i)).first;
+    }
+    for (int i = 1; i < kNumVectorRegister; i++) {
+      vreg_[i] =
+          state_->GetRegister<RVVectorRegister>(absl::StrCat("v", i)).first;
+    }
+  }
+
+  template <typename Vd, typename Vs1, typename Vs2>
+  static std::pair<Vs1, Vs2> CommonBinaryOpArgsGetter(
+      int num_ops, int op_num, int dest_reg_sub_index, int element_index,
+      int vd_size, bool widen_dst, int src1_widen_factor, int vs1_size,
+      const std::vector<Vs1> &vs1_value, int vs2_size, bool s2_scalar,
+      const std::vector<Vs2> &vs2_value, Vs2 rs2_value, bool halftype_op,
+      bool vmvp_op) {
+    auto src1_element_index =
+        op_num * vs1_size + element_index * sizeof(Vd) / sizeof(Vs1);
+    if (!vmvp_op) {
+      if (widen_dst) {
+        src1_element_index += (src1_widen_factor > 1 ? num_ops * vs1_size : 1) *
+                              dest_reg_sub_index;
+      } else if (src1_widen_factor == 2) {
+        src1_element_index += element_index & 1 ? num_ops * vs1_size : 0;
+      } else if (src1_widen_factor == 4) {
+        const int interleave[4] = {0, 2, 1, 3};
+        src1_element_index +=
+            interleave[element_index & 3] * num_ops * vs1_size;
+      }
+    }
+
+    auto src2_element_index = op_num * vs2_size +
+                              element_index * (widen_dst && !vmvp_op ? 2 : 1) +
+                              (vmvp_op ? 0 : 1) * dest_reg_sub_index;
+    Vs1 arg1 = vs1_value[src1_element_index];
+    Vs2 arg2 = halftype_op ? vs1_value[src1_element_index + 1]
+                           : vs2_value[src2_element_index];
+    arg2 = s2_scalar ? rs2_value : arg2;
+    if (vmvp_op && dest_reg_sub_index == 1) {
+      arg1 = arg2;
+    }
+
+    return {arg1, arg2};
+  }
+
+  template <typename Vd, typename Vs1, typename Vs2>
+  using BinaryOpsArgsGetter =
+      std::function<decltype(CommonBinaryOpArgsGetter<Vd, Vs1, Vs2>)>;
+
+  // Helper function for testing vector-vector instructions.
+  template <typename Vd, typename Vs1, typename Ts2, typename... VDArgs>
+  void BinaryOpTestHelper(Instruction::SemanticFunction fcn,
+                          absl::string_view name, bool s2_scalar,
+                          bool strip_mine,
+                          std::function<Vd(VDArgs..., Vs1, Ts2)> operation,
+                          BinaryOpsArgsGetter<Vd, Vs1, Ts2> args_getter,
+                          bool halftype_op, bool vmvp_op, bool widen_dst) {
+    auto instruction = CreateInstruction();
+    instruction->set_semantic_function(fcn);
+
+    const uint32_t num_ops = strip_mine ? 4 : 1;
+    constexpr int src1_widen_factor = sizeof(Vs1) / sizeof(Ts2);
+    static_assert(src1_widen_factor == 1 || src1_widen_factor == 2 ||
+                  src1_widen_factor == 4);
+
+    // Half type ops don't use s2, so s2_scalar should be false.
+    if (halftype_op && s2_scalar) {
+      GTEST_FAIL();
+    }
+
+    if (s2_scalar) {
+      AppendVectorRegisterOperands(instruction.get(), num_ops,
+                                   src1_widen_factor, kVs1, {}, widen_dst,
+                                   {kVd});
+      AppendRegisterOperands(instruction.get(), {kRs1Name}, {});
+    } else if (halftype_op) {
+      AppendVectorRegisterOperands(instruction.get(), num_ops,
+                                   src1_widen_factor, kVs1, {}, widen_dst,
+                                   {kVd});
+    } else {
+      AppendVectorRegisterOperands(instruction.get(), num_ops,
+                                   src1_widen_factor, kVs1, {kVs2}, widen_dst,
+                                   {kVd});
+    }
+
+    // Initialize input values.
+    const auto vector_length_in_bytes = state_->vector_length() / 8;
+    int vs1_size = vector_length_in_bytes / sizeof(Vs1);
+    const size_t vs1_regs_count = num_ops * src1_widen_factor;
+    std::vector<Vs1> vs1_value(vs1_size * vs1_regs_count);
+    auto vs1_span = absl::Span<Vs1>(vs1_value);
+    FillArrayWithRandomValues<Vs1>(vs1_span);
+    for (int i = 0; i < vs1_regs_count; i++) {
+      auto vs1_name = absl::StrCat("v", kVs1 + i);
+      SetVectorRegisterValues<Vs1>(
+          {{vs1_name, vs1_span.subspan(vs1_size * i, vs1_size)}});
+    }
+
+    int vs2_size = vector_length_in_bytes / sizeof(Ts2);
+    std::vector<Ts2> vs2_value(vs2_size * num_ops);
+    Ts2 rs2_value = 0;
+
+    if (s2_scalar) {
+      // Generate a new rs2 value.
+      RV32Register::ValueType rs2_reg_value =
+          RandomValue<RV32Register::ValueType>();
+      SetRegisterValues<RV32Register::ValueType>({{kRs1Name, rs2_reg_value}});
+      // Cast the value to the appropriate width, sign-extending if needed.
+      rs2_value = static_cast<Ts2>(
+          static_cast<typename mpact::sim::riscv::SameSignedType<
+              RV32Register::ValueType, Ts2>::type>(rs2_reg_value));
+    } else if (!halftype_op) {
+      auto vs2_span = absl::Span<Ts2>(vs2_value);
+      FillArrayWithRandomValues<Ts2>(vs2_span);
+      for (int i = 0; i < num_ops; i++) {
+        auto vs2_name = absl::StrCat("v", kVs2 + i);
+        SetVectorRegisterValues<Ts2>(
+            {{vs2_name, vs2_span.subspan(vs2_size * i, vs2_size)}});
+      }
+    }
+
+    const size_t dest_regs_per_op = widen_dst ? 2 : 1;
+    const size_t vd_size = vector_length_in_bytes / sizeof(Vd);
+    const size_t dest_regs_count = num_ops * dest_regs_per_op;
+    std::vector<Vd> vd_value(vd_size * dest_regs_count);
+    auto vd_span = absl::Span<Vd>(vd_value);
+    FillArrayWithRandomValues<Vd>(vd_span);
+    for (int i = 0; i < dest_regs_count; i++) {
+      auto vd_name = absl::StrCat("v", kVd + i);
+      SetVectorRegisterValues<Vd>(
+          {{vd_name, vd_span.subspan(vd_size * i, vd_size)}});
+    }
+
+    // Executing instruction.
+    instruction->Execute();
+
+    // Check if ops gives the same result as vd.
+    for (int op_num = 0; op_num < num_ops; op_num++) {
+      for (int dest_reg_sub_index = 0; dest_reg_sub_index < dest_regs_per_op;
+           dest_reg_sub_index++) {
+        auto dest_reg_index = dest_reg_sub_index * num_ops + op_num;
+        auto dest_vreg_num = kVd + dest_reg_index;
+        auto dest_reg = vreg_[dest_vreg_num];
+        auto dest_span = dest_reg->data_buffer()->Get<Vd>();
+
+        for (int element_index = 0; element_index < vd_size; element_index++) {
+          auto args = args_getter(
+              num_ops, op_num, dest_reg_sub_index, element_index, vd_size,
+              widen_dst, src1_widen_factor, vs1_size, vs1_value, vs2_size,
+              s2_scalar, vs2_value, rs2_value, halftype_op, vmvp_op);
+
+          auto dst_element_index = dest_reg_index * vd_size + element_index;
+          auto expected_value = BinaryOpInvoke(
+              operation, vd_value[dst_element_index], args.first, args.second);
+          EXPECT_EQ(expected_value, dest_span[element_index])
+              << absl::StrCat(name, "[", dst_element_index, "] != reg[",
+                              dest_vreg_num, "*", element_index, "]");
+        }
+      }
+    }
+  }
+
+  template <typename Vd, typename Vs1, typename Ts2, typename... VDArgs>
+  void BinaryOpTestHelper(Instruction::SemanticFunction fcn,
+                          absl::string_view name, bool s2_scalar,
+                          bool strip_mine,
+                          std::function<Vd(VDArgs..., Vs1, Ts2)> operation,
+                          bool halftype_op = false, bool vmvp_op = false) {
+    const bool widen_dst =
+        (sizeof(Vd) > sizeof(Ts2) && !halftype_op) || vmvp_op;
+    BinaryOpTestHelper<Vd, Vs1, Ts2, VDArgs...>(
+        fcn, name, s2_scalar, strip_mine, operation,
+        CommonBinaryOpArgsGetter<Vd, Vs1, Ts2>, halftype_op, vmvp_op,
+        widen_dst);
+  }
+
+  template <typename Vd, typename Vs1, typename Ts2>
+  void BinaryOpTestHelper(Instruction::SemanticFunction fcn,
+                          absl::string_view name, bool s2_scalar,
+                          bool strip_mine,
+                          std::function<Vd(Vd, Vs1, Ts2)> operation) {
+    BinaryOpTestHelper<Vd, Vs1, Ts2, Vd>(fcn, name, s2_scalar, strip_mine,
+                                         operation);
+  }
+
+  // Helper function for testing single vector argument instructions.
+  template <typename Vd, typename Vs>
+  void UnaryOpTestHelper(Instruction::SemanticFunction fcn,
+                         absl::string_view name, bool strip_mine,
+                         std::function<Vd(Vs)> operation) {
+    auto instruction = CreateInstruction();
+    instruction->set_semantic_function(fcn);
+
+    const uint32_t num_ops = strip_mine ? 4 : 1;
+
+    AppendVectorRegisterOperands(instruction.get(), num_ops,
+                                 1 /* src1_widen_factor */, kVs1, {},
+                                 false /* widen_dst */, {kVd});
+
+    // Initialize input values.
+    const auto vector_length_in_bytes = state_->vector_length() / 8;
+    int vs_size = vector_length_in_bytes / sizeof(Vs);
+    const size_t vs_regs_count = num_ops;
+    std::vector<Vs> vs_value(vs_size * vs_regs_count);
+    auto vs_span = absl::Span<Vs>(vs_value);
+    FillArrayWithRandomValues<Vs>(vs_span);
+    for (int i = 0; i < vs_regs_count; i++) {
+      auto vs1_name = absl::StrCat("v", kVs1 + i);
+      SetVectorRegisterValues<Vs>(
+          {{vs1_name, vs_span.subspan(vs_size * i, vs_size)}});
+    }
+
+    const size_t vd_size = vector_length_in_bytes / sizeof(Vd);
+    const size_t dest_regs_count = num_ops;
+    std::vector<Vd> vd_value(vd_size * dest_regs_count);
+    auto vd_span = absl::Span<Vd>(vd_value);
+    FillArrayWithRandomValues<Vd>(vd_span);
+    for (int i = 0; i < dest_regs_count; i++) {
+      auto vd_name = absl::StrCat("v", kVd + i);
+      SetVectorRegisterValues<Vd>(
+          {{vd_name, vd_span.subspan(vd_size * i, vd_size)}});
+    }
+
+    // Executing instruction.
+    instruction->Execute();
+
+    // Check if ops gives the same result as vd.
+    for (int op_num = 0; op_num < num_ops; op_num++) {
+      auto dest_reg_index = op_num;
+      auto dest_vreg_num = kVd + dest_reg_index;
+      auto dest_reg = vreg_[dest_vreg_num];
+      auto dest_span = dest_reg->data_buffer()->Get<Vd>();
+
+      for (int element_index = 0; element_index < vd_size; element_index++) {
+        auto dst_element_index = dest_reg_index * vd_size + element_index;
+        auto src1_element_index =
+            op_num * vs_size + element_index * sizeof(Vd) / sizeof(Vs);
+
+        Vs arg = vs_value[src1_element_index];
+        auto expected_value = operation(arg);
+        EXPECT_EQ(expected_value, dest_span[element_index])
+            << absl::StrCat(name, "[", dst_element_index, "] != reg[",
+                            dest_vreg_num, "*", element_index, "]");
+      }
+    }
+  }
+
+  ~KelvinVectorInstructionsTestBase() override {
+    delete state_;
+    delete memory_;
+  }
+
+ protected:
+  // Helper function invoking vector operations which aren't reading Vd
+  template <typename Vd, typename Vs1, typename Vs2>
+  Vd BinaryOpInvoke(std::function<Vd(Vs1, Vs2)> op, Vd vd, Vs1 vs1, Vs2 vs2) {
+    return op(vs1, vs2);
+  }
+
+  // Overloaded version which for operations reading Vd
+  template <typename Vd, typename Vs1, typename Vs2>
+  Vd BinaryOpInvoke(std::function<Vd(Vd, Vs1, Vs2)> op, Vd vd, Vs1 vs1,
+                    Vs2 vs2) {
+    return op(vd, vs1, vs2);
+  }
+
+  // Create a random value in the valid range for the type.
+  template <typename T>
+  T RandomValue() {
+    return absl::Uniform(absl::IntervalClosed, bitgen_,
+                         std::numeric_limits<T>::lowest(),
+                         std::numeric_limits<T>::max());
+  }
+
+  // Fill the span with random values.
+  template <typename T>
+  void FillArrayWithRandomValues(absl::Span<T> span) {
+    for (auto &val : span) {
+      val = RandomValue<T>();
+    }
+  }
+
+  // Set a vector register value. Takes a vector of tuples of register names and
+  // spans of values, fetches each register and sets it to the corresponding
+  // value.
+  template <typename T>
+  void SetVectorRegisterValues(
+      const std::vector<std::tuple<std::string, Span<const T>>> &values) {
+    for (auto &[vreg_name, span] : values) {
+      auto *vreg = state_->GetRegister<RVVectorRegister>(vreg_name).first;
+      auto *db = state_->db_factory()->MakeCopyOf(vreg->data_buffer());
+      db->template Set<T>(span);
+      vreg->SetDataBuffer(db);
+      db->DecRef();
+    }
+  }
+
+  // Set the named registers to their corresponding value.
+  template <typename T, typename RegisterType = RV32Register>
+  void SetRegisterValues(
+      const std::vector<std::tuple<std::string, const T>> &values) {
+    for (auto &[reg_name, value] : values) {
+      auto *reg = state_->GetRegister<RegisterType>(reg_name).first;
+      auto *db =
+          state_->db_factory()->Allocate<typename RegisterType::ValueType>(1);
+      db->template Set<T>(0, value);
+      reg->SetDataBuffer(db);
+      db->DecRef();
+    }
+  }
+
+  // Creates source and destination scalar register operands for the registers
+  // named in the two vectors and appends them to the given instruction.
+  void AppendRegisterOperands(Instruction *inst,
+                              const std::vector<std::string> &sources,
+                              const std::vector<std::string> &destinations) {
+    for (auto &reg_name : sources) {
+      auto *reg = state_->GetRegister<RV32Register>(reg_name).first;
+      inst->AppendSource(reg->CreateSourceOperand());
+    }
+    for (auto &reg_name : destinations) {
+      auto *reg = state_->GetRegister<RV32Register>(reg_name).first;
+      inst->AppendDestination(reg->CreateDestinationOperand(0));
+    }
+  }
+
+  // Creates source and destination scalar register operands for the registers
+  // named in the two vectors and appends them to the given instruction.
+  void AppendVectorRegisterOperands(Instruction *inst, const uint32_t num_ops,
+                                    int src1_widen_factor, int src1_reg,
+                                    const std::vector<int> &other_sources,
+                                    bool widen_dst,
+                                    const std::vector<int> &destinations) {
+    {
+      std::vector<RegisterBase *> reg_vec;
+      auto regs_count = src1_widen_factor * num_ops;
+      for (int i = 0; (i < regs_count) && (i + src1_reg < kNumVectorRegister);
+           i++) {
+        std::string reg_name = absl::StrCat("v", i + src1_reg);
+        reg_vec.push_back(
+            state_->GetRegister<RVVectorRegister>(reg_name).first);
+      }
+      auto *op = new RV32VectorSourceOperand(
+          absl::Span<RegisterBase *>(reg_vec), absl::StrCat("v", src1_reg));
+      inst->AppendSource(op);
+    }
+    for (auto &reg_no : other_sources) {
+      std::vector<RegisterBase *> reg_vec;
+      for (int i = 0; (i < num_ops) && (i + reg_no < kNumVectorRegister); i++) {
+        std::string reg_name = absl::StrCat("v", i + reg_no);
+        reg_vec.push_back(
+            state_->GetRegister<RVVectorRegister>(reg_name).first);
+      }
+      auto *op = new RV32VectorSourceOperand(
+          absl::Span<RegisterBase *>(reg_vec), absl::StrCat("v", reg_no));
+      inst->AppendSource(op);
+    }
+    for (auto &reg_no : destinations) {
+      std::vector<RegisterBase *> reg_vec;
+      auto regs_count = widen_dst ? num_ops * 2 : num_ops;
+      for (int i = 0; (i < regs_count) && (i + reg_no < kNumVectorRegister);
+           i++) {
+        std::string reg_name = absl::StrCat("v", i + reg_no);
+        reg_vec.push_back(
+            state_->GetRegister<RVVectorRegister>(reg_name).first);
+      }
+      auto *op = new RV32VectorDestinationOperand(
+          absl::Span<RegisterBase *>(reg_vec), 0, absl::StrCat("v", reg_no));
+      inst->AppendDestination(op);
+    }
+  }
+
+  using InstructionPtr = std::unique_ptr<Instruction, void (*)(Instruction *)>;
+  InstructionPtr CreateInstruction() {
+    InstructionPtr inst(new Instruction(next_instruction_address_, state_),
+                        [](Instruction *inst) { inst->DecRef(); });
+    inst->set_size(4);
+    next_instruction_address_ += 4;
+    return inst;
+  }
+
+  RVVectorRegister *vreg_[kNumVectorRegister];
+  RV32Register *xreg_[32];
+  KelvinState *state_;
+  FlatDemandMemory *memory_;
+  absl::BitGen bitgen_;
+  uint32_t next_instruction_address_ = kInstAddress;
+};
+}  // namespace kelvin::sim::test
+#endif  // SIM_TEST_KELVIN_VECTOR_INSTRUCTIONS_TEST_BASE_H_
diff --git a/sim/test/testfiles/hello_world_mpause.elf b/sim/test/testfiles/hello_world_mpause.elf
new file mode 100755
index 0000000..5e74f05
--- /dev/null
+++ b/sim/test/testfiles/hello_world_mpause.elf
Binary files differ
diff --git a/sim/test/testfiles/hello_world_rv32imf.elf b/sim/test/testfiles/hello_world_rv32imf.elf
new file mode 100755
index 0000000..11f5b65
--- /dev/null
+++ b/sim/test/testfiles/hello_world_rv32imf.elf
Binary files differ
diff --git a/sim/test/testfiles/rv32i.elf b/sim/test/testfiles/rv32i.elf
new file mode 100755
index 0000000..3429922
--- /dev/null
+++ b/sim/test/testfiles/rv32i.elf
Binary files differ
diff --git a/sim/test/testfiles/rv32m.elf b/sim/test/testfiles/rv32m.elf
new file mode 100755
index 0000000..1a2835a
--- /dev/null
+++ b/sim/test/testfiles/rv32m.elf
Binary files differ
diff --git a/sim/test/testfiles/rv32soft_fp.elf b/sim/test/testfiles/rv32soft_fp.elf
new file mode 100755
index 0000000..337c2cb
--- /dev/null
+++ b/sim/test/testfiles/rv32soft_fp.elf
Binary files differ