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 ®_name : sources) { + auto *reg = state_->GetRegister<RV32Register>(reg_name).first; + inst->AppendSource(reg->CreateSourceOperand()); + } + for (auto ®_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 ®_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 ®_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