aboutsummaryrefslogtreecommitdiffstats
path: root/target/riscv
diff options
context:
space:
mode:
Diffstat (limited to 'target/riscv')
-rw-r--r--target/riscv/Kconfig5
-rw-r--r--target/riscv/arch_dump.c202
-rw-r--r--target/riscv/bitmanip_helper.c51
-rw-r--r--target/riscv/cpu-param.h32
-rw-r--r--target/riscv/cpu.c819
-rw-r--r--target/riscv/cpu.h495
-rw-r--r--target/riscv/cpu_bits.h618
-rw-r--r--target/riscv/cpu_helper.c1138
-rw-r--r--target/riscv/cpu_user.h19
-rw-r--r--target/riscv/csr.c2098
-rw-r--r--target/riscv/fpu_helper.c376
-rw-r--r--target/riscv/gdbstub.c212
-rw-r--r--target/riscv/helper.h1149
-rw-r--r--target/riscv/insn16.decode162
-rw-r--r--target/riscv/insn32.decode728
-rw-r--r--target/riscv/insn_trans/trans_privileged.c.inc128
-rw-r--r--target/riscv/insn_trans/trans_rva.c.inc226
-rw-r--r--target/riscv/insn_trans/trans_rvb.c.inc506
-rw-r--r--target/riscv/insn_trans/trans_rvd.c.inc449
-rw-r--r--target/riscv/insn_trans/trans_rvf.c.inc473
-rw-r--r--target/riscv/insn_trans/trans_rvh.c.inc186
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc577
-rw-r--r--target/riscv/insn_trans/trans_rvm.c.inc271
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc2867
-rw-r--r--target/riscv/instmap.h369
-rw-r--r--target/riscv/internals.h61
-rw-r--r--target/riscv/machine.c223
-rw-r--r--target/riscv/meson.build32
-rw-r--r--target/riscv/monitor.c236
-rw-r--r--target/riscv/op_helper.c249
-rw-r--r--target/riscv/pmp.c664
-rw-r--r--target/riscv/pmp.h85
-rw-r--r--target/riscv/trace-events11
-rw-r--r--target/riscv/trace.h1
-rw-r--r--target/riscv/translate.c773
-rw-r--r--target/riscv/vector_helper.c4872
36 files changed, 21363 insertions, 0 deletions
diff --git a/target/riscv/Kconfig b/target/riscv/Kconfig
new file mode 100644
index 000000000..b9e5932f1
--- /dev/null
+++ b/target/riscv/Kconfig
@@ -0,0 +1,5 @@
+config RISCV32
+ bool
+
+config RISCV64
+ bool
diff --git a/target/riscv/arch_dump.c b/target/riscv/arch_dump.c
new file mode 100644
index 000000000..709f621d8
--- /dev/null
+++ b/target/riscv/arch_dump.c
@@ -0,0 +1,202 @@
+/* Support for writing ELF notes for RISC-V architectures
+ *
+ * Copyright (C) 2021 Huawei Technologies Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "elf.h"
+#include "sysemu/dump.h"
+
+/* struct user_regs_struct from arch/riscv/include/uapi/asm/ptrace.h */
+struct riscv64_user_regs {
+ uint64_t pc;
+ uint64_t regs[31];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct riscv64_user_regs) != 256);
+
+/* struct elf_prstatus from include/linux/elfcore.h */
+struct riscv64_elf_prstatus {
+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pr_pid;
+ char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
+ offsetof(struct elf_prstatus, pr_ppid) */
+ struct riscv64_user_regs pr_reg;
+ char pad3[8];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct riscv64_elf_prstatus) != 376);
+
+struct riscv64_note {
+ Elf64_Nhdr hdr;
+ char name[8]; /* align_up(sizeof("CORE"), 4) */
+ struct riscv64_elf_prstatus prstatus;
+} QEMU_PACKED;
+
+#define RISCV64_NOTE_HEADER_SIZE offsetof(struct riscv64_note, prstatus)
+#define RISCV64_PRSTATUS_NOTE_SIZE \
+ (RISCV64_NOTE_HEADER_SIZE + sizeof(struct riscv64_elf_prstatus))
+
+static void riscv64_note_init(struct riscv64_note *note, DumpState *s,
+ const char *name, Elf64_Word namesz,
+ Elf64_Word type, Elf64_Word descsz)
+{
+ memset(note, 0, sizeof(*note));
+
+ note->hdr.n_namesz = cpu_to_dump32(s, namesz);
+ note->hdr.n_descsz = cpu_to_dump32(s, descsz);
+ note->hdr.n_type = cpu_to_dump32(s, type);
+
+ memcpy(note->name, name, namesz);
+}
+
+int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque)
+{
+ struct riscv64_note note;
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ DumpState *s = opaque;
+ int ret, i = 0;
+ const char name[] = "CORE";
+
+ riscv64_note_init(&note, s, name, sizeof(name),
+ NT_PRSTATUS, sizeof(note.prstatus));
+
+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
+
+ note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
+
+ for (i = 0; i < 31; i++) {
+ note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->gpr[i + 1]);
+ }
+
+ ret = f(&note, RISCV64_PRSTATUS_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return ret;
+}
+
+struct riscv32_user_regs {
+ uint32_t pc;
+ uint32_t regs[31];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct riscv32_user_regs) != 128);
+
+struct riscv32_elf_prstatus {
+ char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pr_pid;
+ char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
+ offsetof(struct elf_prstatus, pr_ppid) */
+ struct riscv32_user_regs pr_reg;
+ char pad3[4];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct riscv32_elf_prstatus) != 204);
+
+struct riscv32_note {
+ Elf32_Nhdr hdr;
+ char name[8]; /* align_up(sizeof("CORE"), 4) */
+ struct riscv32_elf_prstatus prstatus;
+} QEMU_PACKED;
+
+#define RISCV32_NOTE_HEADER_SIZE offsetof(struct riscv32_note, prstatus)
+#define RISCV32_PRSTATUS_NOTE_SIZE \
+ (RISCV32_NOTE_HEADER_SIZE + sizeof(struct riscv32_elf_prstatus))
+
+static void riscv32_note_init(struct riscv32_note *note, DumpState *s,
+ const char *name, Elf32_Word namesz,
+ Elf32_Word type, Elf32_Word descsz)
+{
+ memset(note, 0, sizeof(*note));
+
+ note->hdr.n_namesz = cpu_to_dump32(s, namesz);
+ note->hdr.n_descsz = cpu_to_dump32(s, descsz);
+ note->hdr.n_type = cpu_to_dump32(s, type);
+
+ memcpy(note->name, name, namesz);
+}
+
+int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque)
+{
+ struct riscv32_note note;
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ DumpState *s = opaque;
+ int ret, i;
+ const char name[] = "CORE";
+
+ riscv32_note_init(&note, s, name, sizeof(name),
+ NT_PRSTATUS, sizeof(note.prstatus));
+
+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
+
+ note.prstatus.pr_reg.pc = cpu_to_dump32(s, env->pc);
+
+ for (i = 0; i < 31; i++) {
+ note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->gpr[i + 1]);
+ }
+
+ ret = f(&note, RISCV32_PRSTATUS_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return ret;
+}
+
+int cpu_get_dump_info(ArchDumpInfo *info,
+ const GuestPhysBlockList *guest_phys_blocks)
+{
+ RISCVCPU *cpu;
+ CPURISCVState *env;
+
+ if (first_cpu == NULL) {
+ return -1;
+ }
+ cpu = RISCV_CPU(first_cpu);
+ env = &cpu->env;
+
+ info->d_machine = EM_RISCV;
+
+#if defined(TARGET_RISCV64)
+ info->d_class = ELFCLASS64;
+#else
+ info->d_class = ELFCLASS32;
+#endif
+
+ info->d_endian = (env->mstatus & MSTATUS_UBE) != 0
+ ? ELFDATA2MSB : ELFDATA2LSB;
+
+ return 0;
+}
+
+ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
+{
+ size_t note_size;
+
+ if (class == ELFCLASS64) {
+ note_size = RISCV64_PRSTATUS_NOTE_SIZE;
+ } else {
+ note_size = RISCV32_PRSTATUS_NOTE_SIZE;
+ }
+
+ return note_size * nr_cpus;
+}
diff --git a/target/riscv/bitmanip_helper.c b/target/riscv/bitmanip_helper.c
new file mode 100644
index 000000000..f1b5e5549
--- /dev/null
+++ b/target/riscv/bitmanip_helper.c
@@ -0,0 +1,51 @@
+/*
+ * RISC-V Bitmanip Extension Helpers for QEMU.
+ *
+ * Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com
+ * Copyright (c) 2020 Frank Chang, frank.chang@sifive.com
+ * Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "tcg/tcg.h"
+
+target_ulong HELPER(clmul)(target_ulong rs1, target_ulong rs2)
+{
+ target_ulong result = 0;
+
+ for (int i = 0; i < TARGET_LONG_BITS; i++) {
+ if ((rs2 >> i) & 1) {
+ result ^= (rs1 << i);
+ }
+ }
+
+ return result;
+}
+
+target_ulong HELPER(clmulr)(target_ulong rs1, target_ulong rs2)
+{
+ target_ulong result = 0;
+
+ for (int i = 0; i < TARGET_LONG_BITS; i++) {
+ if ((rs2 >> i) & 1) {
+ result ^= (rs1 >> (TARGET_LONG_BITS - i - 1));
+ }
+ }
+
+ return result;
+}
diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h
new file mode 100644
index 000000000..80eb615f9
--- /dev/null
+++ b/target/riscv/cpu-param.h
@@ -0,0 +1,32 @@
+/*
+ * RISC-V cpu parameters for qemu.
+ *
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef RISCV_CPU_PARAM_H
+#define RISCV_CPU_PARAM_H 1
+
+#if defined(TARGET_RISCV64)
+# define TARGET_LONG_BITS 64
+# define TARGET_PHYS_ADDR_SPACE_BITS 56 /* 44-bit PPN */
+# define TARGET_VIRT_ADDR_SPACE_BITS 48 /* sv48 */
+#elif defined(TARGET_RISCV32)
+# define TARGET_LONG_BITS 32
+# define TARGET_PHYS_ADDR_SPACE_BITS 34 /* 22-bit PPN */
+# define TARGET_VIRT_ADDR_SPACE_BITS 32 /* sv32 */
+#endif
+#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */
+/*
+ * The current MMU Modes are:
+ * - U mode 0b000
+ * - S mode 0b001
+ * - M mode 0b011
+ * - U mode HLV/HLVX/HSV 0b100
+ * - S mode HLV/HLVX/HSV 0b101
+ * - M mode HLV/HLVX/HSV 0b111
+ */
+#define NB_MMU_MODES 8
+
+#endif
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
new file mode 100644
index 000000000..f81299812
--- /dev/null
+++ b/target/riscv/cpu.c
@@ -0,0 +1,819 @@
+/*
+ * QEMU RISC-V CPU
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/qemu-print.h"
+#include "qemu/ctype.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/exec-all.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "fpu/softfloat-helpers.h"
+
+/* RISC-V CPU definitions */
+
+static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
+
+const char * const riscv_int_regnames[] = {
+ "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
+ "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
+ "x14/a4", "x15/a5", "x16/a6", "x17/a7", "x18/s2", "x19/s3", "x20/s4",
+ "x21/s5", "x22/s6", "x23/s7", "x24/s8", "x25/s9", "x26/s10", "x27/s11",
+ "x28/t3", "x29/t4", "x30/t5", "x31/t6"
+};
+
+const char * const riscv_fpr_regnames[] = {
+ "f0/ft0", "f1/ft1", "f2/ft2", "f3/ft3", "f4/ft4", "f5/ft5",
+ "f6/ft6", "f7/ft7", "f8/fs0", "f9/fs1", "f10/fa0", "f11/fa1",
+ "f12/fa2", "f13/fa3", "f14/fa4", "f15/fa5", "f16/fa6", "f17/fa7",
+ "f18/fs2", "f19/fs3", "f20/fs4", "f21/fs5", "f22/fs6", "f23/fs7",
+ "f24/fs8", "f25/fs9", "f26/fs10", "f27/fs11", "f28/ft8", "f29/ft9",
+ "f30/ft10", "f31/ft11"
+};
+
+static const char * const riscv_excp_names[] = {
+ "misaligned_fetch",
+ "fault_fetch",
+ "illegal_instruction",
+ "breakpoint",
+ "misaligned_load",
+ "fault_load",
+ "misaligned_store",
+ "fault_store",
+ "user_ecall",
+ "supervisor_ecall",
+ "hypervisor_ecall",
+ "machine_ecall",
+ "exec_page_fault",
+ "load_page_fault",
+ "reserved",
+ "store_page_fault",
+ "reserved",
+ "reserved",
+ "reserved",
+ "reserved",
+ "guest_exec_page_fault",
+ "guest_load_page_fault",
+ "reserved",
+ "guest_store_page_fault",
+};
+
+static const char * const riscv_intr_names[] = {
+ "u_software",
+ "s_software",
+ "vs_software",
+ "m_software",
+ "u_timer",
+ "s_timer",
+ "vs_timer",
+ "m_timer",
+ "u_external",
+ "s_external",
+ "vs_external",
+ "m_external",
+ "reserved",
+ "reserved",
+ "reserved",
+ "reserved"
+};
+
+const char *riscv_cpu_get_trap_name(target_ulong cause, bool async)
+{
+ if (async) {
+ return (cause < ARRAY_SIZE(riscv_intr_names)) ?
+ riscv_intr_names[cause] : "(unknown)";
+ } else {
+ return (cause < ARRAY_SIZE(riscv_excp_names)) ?
+ riscv_excp_names[cause] : "(unknown)";
+ }
+}
+
+static void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext)
+{
+ env->misa_mxl_max = env->misa_mxl = mxl;
+ env->misa_ext_mask = env->misa_ext = ext;
+}
+
+static void set_priv_version(CPURISCVState *env, int priv_ver)
+{
+ env->priv_ver = priv_ver;
+}
+
+static void set_vext_version(CPURISCVState *env, int vext_ver)
+{
+ env->vext_ver = vext_ver;
+}
+
+static void set_feature(CPURISCVState *env, int feature)
+{
+ env->features |= (1ULL << feature);
+}
+
+static void set_resetvec(CPURISCVState *env, target_ulong resetvec)
+{
+#ifndef CONFIG_USER_ONLY
+ env->resetvec = resetvec;
+#endif
+}
+
+static void riscv_any_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+#if defined(TARGET_RISCV32)
+ set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+#elif defined(TARGET_RISCV64)
+ set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+#endif
+ set_priv_version(env, PRIV_VERSION_1_11_0);
+}
+
+#if defined(TARGET_RISCV64)
+static void rv64_base_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ /* We set this in the realise function */
+ set_misa(env, MXL_RV64, 0);
+}
+
+static void rv64_sifive_u_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
+}
+
+static void rv64_sifive_e_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+}
+#else
+static void rv32_base_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ /* We set this in the realise function */
+ set_misa(env, MXL_RV32, 0);
+}
+
+static void rv32_sifive_u_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
+}
+
+static void rv32_sifive_e_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+}
+
+static void rv32_ibex_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+ qdev_prop_set_bit(DEVICE(obj), "x-epmp", true);
+}
+
+static void rv32_imafcu_nommu_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
+ set_priv_version(env, PRIV_VERSION_1_10_0);
+ set_resetvec(env, DEFAULT_RSTVEC);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+}
+#endif
+
+static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+ char **cpuname;
+
+ cpuname = g_strsplit(cpu_model, ",", 1);
+ typename = g_strdup_printf(RISCV_CPU_TYPE_NAME("%s"), cpuname[0]);
+ oc = object_class_by_name(typename);
+ g_strfreev(cpuname);
+ g_free(typename);
+ if (!oc || !object_class_dynamic_cast(oc, TYPE_RISCV_CPU) ||
+ object_class_is_abstract(oc)) {
+ return NULL;
+ }
+ return oc;
+}
+
+static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ int i;
+
+#if !defined(CONFIG_USER_ONLY)
+ if (riscv_has_ext(env, RVH)) {
+ qemu_fprintf(f, " %s %d\n", "V = ", riscv_cpu_virt_enabled(env));
+ }
+#endif
+ qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc);
+#ifndef CONFIG_USER_ONLY
+ {
+ static const int dump_csrs[] = {
+ CSR_MHARTID,
+ CSR_MSTATUS,
+ CSR_MSTATUSH,
+ CSR_HSTATUS,
+ CSR_VSSTATUS,
+ CSR_MIP,
+ CSR_MIE,
+ CSR_MIDELEG,
+ CSR_HIDELEG,
+ CSR_MEDELEG,
+ CSR_HEDELEG,
+ CSR_MTVEC,
+ CSR_STVEC,
+ CSR_VSTVEC,
+ CSR_MEPC,
+ CSR_SEPC,
+ CSR_VSEPC,
+ CSR_MCAUSE,
+ CSR_SCAUSE,
+ CSR_VSCAUSE,
+ CSR_MTVAL,
+ CSR_STVAL,
+ CSR_HTVAL,
+ CSR_MTVAL2,
+ CSR_MSCRATCH,
+ CSR_SSCRATCH,
+ CSR_SATP,
+ CSR_MMTE,
+ CSR_UPMBASE,
+ CSR_UPMMASK,
+ CSR_SPMBASE,
+ CSR_SPMMASK,
+ CSR_MPMBASE,
+ CSR_MPMMASK,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(dump_csrs); ++i) {
+ int csrno = dump_csrs[i];
+ target_ulong val = 0;
+ RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0);
+
+ /*
+ * Rely on the smode, hmode, etc, predicates within csr.c
+ * to do the filtering of the registers that are present.
+ */
+ if (res == RISCV_EXCP_NONE) {
+ qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n",
+ csr_ops[csrno].name, val);
+ }
+ }
+ }
+#endif
+
+ for (i = 0; i < 32; i++) {
+ qemu_fprintf(f, " %-8s " TARGET_FMT_lx,
+ riscv_int_regnames[i], env->gpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+ if (flags & CPU_DUMP_FPU) {
+ for (i = 0; i < 32; i++) {
+ qemu_fprintf(f, " %-8s %016" PRIx64,
+ riscv_fpr_regnames[i], env->fpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+ }
+}
+
+static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ env->pc = value;
+}
+
+static void riscv_cpu_synchronize_from_tb(CPUState *cs,
+ const TranslationBlock *tb)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ env->pc = tb->pc;
+}
+
+static bool riscv_cpu_has_work(CPUState *cs)
+{
+#ifndef CONFIG_USER_ONLY
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ /*
+ * Definition of the WFI instruction requires it to ignore the privilege
+ * mode and delegation registers, but respect individual enables
+ */
+ return (env->mip & env->mie) != 0;
+#else
+ return true;
+#endif
+}
+
+void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
+ target_ulong *data)
+{
+ env->pc = data[0];
+}
+
+static void riscv_cpu_reset(DeviceState *dev)
+{
+ CPUState *cs = CPU(dev);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
+ CPURISCVState *env = &cpu->env;
+
+ mcc->parent_reset(dev);
+#ifndef CONFIG_USER_ONLY
+ env->misa_mxl = env->misa_mxl_max;
+ env->priv = PRV_M;
+ env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
+ if (env->misa_mxl > MXL_RV32) {
+ /*
+ * The reset status of SXL/UXL is undefined, but mstatus is WARL
+ * and we must ensure that the value after init is valid for read.
+ */
+ env->mstatus = set_field(env->mstatus, MSTATUS64_SXL, env->misa_mxl);
+ env->mstatus = set_field(env->mstatus, MSTATUS64_UXL, env->misa_mxl);
+ }
+ env->mcause = 0;
+ env->pc = env->resetvec;
+ env->two_stage_lookup = false;
+ /* mmte is supposed to have pm.current hardwired to 1 */
+ env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT);
+#endif
+ cs->exception_index = RISCV_EXCP_NONE;
+ env->load_res = -1;
+ set_default_nan_mode(1, &env->fp_status);
+}
+
+static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
+{
+ RISCVCPU *cpu = RISCV_CPU(s);
+
+ switch (riscv_cpu_mxl(&cpu->env)) {
+ case MXL_RV32:
+ info->print_insn = print_insn_riscv32;
+ break;
+ case MXL_RV64:
+ info->print_insn = print_insn_riscv64;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void riscv_cpu_realize(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ RISCVCPU *cpu = RISCV_CPU(dev);
+ CPURISCVState *env = &cpu->env;
+ RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
+ int priv_version = 0;
+ Error *local_err = NULL;
+
+ cpu_exec_realizefn(cs, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (cpu->cfg.priv_spec) {
+ if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) {
+ priv_version = PRIV_VERSION_1_11_0;
+ } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) {
+ priv_version = PRIV_VERSION_1_10_0;
+ } else {
+ error_setg(errp,
+ "Unsupported privilege spec version '%s'",
+ cpu->cfg.priv_spec);
+ return;
+ }
+ }
+
+ if (priv_version) {
+ set_priv_version(env, priv_version);
+ } else if (!env->priv_ver) {
+ set_priv_version(env, PRIV_VERSION_1_11_0);
+ }
+
+ if (cpu->cfg.mmu) {
+ set_feature(env, RISCV_FEATURE_MMU);
+ }
+
+ if (cpu->cfg.pmp) {
+ set_feature(env, RISCV_FEATURE_PMP);
+
+ /*
+ * Enhanced PMP should only be available
+ * on harts with PMP support
+ */
+ if (cpu->cfg.epmp) {
+ set_feature(env, RISCV_FEATURE_EPMP);
+ }
+ }
+
+ set_resetvec(env, cpu->cfg.resetvec);
+
+ /* Validate that MISA_MXL is set properly. */
+ switch (env->misa_mxl_max) {
+#ifdef TARGET_RISCV64
+ case MXL_RV64:
+ break;
+#endif
+ case MXL_RV32:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ assert(env->misa_mxl_max == env->misa_mxl);
+
+ /* If only MISA_EXT is unset for misa, then set it from properties */
+ if (env->misa_ext == 0) {
+ uint32_t ext = 0;
+
+ /* Do some ISA extension error checking */
+ if (cpu->cfg.ext_i && cpu->cfg.ext_e) {
+ error_setg(errp,
+ "I and E extensions are incompatible");
+ return;
+ }
+
+ if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) {
+ error_setg(errp,
+ "Either I or E extension must be set");
+ return;
+ }
+
+ if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m &
+ cpu->cfg.ext_a & cpu->cfg.ext_f &
+ cpu->cfg.ext_d)) {
+ warn_report("Setting G will also set IMAFD");
+ cpu->cfg.ext_i = true;
+ cpu->cfg.ext_m = true;
+ cpu->cfg.ext_a = true;
+ cpu->cfg.ext_f = true;
+ cpu->cfg.ext_d = true;
+ }
+
+ /* Set the ISA extensions, checks should have happened above */
+ if (cpu->cfg.ext_i) {
+ ext |= RVI;
+ }
+ if (cpu->cfg.ext_e) {
+ ext |= RVE;
+ }
+ if (cpu->cfg.ext_m) {
+ ext |= RVM;
+ }
+ if (cpu->cfg.ext_a) {
+ ext |= RVA;
+ }
+ if (cpu->cfg.ext_f) {
+ ext |= RVF;
+ }
+ if (cpu->cfg.ext_d) {
+ ext |= RVD;
+ }
+ if (cpu->cfg.ext_c) {
+ ext |= RVC;
+ }
+ if (cpu->cfg.ext_s) {
+ ext |= RVS;
+ }
+ if (cpu->cfg.ext_u) {
+ ext |= RVU;
+ }
+ if (cpu->cfg.ext_h) {
+ ext |= RVH;
+ }
+ if (cpu->cfg.ext_v) {
+ int vext_version = VEXT_VERSION_0_07_1;
+ ext |= RVV;
+ if (!is_power_of_2(cpu->cfg.vlen)) {
+ error_setg(errp,
+ "Vector extension VLEN must be power of 2");
+ return;
+ }
+ if (cpu->cfg.vlen > RV_VLEN_MAX || cpu->cfg.vlen < 128) {
+ error_setg(errp,
+ "Vector extension implementation only supports VLEN "
+ "in the range [128, %d]", RV_VLEN_MAX);
+ return;
+ }
+ if (!is_power_of_2(cpu->cfg.elen)) {
+ error_setg(errp,
+ "Vector extension ELEN must be power of 2");
+ return;
+ }
+ if (cpu->cfg.elen > 64 || cpu->cfg.vlen < 8) {
+ error_setg(errp,
+ "Vector extension implementation only supports ELEN "
+ "in the range [8, 64]");
+ return;
+ }
+ if (cpu->cfg.vext_spec) {
+ if (!g_strcmp0(cpu->cfg.vext_spec, "v0.7.1")) {
+ vext_version = VEXT_VERSION_0_07_1;
+ } else {
+ error_setg(errp,
+ "Unsupported vector spec version '%s'",
+ cpu->cfg.vext_spec);
+ return;
+ }
+ } else {
+ qemu_log("vector version is not specified, "
+ "use the default value v0.7.1\n");
+ }
+ set_vext_version(env, vext_version);
+ }
+ if (cpu->cfg.ext_j) {
+ ext |= RVJ;
+ }
+
+ set_misa(env, env->misa_mxl, ext);
+ }
+
+ riscv_cpu_register_gdb_regs_for_features(cs);
+
+ qemu_init_vcpu(cs);
+ cpu_reset(cs);
+
+ mcc->parent_realize(dev, errp);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void riscv_cpu_set_irq(void *opaque, int irq, int level)
+{
+ RISCVCPU *cpu = RISCV_CPU(opaque);
+
+ switch (irq) {
+ case IRQ_U_SOFT:
+ case IRQ_S_SOFT:
+ case IRQ_VS_SOFT:
+ case IRQ_M_SOFT:
+ case IRQ_U_TIMER:
+ case IRQ_S_TIMER:
+ case IRQ_VS_TIMER:
+ case IRQ_M_TIMER:
+ case IRQ_U_EXT:
+ case IRQ_S_EXT:
+ case IRQ_VS_EXT:
+ case IRQ_M_EXT:
+ riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+#endif /* CONFIG_USER_ONLY */
+
+static void riscv_cpu_init(Object *obj)
+{
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
+ cpu_set_cpustate_pointers(cpu);
+
+#ifndef CONFIG_USER_ONLY
+ qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, 12);
+#endif /* CONFIG_USER_ONLY */
+}
+
+static Property riscv_cpu_properties[] = {
+ /* Defaults for standard extensions */
+ DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true),
+ DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false),
+ DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true),
+ DEFINE_PROP_BOOL("m", RISCVCPU, cfg.ext_m, true),
+ DEFINE_PROP_BOOL("a", RISCVCPU, cfg.ext_a, true),
+ DEFINE_PROP_BOOL("f", RISCVCPU, cfg.ext_f, true),
+ DEFINE_PROP_BOOL("d", RISCVCPU, cfg.ext_d, true),
+ DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true),
+ DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true),
+ DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
+ DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
+ DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
+ DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
+ DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
+ DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+
+ DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
+
+ /* These are experimental so mark with 'x-' */
+ DEFINE_PROP_BOOL("x-zba", RISCVCPU, cfg.ext_zba, false),
+ DEFINE_PROP_BOOL("x-zbb", RISCVCPU, cfg.ext_zbb, false),
+ DEFINE_PROP_BOOL("x-zbc", RISCVCPU, cfg.ext_zbc, false),
+ DEFINE_PROP_BOOL("x-zbs", RISCVCPU, cfg.ext_zbs, false),
+ DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
+ DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
+ DEFINE_PROP_BOOL("x-v", RISCVCPU, cfg.ext_v, false),
+ DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
+ DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128),
+ DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
+ /* ePMP 0.9.3 */
+ DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
+
+ DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static gchar *riscv_gdb_arch_name(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ switch (riscv_cpu_mxl(env)) {
+ case MXL_RV32:
+ return g_strdup("riscv:rv32");
+ case MXL_RV64:
+ return g_strdup("riscv:rv64");
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+
+ if (strcmp(xmlname, "riscv-csr.xml") == 0) {
+ return cpu->dyn_csr_xml;
+ }
+
+ return NULL;
+}
+
+#ifndef CONFIG_USER_ONLY
+#include "hw/core/sysemu-cpu-ops.h"
+
+static const struct SysemuCPUOps riscv_sysemu_ops = {
+ .get_phys_page_debug = riscv_cpu_get_phys_page_debug,
+ .write_elf64_note = riscv_cpu_write_elf64_note,
+ .write_elf32_note = riscv_cpu_write_elf32_note,
+ .legacy_vmsd = &vmstate_riscv_cpu,
+};
+#endif
+
+#include "hw/core/tcg-cpu-ops.h"
+
+static const struct TCGCPUOps riscv_tcg_ops = {
+ .initialize = riscv_translate_init,
+ .synchronize_from_tb = riscv_cpu_synchronize_from_tb,
+
+#ifndef CONFIG_USER_ONLY
+ .tlb_fill = riscv_cpu_tlb_fill,
+ .cpu_exec_interrupt = riscv_cpu_exec_interrupt,
+ .do_interrupt = riscv_cpu_do_interrupt,
+ .do_transaction_failed = riscv_cpu_do_transaction_failed,
+ .do_unaligned_access = riscv_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
+static void riscv_cpu_class_init(ObjectClass *c, void *data)
+{
+ RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
+ CPUClass *cc = CPU_CLASS(c);
+ DeviceClass *dc = DEVICE_CLASS(c);
+
+ device_class_set_parent_realize(dc, riscv_cpu_realize,
+ &mcc->parent_realize);
+
+ device_class_set_parent_reset(dc, riscv_cpu_reset, &mcc->parent_reset);
+
+ cc->class_by_name = riscv_cpu_class_by_name;
+ cc->has_work = riscv_cpu_has_work;
+ cc->dump_state = riscv_cpu_dump_state;
+ cc->set_pc = riscv_cpu_set_pc;
+ cc->gdb_read_register = riscv_cpu_gdb_read_register;
+ cc->gdb_write_register = riscv_cpu_gdb_write_register;
+ cc->gdb_num_core_regs = 33;
+#if defined(TARGET_RISCV32)
+ cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
+#elif defined(TARGET_RISCV64)
+ cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
+#endif
+ cc->gdb_stop_before_watchpoint = true;
+ cc->disas_set_info = riscv_cpu_disas_set_info;
+#ifndef CONFIG_USER_ONLY
+ cc->sysemu_ops = &riscv_sysemu_ops;
+#endif
+ cc->gdb_arch_name = riscv_gdb_arch_name;
+ cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml;
+ cc->tcg_ops = &riscv_tcg_ops;
+
+ device_class_set_props(dc, riscv_cpu_properties);
+}
+
+char *riscv_isa_string(RISCVCPU *cpu)
+{
+ int i;
+ const size_t maxlen = sizeof("rv128") + sizeof(riscv_exts) + 1;
+ char *isa_str = g_new(char, maxlen);
+ char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS);
+ for (i = 0; i < sizeof(riscv_exts); i++) {
+ if (cpu->env.misa_ext & RV(riscv_exts[i])) {
+ *p++ = qemu_tolower(riscv_exts[i]);
+ }
+ }
+ *p = '\0';
+ return isa_str;
+}
+
+static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+ const char *name_a, *name_b;
+
+ name_a = object_class_get_name(class_a);
+ name_b = object_class_get_name(class_b);
+ return strcmp(name_a, name_b);
+}
+
+static void riscv_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ const char *typename = object_class_get_name(OBJECT_CLASS(data));
+ int len = strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX);
+
+ qemu_printf("%.*s\n", len, typename);
+}
+
+void riscv_cpu_list(void)
+{
+ GSList *list;
+
+ list = object_class_get_list(TYPE_RISCV_CPU, false);
+ list = g_slist_sort(list, riscv_cpu_list_compare);
+ g_slist_foreach(list, riscv_cpu_list_entry, NULL);
+ g_slist_free(list);
+}
+
+#define DEFINE_CPU(type_name, initfn) \
+ { \
+ .name = type_name, \
+ .parent = TYPE_RISCV_CPU, \
+ .instance_init = initfn \
+ }
+
+static const TypeInfo riscv_cpu_type_infos[] = {
+ {
+ .name = TYPE_RISCV_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(RISCVCPU),
+ .instance_align = __alignof__(RISCVCPU),
+ .instance_init = riscv_cpu_init,
+ .abstract = true,
+ .class_size = sizeof(RISCVCPUClass),
+ .class_init = riscv_cpu_class_init,
+ },
+ DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
+#if defined(TARGET_RISCV32)
+ DEFINE_CPU(TYPE_RISCV_CPU_BASE32, rv32_base_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init),
+#elif defined(TARGET_RISCV64)
+ DEFINE_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init),
+#endif
+};
+
+DEFINE_TYPES(riscv_cpu_type_infos)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
new file mode 100644
index 000000000..0760c0af9
--- /dev/null
+++ b/target/riscv/cpu.h
@@ -0,0 +1,495 @@
+/*
+ * QEMU RISC-V CPU
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RISCV_CPU_H
+#define RISCV_CPU_H
+
+#include "hw/core/cpu.h"
+#include "hw/registerfields.h"
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat-types.h"
+#include "qom/object.h"
+#include "cpu_bits.h"
+
+#define TCG_GUEST_DEFAULT_MO 0
+
+#define TYPE_RISCV_CPU "riscv-cpu"
+
+#define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU
+#define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX)
+#define CPU_RESOLVING_TYPE TYPE_RISCV_CPU
+
+#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
+#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
+#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
+#define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex")
+#define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c")
+#define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31")
+#define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34")
+#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51")
+#define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34")
+#define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54")
+
+#if defined(TARGET_RISCV32)
+# define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE32
+#elif defined(TARGET_RISCV64)
+# define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE64
+#endif
+
+#define RV(x) ((target_ulong)1 << (x - 'A'))
+
+#define RVI RV('I')
+#define RVE RV('E') /* E and I are mutually exclusive */
+#define RVM RV('M')
+#define RVA RV('A')
+#define RVF RV('F')
+#define RVD RV('D')
+#define RVV RV('V')
+#define RVC RV('C')
+#define RVS RV('S')
+#define RVU RV('U')
+#define RVH RV('H')
+#define RVJ RV('J')
+
+/* S extension denotes that Supervisor mode exists, however it is possible
+ to have a core that support S mode but does not have an MMU and there
+ is currently no bit in misa to indicate whether an MMU exists or not
+ so a cpu features bitfield is required, likewise for optional PMP support */
+enum {
+ RISCV_FEATURE_MMU,
+ RISCV_FEATURE_PMP,
+ RISCV_FEATURE_EPMP,
+ RISCV_FEATURE_MISA
+};
+
+#define PRIV_VERSION_1_10_0 0x00011000
+#define PRIV_VERSION_1_11_0 0x00011100
+
+#define VEXT_VERSION_0_07_1 0x00000701
+
+enum {
+ TRANSLATE_SUCCESS,
+ TRANSLATE_FAIL,
+ TRANSLATE_PMP_FAIL,
+ TRANSLATE_G_STAGE_FAIL
+};
+
+#define MMU_USER_IDX 3
+
+#define MAX_RISCV_PMPS (16)
+
+typedef struct CPURISCVState CPURISCVState;
+
+#if !defined(CONFIG_USER_ONLY)
+#include "pmp.h"
+#endif
+
+#define RV_VLEN_MAX 256
+
+FIELD(VTYPE, VLMUL, 0, 2)
+FIELD(VTYPE, VSEW, 2, 3)
+FIELD(VTYPE, VEDIV, 5, 2)
+FIELD(VTYPE, RESERVED, 7, sizeof(target_ulong) * 8 - 9)
+FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 1, 1)
+
+struct CPURISCVState {
+ target_ulong gpr[32];
+ uint64_t fpr[32]; /* assume both F and D extensions */
+
+ /* vector coprocessor state. */
+ uint64_t vreg[32 * RV_VLEN_MAX / 64] QEMU_ALIGNED(16);
+ target_ulong vxrm;
+ target_ulong vxsat;
+ target_ulong vl;
+ target_ulong vstart;
+ target_ulong vtype;
+
+ target_ulong pc;
+ target_ulong load_res;
+ target_ulong load_val;
+
+ target_ulong frm;
+
+ target_ulong badaddr;
+ target_ulong guest_phys_fault_addr;
+
+ target_ulong priv_ver;
+ target_ulong bext_ver;
+ target_ulong vext_ver;
+
+ /* RISCVMXL, but uint32_t for vmstate migration */
+ uint32_t misa_mxl; /* current mxl */
+ uint32_t misa_mxl_max; /* max mxl for this cpu */
+ uint32_t misa_ext; /* current extensions */
+ uint32_t misa_ext_mask; /* max ext for this cpu */
+
+ uint32_t features;
+
+#ifdef CONFIG_USER_ONLY
+ uint32_t elf_flags;
+#endif
+
+#ifndef CONFIG_USER_ONLY
+ target_ulong priv;
+ /* This contains QEMU specific information about the virt state. */
+ target_ulong virt;
+ target_ulong resetvec;
+
+ target_ulong mhartid;
+ /*
+ * For RV32 this is 32-bit mstatus and 32-bit mstatush.
+ * For RV64 this is a 64-bit mstatus.
+ */
+ uint64_t mstatus;
+
+ target_ulong mip;
+
+ uint32_t miclaim;
+
+ target_ulong mie;
+ target_ulong mideleg;
+
+ target_ulong satp; /* since: priv-1.10.0 */
+ target_ulong stval;
+ target_ulong medeleg;
+
+ target_ulong stvec;
+ target_ulong sepc;
+ target_ulong scause;
+
+ target_ulong mtvec;
+ target_ulong mepc;
+ target_ulong mcause;
+ target_ulong mtval; /* since: priv-1.10.0 */
+
+ /* Hypervisor CSRs */
+ target_ulong hstatus;
+ target_ulong hedeleg;
+ target_ulong hideleg;
+ target_ulong hcounteren;
+ target_ulong htval;
+ target_ulong htinst;
+ target_ulong hgatp;
+ uint64_t htimedelta;
+
+ /* Virtual CSRs */
+ /*
+ * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
+ * For RV64 this is a 64-bit vsstatus.
+ */
+ uint64_t vsstatus;
+ target_ulong vstvec;
+ target_ulong vsscratch;
+ target_ulong vsepc;
+ target_ulong vscause;
+ target_ulong vstval;
+ target_ulong vsatp;
+
+ target_ulong mtval2;
+ target_ulong mtinst;
+
+ /* HS Backup CSRs */
+ target_ulong stvec_hs;
+ target_ulong sscratch_hs;
+ target_ulong sepc_hs;
+ target_ulong scause_hs;
+ target_ulong stval_hs;
+ target_ulong satp_hs;
+ uint64_t mstatus_hs;
+
+ /* Signals whether the current exception occurred with two-stage address
+ translation active. */
+ bool two_stage_lookup;
+
+ target_ulong scounteren;
+ target_ulong mcounteren;
+
+ target_ulong sscratch;
+ target_ulong mscratch;
+
+ /* temporary htif regs */
+ uint64_t mfromhost;
+ uint64_t mtohost;
+ uint64_t timecmp;
+
+ /* physical memory protection */
+ pmp_table_t pmp_state;
+ target_ulong mseccfg;
+
+ /* machine specific rdtime callback */
+ uint64_t (*rdtime_fn)(uint32_t);
+ uint32_t rdtime_fn_arg;
+
+ /* True if in debugger mode. */
+ bool debugger;
+
+ /*
+ * CSRs for PointerMasking extension
+ */
+ target_ulong mmte;
+ target_ulong mpmmask;
+ target_ulong mpmbase;
+ target_ulong spmmask;
+ target_ulong spmbase;
+ target_ulong upmmask;
+ target_ulong upmbase;
+#endif
+
+ float_status fp_status;
+
+ /* Fields from here on are preserved across CPU reset. */
+ QEMUTimer *timer; /* Internal timer */
+};
+
+OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass,
+ RISCV_CPU)
+
+/**
+ * RISCVCPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A RISCV CPU model.
+ */
+struct RISCVCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+ DeviceRealize parent_realize;
+ DeviceReset parent_reset;
+};
+
+/**
+ * RISCVCPU:
+ * @env: #CPURISCVState
+ *
+ * A RISCV CPU.
+ */
+struct RISCVCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+ CPUNegativeOffsetState neg;
+ CPURISCVState env;
+
+ char *dyn_csr_xml;
+
+ /* Configuration Settings */
+ struct {
+ bool ext_i;
+ bool ext_e;
+ bool ext_g;
+ bool ext_m;
+ bool ext_a;
+ bool ext_f;
+ bool ext_d;
+ bool ext_c;
+ bool ext_s;
+ bool ext_u;
+ bool ext_h;
+ bool ext_j;
+ bool ext_v;
+ bool ext_zba;
+ bool ext_zbb;
+ bool ext_zbc;
+ bool ext_zbs;
+ bool ext_counters;
+ bool ext_ifencei;
+ bool ext_icsr;
+
+ char *priv_spec;
+ char *user_spec;
+ char *bext_spec;
+ char *vext_spec;
+ uint16_t vlen;
+ uint16_t elen;
+ bool mmu;
+ bool pmp;
+ bool epmp;
+ uint64_t resetvec;
+ } cfg;
+};
+
+static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext)
+{
+ return (env->misa_ext & ext) != 0;
+}
+
+static inline bool riscv_feature(CPURISCVState *env, int feature)
+{
+ return env->features & (1ULL << feature);
+}
+
+#include "cpu_user.h"
+
+extern const char * const riscv_int_regnames[];
+extern const char * const riscv_fpr_regnames[];
+
+const char *riscv_cpu_get_trap_name(target_ulong cause, bool async);
+void riscv_cpu_do_interrupt(CPUState *cpu);
+int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque);
+int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque);
+int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+bool riscv_cpu_fp_enabled(CPURISCVState *env);
+bool riscv_cpu_virt_enabled(CPURISCVState *env);
+void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
+bool riscv_cpu_two_stage_lookup(int mmu_idx);
+int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+ MMUAccessType access_type, int mmu_idx,
+ uintptr_t retaddr) QEMU_NORETURN;
+bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
+char *riscv_isa_string(RISCVCPU *cpu);
+void riscv_cpu_list(void);
+
+#define cpu_list riscv_cpu_list
+#define cpu_mmu_index riscv_cpu_mmu_index
+
+#ifndef CONFIG_USER_ONLY
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
+void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
+uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
+#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
+void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
+ uint32_t arg);
+#endif
+void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
+
+void riscv_translate_init(void);
+void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
+ uint32_t exception, uintptr_t pc);
+
+target_ulong riscv_cpu_get_fflags(CPURISCVState *env);
+void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong);
+
+#define TB_FLAGS_PRIV_MMU_MASK 3
+#define TB_FLAGS_PRIV_HYP_ACCESS_MASK (1 << 2)
+#define TB_FLAGS_MSTATUS_FS MSTATUS_FS
+
+typedef CPURISCVState CPUArchState;
+typedef RISCVCPU ArchCPU;
+#include "exec/cpu-all.h"
+
+FIELD(TB_FLAGS, MEM_IDX, 0, 3)
+FIELD(TB_FLAGS, VL_EQ_VLMAX, 3, 1)
+FIELD(TB_FLAGS, LMUL, 4, 2)
+FIELD(TB_FLAGS, SEW, 6, 3)
+FIELD(TB_FLAGS, VILL, 9, 1)
+/* Is a Hypervisor instruction load/store allowed? */
+FIELD(TB_FLAGS, HLSX, 10, 1)
+FIELD(TB_FLAGS, MSTATUS_HS_FS, 11, 2)
+/* The combination of MXL/SXL/UXL that applies to the current cpu mode. */
+FIELD(TB_FLAGS, XL, 13, 2)
+/* If PointerMasking should be applied */
+FIELD(TB_FLAGS, PM_ENABLED, 15, 1)
+
+#ifdef TARGET_RISCV32
+#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
+#else
+static inline RISCVMXL riscv_cpu_mxl(CPURISCVState *env)
+{
+ return env->misa_mxl;
+}
+#endif
+
+/*
+ * A simplification for VLMAX
+ * = (1 << LMUL) * VLEN / (8 * (1 << SEW))
+ * = (VLEN << LMUL) / (8 << SEW)
+ * = (VLEN << LMUL) >> (SEW + 3)
+ * = VLEN >> (SEW + 3 - LMUL)
+ */
+static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype)
+{
+ uint8_t sew, lmul;
+
+ sew = FIELD_EX64(vtype, VTYPE, VSEW);
+ lmul = FIELD_EX64(vtype, VTYPE, VLMUL);
+ return cpu->cfg.vlen >> (sew + 3 - lmul);
+}
+
+void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
+ target_ulong *cs_base, uint32_t *pflags);
+
+RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask);
+RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask);
+
+static inline void riscv_csr_write(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS));
+}
+
+static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
+{
+ target_ulong val = 0;
+ riscv_csrrw(env, csrno, &val, 0, 0);
+ return val;
+}
+
+typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env,
+ int csrno);
+typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
+ target_ulong *ret_value);
+typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno,
+ target_ulong new_value);
+typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask);
+
+typedef struct {
+ const char *name;
+ riscv_csr_predicate_fn predicate;
+ riscv_csr_read_fn read;
+ riscv_csr_write_fn write;
+ riscv_csr_op_fn op;
+} riscv_csr_operations;
+
+/* CSR function table constants */
+enum {
+ CSR_TABLE_SIZE = 0x1000
+};
+
+/* CSR function table */
+extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
+
+void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
+void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
+
+void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
+
+#endif /* RISCV_CPU_H */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
new file mode 100644
index 000000000..9913fa9f7
--- /dev/null
+++ b/target/riscv/cpu_bits.h
@@ -0,0 +1,618 @@
+/* RISC-V ISA constants */
+
+#ifndef TARGET_RISCV_CPU_BITS_H
+#define TARGET_RISCV_CPU_BITS_H
+
+#define get_field(reg, mask) (((reg) & \
+ (uint64_t)(mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(uint64_t)(mask)) | \
+ (((uint64_t)(val) * ((mask) & ~((mask) << 1))) & \
+ (uint64_t)(mask)))
+
+/* Floating point round mode */
+#define FSR_RD_SHIFT 5
+#define FSR_RD (0x7 << FSR_RD_SHIFT)
+
+/* Floating point accrued exception flags */
+#define FPEXC_NX 0x01
+#define FPEXC_UF 0x02
+#define FPEXC_OF 0x04
+#define FPEXC_DZ 0x08
+#define FPEXC_NV 0x10
+
+/* Floating point status register bits */
+#define FSR_AEXC_SHIFT 0
+#define FSR_NVA (FPEXC_NV << FSR_AEXC_SHIFT)
+#define FSR_OFA (FPEXC_OF << FSR_AEXC_SHIFT)
+#define FSR_UFA (FPEXC_UF << FSR_AEXC_SHIFT)
+#define FSR_DZA (FPEXC_DZ << FSR_AEXC_SHIFT)
+#define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT)
+#define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
+
+/* Vector Fixed-Point round model */
+#define FSR_VXRM_SHIFT 9
+#define FSR_VXRM (0x3 << FSR_VXRM_SHIFT)
+
+/* Vector Fixed-Point saturation flag */
+#define FSR_VXSAT_SHIFT 8
+#define FSR_VXSAT (0x1 << FSR_VXSAT_SHIFT)
+
+/* Control and Status Registers */
+
+/* User Trap Setup */
+#define CSR_USTATUS 0x000
+#define CSR_UIE 0x004
+#define CSR_UTVEC 0x005
+
+/* User Trap Handling */
+#define CSR_USCRATCH 0x040
+#define CSR_UEPC 0x041
+#define CSR_UCAUSE 0x042
+#define CSR_UTVAL 0x043
+#define CSR_UIP 0x044
+
+/* User Floating-Point CSRs */
+#define CSR_FFLAGS 0x001
+#define CSR_FRM 0x002
+#define CSR_FCSR 0x003
+
+/* User Vector CSRs */
+#define CSR_VSTART 0x008
+#define CSR_VXSAT 0x009
+#define CSR_VXRM 0x00a
+#define CSR_VL 0xc20
+#define CSR_VTYPE 0xc21
+
+/* User Timers and Counters */
+#define CSR_CYCLE 0xc00
+#define CSR_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_HPMCOUNTER3 0xc03
+#define CSR_HPMCOUNTER4 0xc04
+#define CSR_HPMCOUNTER5 0xc05
+#define CSR_HPMCOUNTER6 0xc06
+#define CSR_HPMCOUNTER7 0xc07
+#define CSR_HPMCOUNTER8 0xc08
+#define CSR_HPMCOUNTER9 0xc09
+#define CSR_HPMCOUNTER10 0xc0a
+#define CSR_HPMCOUNTER11 0xc0b
+#define CSR_HPMCOUNTER12 0xc0c
+#define CSR_HPMCOUNTER13 0xc0d
+#define CSR_HPMCOUNTER14 0xc0e
+#define CSR_HPMCOUNTER15 0xc0f
+#define CSR_HPMCOUNTER16 0xc10
+#define CSR_HPMCOUNTER17 0xc11
+#define CSR_HPMCOUNTER18 0xc12
+#define CSR_HPMCOUNTER19 0xc13
+#define CSR_HPMCOUNTER20 0xc14
+#define CSR_HPMCOUNTER21 0xc15
+#define CSR_HPMCOUNTER22 0xc16
+#define CSR_HPMCOUNTER23 0xc17
+#define CSR_HPMCOUNTER24 0xc18
+#define CSR_HPMCOUNTER25 0xc19
+#define CSR_HPMCOUNTER26 0xc1a
+#define CSR_HPMCOUNTER27 0xc1b
+#define CSR_HPMCOUNTER28 0xc1c
+#define CSR_HPMCOUNTER29 0xc1d
+#define CSR_HPMCOUNTER30 0xc1e
+#define CSR_HPMCOUNTER31 0xc1f
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CSR_HPMCOUNTER3H 0xc83
+#define CSR_HPMCOUNTER4H 0xc84
+#define CSR_HPMCOUNTER5H 0xc85
+#define CSR_HPMCOUNTER6H 0xc86
+#define CSR_HPMCOUNTER7H 0xc87
+#define CSR_HPMCOUNTER8H 0xc88
+#define CSR_HPMCOUNTER9H 0xc89
+#define CSR_HPMCOUNTER10H 0xc8a
+#define CSR_HPMCOUNTER11H 0xc8b
+#define CSR_HPMCOUNTER12H 0xc8c
+#define CSR_HPMCOUNTER13H 0xc8d
+#define CSR_HPMCOUNTER14H 0xc8e
+#define CSR_HPMCOUNTER15H 0xc8f
+#define CSR_HPMCOUNTER16H 0xc90
+#define CSR_HPMCOUNTER17H 0xc91
+#define CSR_HPMCOUNTER18H 0xc92
+#define CSR_HPMCOUNTER19H 0xc93
+#define CSR_HPMCOUNTER20H 0xc94
+#define CSR_HPMCOUNTER21H 0xc95
+#define CSR_HPMCOUNTER22H 0xc96
+#define CSR_HPMCOUNTER23H 0xc97
+#define CSR_HPMCOUNTER24H 0xc98
+#define CSR_HPMCOUNTER25H 0xc99
+#define CSR_HPMCOUNTER26H 0xc9a
+#define CSR_HPMCOUNTER27H 0xc9b
+#define CSR_HPMCOUNTER28H 0xc9c
+#define CSR_HPMCOUNTER29H 0xc9d
+#define CSR_HPMCOUNTER30H 0xc9e
+#define CSR_HPMCOUNTER31H 0xc9f
+
+/* Machine Timers and Counters */
+#define CSR_MCYCLE 0xb00
+#define CSR_MINSTRET 0xb02
+#define CSR_MCYCLEH 0xb80
+#define CSR_MINSTRETH 0xb82
+
+/* Machine Information Registers */
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+
+/* Machine Trap Setup */
+#define CSR_MSTATUS 0x300
+#define CSR_MISA 0x301
+#define CSR_MEDELEG 0x302
+#define CSR_MIDELEG 0x303
+#define CSR_MIE 0x304
+#define CSR_MTVEC 0x305
+#define CSR_MCOUNTEREN 0x306
+
+/* 32-bit only */
+#define CSR_MSTATUSH 0x310
+
+/* Machine Trap Handling */
+#define CSR_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MTVAL 0x343
+#define CSR_MIP 0x344
+
+/* Supervisor Trap Setup */
+#define CSR_SSTATUS 0x100
+#define CSR_SEDELEG 0x102
+#define CSR_SIDELEG 0x103
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SCOUNTEREN 0x106
+
+/* Supervisor Trap Handling */
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_STVAL 0x143
+#define CSR_SIP 0x144
+
+/* Supervisor Protection and Translation */
+#define CSR_SPTBR 0x180
+#define CSR_SATP 0x180
+
+/* Hpervisor CSRs */
+#define CSR_HSTATUS 0x600
+#define CSR_HEDELEG 0x602
+#define CSR_HIDELEG 0x603
+#define CSR_HIE 0x604
+#define CSR_HCOUNTEREN 0x606
+#define CSR_HGEIE 0x607
+#define CSR_HTVAL 0x643
+#define CSR_HVIP 0x645
+#define CSR_HIP 0x644
+#define CSR_HTINST 0x64A
+#define CSR_HGEIP 0xE12
+#define CSR_HGATP 0x680
+#define CSR_HTIMEDELTA 0x605
+#define CSR_HTIMEDELTAH 0x615
+
+/* Virtual CSRs */
+#define CSR_VSSTATUS 0x200
+#define CSR_VSIE 0x204
+#define CSR_VSTVEC 0x205
+#define CSR_VSSCRATCH 0x240
+#define CSR_VSEPC 0x241
+#define CSR_VSCAUSE 0x242
+#define CSR_VSTVAL 0x243
+#define CSR_VSIP 0x244
+#define CSR_VSATP 0x280
+
+#define CSR_MTINST 0x34a
+#define CSR_MTVAL2 0x34b
+
+/* Enhanced Physical Memory Protection (ePMP) */
+#define CSR_MSECCFG 0x747
+#define CSR_MSECCFGH 0x757
+/* Physical Memory Protection */
+#define CSR_PMPCFG0 0x3a0
+#define CSR_PMPCFG1 0x3a1
+#define CSR_PMPCFG2 0x3a2
+#define CSR_PMPCFG3 0x3a3
+#define CSR_PMPADDR0 0x3b0
+#define CSR_PMPADDR1 0x3b1
+#define CSR_PMPADDR2 0x3b2
+#define CSR_PMPADDR3 0x3b3
+#define CSR_PMPADDR4 0x3b4
+#define CSR_PMPADDR5 0x3b5
+#define CSR_PMPADDR6 0x3b6
+#define CSR_PMPADDR7 0x3b7
+#define CSR_PMPADDR8 0x3b8
+#define CSR_PMPADDR9 0x3b9
+#define CSR_PMPADDR10 0x3ba
+#define CSR_PMPADDR11 0x3bb
+#define CSR_PMPADDR12 0x3bc
+#define CSR_PMPADDR13 0x3bd
+#define CSR_PMPADDR14 0x3be
+#define CSR_PMPADDR15 0x3bf
+
+/* Debug/Trace Registers (shared with Debug Mode) */
+#define CSR_TSELECT 0x7a0
+#define CSR_TDATA1 0x7a1
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA3 0x7a3
+
+/* Debug Mode Registers */
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+
+/* Performance Counters */
+#define CSR_MHPMCOUNTER3 0xb03
+#define CSR_MHPMCOUNTER4 0xb04
+#define CSR_MHPMCOUNTER5 0xb05
+#define CSR_MHPMCOUNTER6 0xb06
+#define CSR_MHPMCOUNTER7 0xb07
+#define CSR_MHPMCOUNTER8 0xb08
+#define CSR_MHPMCOUNTER9 0xb09
+#define CSR_MHPMCOUNTER10 0xb0a
+#define CSR_MHPMCOUNTER11 0xb0b
+#define CSR_MHPMCOUNTER12 0xb0c
+#define CSR_MHPMCOUNTER13 0xb0d
+#define CSR_MHPMCOUNTER14 0xb0e
+#define CSR_MHPMCOUNTER15 0xb0f
+#define CSR_MHPMCOUNTER16 0xb10
+#define CSR_MHPMCOUNTER17 0xb11
+#define CSR_MHPMCOUNTER18 0xb12
+#define CSR_MHPMCOUNTER19 0xb13
+#define CSR_MHPMCOUNTER20 0xb14
+#define CSR_MHPMCOUNTER21 0xb15
+#define CSR_MHPMCOUNTER22 0xb16
+#define CSR_MHPMCOUNTER23 0xb17
+#define CSR_MHPMCOUNTER24 0xb18
+#define CSR_MHPMCOUNTER25 0xb19
+#define CSR_MHPMCOUNTER26 0xb1a
+#define CSR_MHPMCOUNTER27 0xb1b
+#define CSR_MHPMCOUNTER28 0xb1c
+#define CSR_MHPMCOUNTER29 0xb1d
+#define CSR_MHPMCOUNTER30 0xb1e
+#define CSR_MHPMCOUNTER31 0xb1f
+#define CSR_MHPMEVENT3 0x323
+#define CSR_MHPMEVENT4 0x324
+#define CSR_MHPMEVENT5 0x325
+#define CSR_MHPMEVENT6 0x326
+#define CSR_MHPMEVENT7 0x327
+#define CSR_MHPMEVENT8 0x328
+#define CSR_MHPMEVENT9 0x329
+#define CSR_MHPMEVENT10 0x32a
+#define CSR_MHPMEVENT11 0x32b
+#define CSR_MHPMEVENT12 0x32c
+#define CSR_MHPMEVENT13 0x32d
+#define CSR_MHPMEVENT14 0x32e
+#define CSR_MHPMEVENT15 0x32f
+#define CSR_MHPMEVENT16 0x330
+#define CSR_MHPMEVENT17 0x331
+#define CSR_MHPMEVENT18 0x332
+#define CSR_MHPMEVENT19 0x333
+#define CSR_MHPMEVENT20 0x334
+#define CSR_MHPMEVENT21 0x335
+#define CSR_MHPMEVENT22 0x336
+#define CSR_MHPMEVENT23 0x337
+#define CSR_MHPMEVENT24 0x338
+#define CSR_MHPMEVENT25 0x339
+#define CSR_MHPMEVENT26 0x33a
+#define CSR_MHPMEVENT27 0x33b
+#define CSR_MHPMEVENT28 0x33c
+#define CSR_MHPMEVENT29 0x33d
+#define CSR_MHPMEVENT30 0x33e
+#define CSR_MHPMEVENT31 0x33f
+#define CSR_MHPMCOUNTER3H 0xb83
+#define CSR_MHPMCOUNTER4H 0xb84
+#define CSR_MHPMCOUNTER5H 0xb85
+#define CSR_MHPMCOUNTER6H 0xb86
+#define CSR_MHPMCOUNTER7H 0xb87
+#define CSR_MHPMCOUNTER8H 0xb88
+#define CSR_MHPMCOUNTER9H 0xb89
+#define CSR_MHPMCOUNTER10H 0xb8a
+#define CSR_MHPMCOUNTER11H 0xb8b
+#define CSR_MHPMCOUNTER12H 0xb8c
+#define CSR_MHPMCOUNTER13H 0xb8d
+#define CSR_MHPMCOUNTER14H 0xb8e
+#define CSR_MHPMCOUNTER15H 0xb8f
+#define CSR_MHPMCOUNTER16H 0xb90
+#define CSR_MHPMCOUNTER17H 0xb91
+#define CSR_MHPMCOUNTER18H 0xb92
+#define CSR_MHPMCOUNTER19H 0xb93
+#define CSR_MHPMCOUNTER20H 0xb94
+#define CSR_MHPMCOUNTER21H 0xb95
+#define CSR_MHPMCOUNTER22H 0xb96
+#define CSR_MHPMCOUNTER23H 0xb97
+#define CSR_MHPMCOUNTER24H 0xb98
+#define CSR_MHPMCOUNTER25H 0xb99
+#define CSR_MHPMCOUNTER26H 0xb9a
+#define CSR_MHPMCOUNTER27H 0xb9b
+#define CSR_MHPMCOUNTER28H 0xb9c
+#define CSR_MHPMCOUNTER29H 0xb9d
+#define CSR_MHPMCOUNTER30H 0xb9e
+#define CSR_MHPMCOUNTER31H 0xb9f
+
+/*
+ * User PointerMasking registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_UMTE 0x4c0
+#define CSR_UPMMASK 0x4c1
+#define CSR_UPMBASE 0x4c2
+
+/*
+ * Machine PointerMasking registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_MMTE 0x3c0
+#define CSR_MPMMASK 0x3c1
+#define CSR_MPMBASE 0x3c2
+
+/*
+ * Supervisor PointerMaster registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_SMTE 0x1c0
+#define CSR_SPMMASK 0x1c1
+#define CSR_SPMBASE 0x1c2
+
+/*
+ * Hypervisor PointerMaster registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_VSMTE 0x2c0
+#define CSR_VSPMMASK 0x2c1
+#define CSR_VSPMBASE 0x2c2
+
+/* mstatus CSR bits */
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_UBE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_SUM 0x00040000 /* since: priv-1.10 */
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */
+#define MSTATUS_TW 0x00200000 /* since: priv-1.10 */
+#define MSTATUS_TSR 0x00400000 /* since: priv-1.10 */
+#define MSTATUS_GVA 0x4000000000ULL
+#define MSTATUS_MPV 0x8000000000ULL
+
+#define MSTATUS64_UXL 0x0000000300000000ULL
+#define MSTATUS64_SXL 0x0000000C00000000ULL
+
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_SD 0x8000000000000000ULL
+
+#define MISA32_MXL 0xC0000000
+#define MISA64_MXL 0xC000000000000000ULL
+
+typedef enum {
+ MXL_RV32 = 1,
+ MXL_RV64 = 2,
+ MXL_RV128 = 3,
+} RISCVMXL;
+
+/* sstatus CSR bits */
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */
+#define SSTATUS_MXR 0x00080000
+
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000ULL
+
+/* hstatus CSR bits */
+#define HSTATUS_VSBE 0x00000020
+#define HSTATUS_GVA 0x00000040
+#define HSTATUS_SPV 0x00000080
+#define HSTATUS_SPVP 0x00000100
+#define HSTATUS_HU 0x00000200
+#define HSTATUS_VGEIN 0x0003F000
+#define HSTATUS_VTVM 0x00100000
+#define HSTATUS_VTW 0x00200000
+#define HSTATUS_VTSR 0x00400000
+#define HSTATUS_VSXL 0x300000000
+
+#define HSTATUS32_WPRI 0xFF8FF87E
+#define HSTATUS64_WPRI 0xFFFFFFFFFF8FF87EULL
+
+#define COUNTEREN_CY (1 << 0)
+#define COUNTEREN_TM (1 << 1)
+#define COUNTEREN_IR (1 << 2)
+#define COUNTEREN_HPM3 (1 << 3)
+
+/* Privilege modes */
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2 /* Reserved */
+#define PRV_M 3
+
+/* Virtulisation Register Fields */
+#define VIRT_ONOFF 1
+
+/* RV32 satp CSR field masks */
+#define SATP32_MODE 0x80000000
+#define SATP32_ASID 0x7fc00000
+#define SATP32_PPN 0x003fffff
+
+/* RV64 satp CSR field masks */
+#define SATP64_MODE 0xF000000000000000ULL
+#define SATP64_ASID 0x0FFFF00000000000ULL
+#define SATP64_PPN 0x00000FFFFFFFFFFFULL
+
+/* VM modes (satp.mode) privileged ISA 1.10 */
+#define VM_1_10_MBARE 0
+#define VM_1_10_SV32 1
+#define VM_1_10_SV39 8
+#define VM_1_10_SV48 9
+#define VM_1_10_SV57 10
+#define VM_1_10_SV64 11
+
+/* Page table entry (PTE) fields */
+#define PTE_V 0x001 /* Valid */
+#define PTE_R 0x002 /* Read */
+#define PTE_W 0x004 /* Write */
+#define PTE_X 0x008 /* Execute */
+#define PTE_U 0x010 /* User */
+#define PTE_G 0x020 /* Global */
+#define PTE_A 0x040 /* Accessed */
+#define PTE_D 0x080 /* Dirty */
+#define PTE_SOFT 0x300 /* Reserved for Software */
+
+/* Page table PPN shift amount */
+#define PTE_PPN_SHIFT 10
+
+/* Leaf page shift amount */
+#define PGSHIFT 12
+
+/* Default Reset Vector adress */
+#define DEFAULT_RSTVEC 0x1000
+
+/* Exception causes */
+typedef enum RISCVException {
+ RISCV_EXCP_NONE = -1, /* sentinel value */
+ RISCV_EXCP_INST_ADDR_MIS = 0x0,
+ RISCV_EXCP_INST_ACCESS_FAULT = 0x1,
+ RISCV_EXCP_ILLEGAL_INST = 0x2,
+ RISCV_EXCP_BREAKPOINT = 0x3,
+ RISCV_EXCP_LOAD_ADDR_MIS = 0x4,
+ RISCV_EXCP_LOAD_ACCESS_FAULT = 0x5,
+ RISCV_EXCP_STORE_AMO_ADDR_MIS = 0x6,
+ RISCV_EXCP_STORE_AMO_ACCESS_FAULT = 0x7,
+ RISCV_EXCP_U_ECALL = 0x8,
+ RISCV_EXCP_S_ECALL = 0x9,
+ RISCV_EXCP_VS_ECALL = 0xa,
+ RISCV_EXCP_M_ECALL = 0xb,
+ RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */
+ RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */
+ RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */
+ RISCV_EXCP_SEMIHOST = 0x10,
+ RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14,
+ RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15,
+ RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16,
+ RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT = 0x17,
+} RISCVException;
+
+#define RISCV_EXCP_INT_FLAG 0x80000000
+#define RISCV_EXCP_INT_MASK 0x7fffffff
+
+/* Interrupt causes */
+#define IRQ_U_SOFT 0
+#define IRQ_S_SOFT 1
+#define IRQ_VS_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_U_TIMER 4
+#define IRQ_S_TIMER 5
+#define IRQ_VS_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_U_EXT 8
+#define IRQ_S_EXT 9
+#define IRQ_VS_EXT 10
+#define IRQ_M_EXT 11
+
+/* mip masks */
+#define MIP_USIP (1 << IRQ_U_SOFT)
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_VSSIP (1 << IRQ_VS_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_UTIP (1 << IRQ_U_TIMER)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_VSTIP (1 << IRQ_VS_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_UEIP (1 << IRQ_U_EXT)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_VSEIP (1 << IRQ_VS_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+/* sip masks */
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+#define SIP_SEIP MIP_SEIP
+
+/* MIE masks */
+#define MIE_SEIE (1 << IRQ_S_EXT)
+#define MIE_UEIE (1 << IRQ_U_EXT)
+#define MIE_STIE (1 << IRQ_S_TIMER)
+#define MIE_UTIE (1 << IRQ_U_TIMER)
+#define MIE_SSIE (1 << IRQ_S_SOFT)
+#define MIE_USIE (1 << IRQ_U_SOFT)
+
+/* General PointerMasking CSR bits*/
+#define PM_ENABLE 0x00000001ULL
+#define PM_CURRENT 0x00000002ULL
+#define PM_INSN 0x00000004ULL
+#define PM_XS_MASK 0x00000003ULL
+
+/* PointerMasking XS bits values */
+#define PM_EXT_DISABLE 0x00000000ULL
+#define PM_EXT_INITIAL 0x00000001ULL
+#define PM_EXT_CLEAN 0x00000002ULL
+#define PM_EXT_DIRTY 0x00000003ULL
+
+/* Offsets for every pair of control bits per each priv level */
+#define XS_OFFSET 0ULL
+#define U_OFFSET 2ULL
+#define S_OFFSET 5ULL
+#define M_OFFSET 8ULL
+
+#define PM_XS_BITS (PM_XS_MASK << XS_OFFSET)
+#define U_PM_ENABLE (PM_ENABLE << U_OFFSET)
+#define U_PM_CURRENT (PM_CURRENT << U_OFFSET)
+#define U_PM_INSN (PM_INSN << U_OFFSET)
+#define S_PM_ENABLE (PM_ENABLE << S_OFFSET)
+#define S_PM_CURRENT (PM_CURRENT << S_OFFSET)
+#define S_PM_INSN (PM_INSN << S_OFFSET)
+#define M_PM_ENABLE (PM_ENABLE << M_OFFSET)
+#define M_PM_CURRENT (PM_CURRENT << M_OFFSET)
+#define M_PM_INSN (PM_INSN << M_OFFSET)
+
+/* mmte CSR bits */
+#define MMTE_PM_XS_BITS PM_XS_BITS
+#define MMTE_U_PM_ENABLE U_PM_ENABLE
+#define MMTE_U_PM_CURRENT U_PM_CURRENT
+#define MMTE_U_PM_INSN U_PM_INSN
+#define MMTE_S_PM_ENABLE S_PM_ENABLE
+#define MMTE_S_PM_CURRENT S_PM_CURRENT
+#define MMTE_S_PM_INSN S_PM_INSN
+#define MMTE_M_PM_ENABLE M_PM_ENABLE
+#define MMTE_M_PM_CURRENT M_PM_CURRENT
+#define MMTE_M_PM_INSN M_PM_INSN
+#define MMTE_MASK (MMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | MMTE_U_PM_INSN | \
+ MMTE_S_PM_ENABLE | MMTE_S_PM_CURRENT | MMTE_S_PM_INSN | \
+ MMTE_M_PM_ENABLE | MMTE_M_PM_CURRENT | MMTE_M_PM_INSN | \
+ MMTE_PM_XS_BITS)
+
+/* (v)smte CSR bits */
+#define SMTE_PM_XS_BITS PM_XS_BITS
+#define SMTE_U_PM_ENABLE U_PM_ENABLE
+#define SMTE_U_PM_CURRENT U_PM_CURRENT
+#define SMTE_U_PM_INSN U_PM_INSN
+#define SMTE_S_PM_ENABLE S_PM_ENABLE
+#define SMTE_S_PM_CURRENT S_PM_CURRENT
+#define SMTE_S_PM_INSN S_PM_INSN
+#define SMTE_MASK (SMTE_U_PM_ENABLE | SMTE_U_PM_CURRENT | SMTE_U_PM_INSN | \
+ SMTE_S_PM_ENABLE | SMTE_S_PM_CURRENT | SMTE_S_PM_INSN | \
+ SMTE_PM_XS_BITS)
+
+/* umte CSR bits */
+#define UMTE_U_PM_ENABLE U_PM_ENABLE
+#define UMTE_U_PM_CURRENT U_PM_CURRENT
+#define UMTE_U_PM_INSN U_PM_INSN
+#define UMTE_MASK (UMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | UMTE_U_PM_INSN)
+
+#endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
new file mode 100644
index 000000000..9eeed38c7
--- /dev/null
+++ b/target/riscv/cpu_helper.c
@@ -0,0 +1,1138 @@
+/*
+ * RISC-V CPU helpers for qemu.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "tcg/tcg-op.h"
+#include "trace.h"
+#include "semihosting/common-semi.h"
+
+int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
+{
+#ifdef CONFIG_USER_ONLY
+ return 0;
+#else
+ return env->priv;
+#endif
+}
+
+static RISCVMXL cpu_get_xl(CPURISCVState *env)
+{
+#if defined(TARGET_RISCV32)
+ return MXL_RV32;
+#elif defined(CONFIG_USER_ONLY)
+ return MXL_RV64;
+#else
+ RISCVMXL xl = riscv_cpu_mxl(env);
+
+ /*
+ * When emulating a 32-bit-only cpu, use RV32.
+ * When emulating a 64-bit cpu, and MXL has been reduced to RV32,
+ * MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened
+ * back to RV64 for lower privs.
+ */
+ if (xl != MXL_RV32) {
+ switch (env->priv) {
+ case PRV_M:
+ break;
+ case PRV_U:
+ xl = get_field(env->mstatus, MSTATUS64_UXL);
+ break;
+ default: /* PRV_S | PRV_H */
+ xl = get_field(env->mstatus, MSTATUS64_SXL);
+ break;
+ }
+ }
+ return xl;
+#endif
+}
+
+void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
+ target_ulong *cs_base, uint32_t *pflags)
+{
+ uint32_t flags = 0;
+
+ *pc = env->pc;
+ *cs_base = 0;
+
+ if (riscv_has_ext(env, RVV)) {
+ uint32_t vlmax = vext_get_vlmax(env_archcpu(env), env->vtype);
+ bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl);
+ flags = FIELD_DP32(flags, TB_FLAGS, VILL,
+ FIELD_EX64(env->vtype, VTYPE, VILL));
+ flags = FIELD_DP32(flags, TB_FLAGS, SEW,
+ FIELD_EX64(env->vtype, VTYPE, VSEW));
+ flags = FIELD_DP32(flags, TB_FLAGS, LMUL,
+ FIELD_EX64(env->vtype, VTYPE, VLMUL));
+ flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax);
+ } else {
+ flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
+ }
+
+#ifdef CONFIG_USER_ONLY
+ flags |= TB_FLAGS_MSTATUS_FS;
+#else
+ flags |= cpu_mmu_index(env, 0);
+ if (riscv_cpu_fp_enabled(env)) {
+ flags |= env->mstatus & MSTATUS_FS;
+ }
+
+ if (riscv_has_ext(env, RVH)) {
+ if (env->priv == PRV_M ||
+ (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
+ (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
+ get_field(env->hstatus, HSTATUS_HU))) {
+ flags = FIELD_DP32(flags, TB_FLAGS, HLSX, 1);
+ }
+
+ flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_FS,
+ get_field(env->mstatus_hs, MSTATUS_FS));
+ }
+ if (riscv_has_ext(env, RVJ)) {
+ int priv = flags & TB_FLAGS_PRIV_MMU_MASK;
+ bool pm_enabled = false;
+ switch (priv) {
+ case PRV_U:
+ pm_enabled = env->mmte & U_PM_ENABLE;
+ break;
+ case PRV_S:
+ pm_enabled = env->mmte & S_PM_ENABLE;
+ break;
+ case PRV_M:
+ pm_enabled = env->mmte & M_PM_ENABLE;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ flags = FIELD_DP32(flags, TB_FLAGS, PM_ENABLED, pm_enabled);
+ }
+#endif
+
+ flags = FIELD_DP32(flags, TB_FLAGS, XL, cpu_get_xl(env));
+
+ *pflags = flags;
+}
+
+#ifndef CONFIG_USER_ONLY
+static int riscv_cpu_local_irq_pending(CPURISCVState *env)
+{
+ target_ulong virt_enabled = riscv_cpu_virt_enabled(env);
+
+ target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
+ target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
+
+ target_ulong pending = env->mip & env->mie;
+
+ target_ulong mie = env->priv < PRV_M ||
+ (env->priv == PRV_M && mstatus_mie);
+ target_ulong sie = env->priv < PRV_S ||
+ (env->priv == PRV_S && mstatus_sie);
+ target_ulong hsie = virt_enabled || sie;
+ target_ulong vsie = virt_enabled && sie;
+
+ target_ulong irqs =
+ (pending & ~env->mideleg & -mie) |
+ (pending & env->mideleg & ~env->hideleg & -hsie) |
+ (pending & env->mideleg & env->hideleg & -vsie);
+
+ if (irqs) {
+ return ctz64(irqs); /* since non-zero */
+ } else {
+ return RISCV_EXCP_NONE; /* indicates no pending interrupt */
+ }
+}
+
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ int interruptno = riscv_cpu_local_irq_pending(env);
+ if (interruptno >= 0) {
+ cs->exception_index = RISCV_EXCP_INT_FLAG | interruptno;
+ riscv_cpu_do_interrupt(cs);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Return true is floating point support is currently enabled */
+bool riscv_cpu_fp_enabled(CPURISCVState *env)
+{
+ if (env->mstatus & MSTATUS_FS) {
+ if (riscv_cpu_virt_enabled(env) && !(env->mstatus_hs & MSTATUS_FS)) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
+{
+ uint64_t mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS |
+ MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE |
+ MSTATUS64_UXL;
+ bool current_virt = riscv_cpu_virt_enabled(env);
+
+ g_assert(riscv_has_ext(env, RVH));
+
+ if (current_virt) {
+ /* Current V=1 and we are about to change to V=0 */
+ env->vsstatus = env->mstatus & mstatus_mask;
+ env->mstatus &= ~mstatus_mask;
+ env->mstatus |= env->mstatus_hs;
+
+ env->vstvec = env->stvec;
+ env->stvec = env->stvec_hs;
+
+ env->vsscratch = env->sscratch;
+ env->sscratch = env->sscratch_hs;
+
+ env->vsepc = env->sepc;
+ env->sepc = env->sepc_hs;
+
+ env->vscause = env->scause;
+ env->scause = env->scause_hs;
+
+ env->vstval = env->stval;
+ env->stval = env->stval_hs;
+
+ env->vsatp = env->satp;
+ env->satp = env->satp_hs;
+ } else {
+ /* Current V=0 and we are about to change to V=1 */
+ env->mstatus_hs = env->mstatus & mstatus_mask;
+ env->mstatus &= ~mstatus_mask;
+ env->mstatus |= env->vsstatus;
+
+ env->stvec_hs = env->stvec;
+ env->stvec = env->vstvec;
+
+ env->sscratch_hs = env->sscratch;
+ env->sscratch = env->vsscratch;
+
+ env->sepc_hs = env->sepc;
+ env->sepc = env->vsepc;
+
+ env->scause_hs = env->scause;
+ env->scause = env->vscause;
+
+ env->stval_hs = env->stval;
+ env->stval = env->vstval;
+
+ env->satp_hs = env->satp;
+ env->satp = env->vsatp;
+ }
+}
+
+bool riscv_cpu_virt_enabled(CPURISCVState *env)
+{
+ if (!riscv_has_ext(env, RVH)) {
+ return false;
+ }
+
+ return get_field(env->virt, VIRT_ONOFF);
+}
+
+void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
+{
+ if (!riscv_has_ext(env, RVH)) {
+ return;
+ }
+
+ /* Flush the TLB on all virt mode changes. */
+ if (get_field(env->virt, VIRT_ONOFF) != enable) {
+ tlb_flush(env_cpu(env));
+ }
+
+ env->virt = set_field(env->virt, VIRT_ONOFF, enable);
+}
+
+bool riscv_cpu_two_stage_lookup(int mmu_idx)
+{
+ return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+}
+
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
+{
+ CPURISCVState *env = &cpu->env;
+ if (env->miclaim & interrupts) {
+ return -1;
+ } else {
+ env->miclaim |= interrupts;
+ return 0;
+ }
+}
+
+uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
+{
+ CPURISCVState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+ uint32_t old = env->mip;
+ bool locked = false;
+
+ if (!qemu_mutex_iothread_locked()) {
+ locked = true;
+ qemu_mutex_lock_iothread();
+ }
+
+ env->mip = (env->mip & ~mask) | (value & mask);
+
+ if (env->mip) {
+ cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+ }
+
+ if (locked) {
+ qemu_mutex_unlock_iothread();
+ }
+
+ return old;
+}
+
+void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
+ uint32_t arg)
+{
+ env->rdtime_fn = fn;
+ env->rdtime_fn_arg = arg;
+}
+
+void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
+{
+ if (newpriv > PRV_M) {
+ g_assert_not_reached();
+ }
+ if (newpriv == PRV_H) {
+ newpriv = PRV_U;
+ }
+ /* tlb_flush is unnecessary as mode is contained in mmu_idx */
+ env->priv = newpriv;
+
+ /*
+ * Clear the load reservation - otherwise a reservation placed in one
+ * context/process can be used by another, resulting in an SC succeeding
+ * incorrectly. Version 2.2 of the ISA specification explicitly requires
+ * this behaviour, while later revisions say that the kernel "should" use
+ * an SC instruction to force the yielding of a load reservation on a
+ * preemptive context switch. As a result, do both.
+ */
+ env->load_res = -1;
+}
+
+/*
+ * get_physical_address_pmp - check PMP permission for this physical address
+ *
+ * Match the PMP region and check permission for this physical address and it's
+ * TLB page. Returns 0 if the permission checking was successful
+ *
+ * @env: CPURISCVState
+ * @prot: The returned protection attributes
+ * @tlb_size: TLB page size containing addr. It could be modified after PMP
+ * permission checking. NULL if not set TLB page for addr.
+ * @addr: The physical address to be checked permission
+ * @access_type: The type of MMU access
+ * @mode: Indicates current privilege level.
+ */
+static int get_physical_address_pmp(CPURISCVState *env, int *prot,
+ target_ulong *tlb_size, hwaddr addr,
+ int size, MMUAccessType access_type,
+ int mode)
+{
+ pmp_priv_t pmp_priv;
+ target_ulong tlb_size_pmp = 0;
+
+ if (!riscv_feature(env, RISCV_FEATURE_PMP)) {
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TRANSLATE_SUCCESS;
+ }
+
+ if (!pmp_hart_has_privs(env, addr, size, 1 << access_type, &pmp_priv,
+ mode)) {
+ *prot = 0;
+ return TRANSLATE_PMP_FAIL;
+ }
+
+ *prot = pmp_priv_to_page_prot(pmp_priv);
+ if (tlb_size != NULL) {
+ if (pmp_is_range_in_tlb(env, addr & ~(*tlb_size - 1), &tlb_size_pmp)) {
+ *tlb_size = tlb_size_pmp;
+ }
+ }
+
+ return TRANSLATE_SUCCESS;
+}
+
+/* get_physical_address - get the physical address for this virtual address
+ *
+ * Do a page table walk to obtain the physical address corresponding to a
+ * virtual address. Returns 0 if the translation was successful
+ *
+ * Adapted from Spike's mmu_t::translate and mmu_t::walk
+ *
+ * @env: CPURISCVState
+ * @physical: This will be set to the calculated physical address
+ * @prot: The returned protection attributes
+ * @addr: The virtual address to be translated
+ * @fault_pte_addr: If not NULL, this will be set to fault pte address
+ * when a error occurs on pte address translation.
+ * This will already be shifted to match htval.
+ * @access_type: The type of MMU access
+ * @mmu_idx: Indicates current privilege level
+ * @first_stage: Are we in first stage translation?
+ * Second stage is used for hypervisor guest translation
+ * @two_stage: Are we going to perform two stage translation
+ * @is_debug: Is this access from a debugger or the monitor?
+ */
+static int get_physical_address(CPURISCVState *env, hwaddr *physical,
+ int *prot, target_ulong addr,
+ target_ulong *fault_pte_addr,
+ int access_type, int mmu_idx,
+ bool first_stage, bool two_stage,
+ bool is_debug)
+{
+ /* NOTE: the env->pc value visible here will not be
+ * correct, but the value visible to the exception handler
+ * (riscv_cpu_do_interrupt) is correct */
+ MemTxResult res;
+ MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
+ int mode = mmu_idx & TB_FLAGS_PRIV_MMU_MASK;
+ bool use_background = false;
+
+ /*
+ * Check if we should use the background registers for the two
+ * stage translation. We don't need to check if we actually need
+ * two stage translation as that happened before this function
+ * was called. Background registers will be used if the guest has
+ * forced a two stage translation to be on (in HS or M mode).
+ */
+ if (!riscv_cpu_virt_enabled(env) && two_stage) {
+ use_background = true;
+ }
+
+ /* MPRV does not affect the virtual-machine load/store
+ instructions, HLV, HLVX, and HSV. */
+ if (riscv_cpu_two_stage_lookup(mmu_idx)) {
+ mode = get_field(env->hstatus, HSTATUS_SPVP);
+ } else if (mode == PRV_M && access_type != MMU_INST_FETCH) {
+ if (get_field(env->mstatus, MSTATUS_MPRV)) {
+ mode = get_field(env->mstatus, MSTATUS_MPP);
+ }
+ }
+
+ if (first_stage == false) {
+ /* We are in stage 2 translation, this is similar to stage 1. */
+ /* Stage 2 is always taken as U-mode */
+ mode = PRV_U;
+ }
+
+ if (mode == PRV_M || !riscv_feature(env, RISCV_FEATURE_MMU)) {
+ *physical = addr;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TRANSLATE_SUCCESS;
+ }
+
+ *prot = 0;
+
+ hwaddr base;
+ int levels, ptidxbits, ptesize, vm, sum, mxr, widened;
+
+ if (first_stage == true) {
+ mxr = get_field(env->mstatus, MSTATUS_MXR);
+ } else {
+ mxr = get_field(env->vsstatus, MSTATUS_MXR);
+ }
+
+ if (first_stage == true) {
+ if (use_background) {
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->vsatp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->vsatp, SATP64_MODE);
+ }
+ } else {
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP64_MODE);
+ }
+ }
+ widened = 0;
+ } else {
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->hgatp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->hgatp, SATP64_MODE);
+ }
+ widened = 2;
+ }
+ /* status.SUM will be ignored if execute on background */
+ sum = get_field(env->mstatus, MSTATUS_SUM) || use_background || is_debug;
+ switch (vm) {
+ case VM_1_10_SV32:
+ levels = 2; ptidxbits = 10; ptesize = 4; break;
+ case VM_1_10_SV39:
+ levels = 3; ptidxbits = 9; ptesize = 8; break;
+ case VM_1_10_SV48:
+ levels = 4; ptidxbits = 9; ptesize = 8; break;
+ case VM_1_10_SV57:
+ levels = 5; ptidxbits = 9; ptesize = 8; break;
+ case VM_1_10_MBARE:
+ *physical = addr;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TRANSLATE_SUCCESS;
+ default:
+ g_assert_not_reached();
+ }
+
+ CPUState *cs = env_cpu(env);
+ int va_bits = PGSHIFT + levels * ptidxbits + widened;
+ target_ulong mask, masked_msbs;
+
+ if (TARGET_LONG_BITS > (va_bits - 1)) {
+ mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
+ } else {
+ mask = 0;
+ }
+ masked_msbs = (addr >> (va_bits - 1)) & mask;
+
+ if (masked_msbs != 0 && masked_msbs != mask) {
+ return TRANSLATE_FAIL;
+ }
+
+ int ptshift = (levels - 1) * ptidxbits;
+ int i;
+
+#if !TCG_OVERSIZED_GUEST
+restart:
+#endif
+ for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
+ target_ulong idx;
+ if (i == 0) {
+ idx = (addr >> (PGSHIFT + ptshift)) &
+ ((1 << (ptidxbits + widened)) - 1);
+ } else {
+ idx = (addr >> (PGSHIFT + ptshift)) &
+ ((1 << ptidxbits) - 1);
+ }
+
+ /* check that physical address of PTE is legal */
+ hwaddr pte_addr;
+
+ if (two_stage && first_stage) {
+ int vbase_prot;
+ hwaddr vbase;
+
+ /* Do the second stage translation on the base PTE address. */
+ int vbase_ret = get_physical_address(env, &vbase, &vbase_prot,
+ base, NULL, MMU_DATA_LOAD,
+ mmu_idx, false, true,
+ is_debug);
+
+ if (vbase_ret != TRANSLATE_SUCCESS) {
+ if (fault_pte_addr) {
+ *fault_pte_addr = (base + idx * ptesize) >> 2;
+ }
+ return TRANSLATE_G_STAGE_FAIL;
+ }
+
+ pte_addr = vbase + idx * ptesize;
+ } else {
+ pte_addr = base + idx * ptesize;
+ }
+
+ int pmp_prot;
+ int pmp_ret = get_physical_address_pmp(env, &pmp_prot, NULL, pte_addr,
+ sizeof(target_ulong),
+ MMU_DATA_LOAD, PRV_S);
+ if (pmp_ret != TRANSLATE_SUCCESS) {
+ return TRANSLATE_PMP_FAIL;
+ }
+
+ target_ulong pte;
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ pte = address_space_ldl(cs->as, pte_addr, attrs, &res);
+ } else {
+ pte = address_space_ldq(cs->as, pte_addr, attrs, &res);
+ }
+
+ if (res != MEMTX_OK) {
+ return TRANSLATE_FAIL;
+ }
+
+ hwaddr ppn = pte >> PTE_PPN_SHIFT;
+
+ if (!(pte & PTE_V)) {
+ /* Invalid PTE */
+ return TRANSLATE_FAIL;
+ } else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
+ /* Inner PTE, continue walking */
+ base = ppn << PGSHIFT;
+ } else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) {
+ /* Reserved leaf PTE flags: PTE_W */
+ return TRANSLATE_FAIL;
+ } else if ((pte & (PTE_R | PTE_W | PTE_X)) == (PTE_W | PTE_X)) {
+ /* Reserved leaf PTE flags: PTE_W + PTE_X */
+ return TRANSLATE_FAIL;
+ } else if ((pte & PTE_U) && ((mode != PRV_U) &&
+ (!sum || access_type == MMU_INST_FETCH))) {
+ /* User PTE flags when not U mode and mstatus.SUM is not set,
+ or the access type is an instruction fetch */
+ return TRANSLATE_FAIL;
+ } else if (!(pte & PTE_U) && (mode != PRV_S)) {
+ /* Supervisor PTE flags when not S mode */
+ return TRANSLATE_FAIL;
+ } else if (ppn & ((1ULL << ptshift) - 1)) {
+ /* Misaligned PPN */
+ return TRANSLATE_FAIL;
+ } else if (access_type == MMU_DATA_LOAD && !((pte & PTE_R) ||
+ ((pte & PTE_X) && mxr))) {
+ /* Read access check failed */
+ return TRANSLATE_FAIL;
+ } else if (access_type == MMU_DATA_STORE && !(pte & PTE_W)) {
+ /* Write access check failed */
+ return TRANSLATE_FAIL;
+ } else if (access_type == MMU_INST_FETCH && !(pte & PTE_X)) {
+ /* Fetch access check failed */
+ return TRANSLATE_FAIL;
+ } else {
+ /* if necessary, set accessed and dirty bits. */
+ target_ulong updated_pte = pte | PTE_A |
+ (access_type == MMU_DATA_STORE ? PTE_D : 0);
+
+ /* Page table updates need to be atomic with MTTCG enabled */
+ if (updated_pte != pte) {
+ /*
+ * - if accessed or dirty bits need updating, and the PTE is
+ * in RAM, then we do so atomically with a compare and swap.
+ * - if the PTE is in IO space or ROM, then it can't be updated
+ * and we return TRANSLATE_FAIL.
+ * - if the PTE changed by the time we went to update it, then
+ * it is no longer valid and we must re-walk the page table.
+ */
+ MemoryRegion *mr;
+ hwaddr l = sizeof(target_ulong), addr1;
+ mr = address_space_translate(cs->as, pte_addr,
+ &addr1, &l, false, MEMTXATTRS_UNSPECIFIED);
+ if (memory_region_is_ram(mr)) {
+ target_ulong *pte_pa =
+ qemu_map_ram_ptr(mr->ram_block, addr1);
+#if TCG_OVERSIZED_GUEST
+ /* MTTCG is not enabled on oversized TCG guests so
+ * page table updates do not need to be atomic */
+ *pte_pa = pte = updated_pte;
+#else
+ target_ulong old_pte =
+ qatomic_cmpxchg(pte_pa, pte, updated_pte);
+ if (old_pte != pte) {
+ goto restart;
+ } else {
+ pte = updated_pte;
+ }
+#endif
+ } else {
+ /* misconfigured PTE in ROM (AD bits are not preset) or
+ * PTE is in IO space and can't be updated atomically */
+ return TRANSLATE_FAIL;
+ }
+ }
+
+ /* for superpage mappings, make a fake leaf PTE for the TLB's
+ benefit. */
+ target_ulong vpn = addr >> PGSHIFT;
+ *physical = ((ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT) |
+ (addr & ~TARGET_PAGE_MASK);
+
+ /* set permissions on the TLB entry */
+ if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {
+ *prot |= PAGE_READ;
+ }
+ if ((pte & PTE_X)) {
+ *prot |= PAGE_EXEC;
+ }
+ /* add write permission on stores or if the page is already dirty,
+ so that we TLB miss on later writes to update the dirty bit */
+ if ((pte & PTE_W) &&
+ (access_type == MMU_DATA_STORE || (pte & PTE_D))) {
+ *prot |= PAGE_WRITE;
+ }
+ return TRANSLATE_SUCCESS;
+ }
+ }
+ return TRANSLATE_FAIL;
+}
+
+static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
+ MMUAccessType access_type, bool pmp_violation,
+ bool first_stage, bool two_stage)
+{
+ CPUState *cs = env_cpu(env);
+ int page_fault_exceptions, vm;
+ uint64_t stap_mode;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ stap_mode = SATP32_MODE;
+ } else {
+ stap_mode = SATP64_MODE;
+ }
+
+ if (first_stage) {
+ vm = get_field(env->satp, stap_mode);
+ } else {
+ vm = get_field(env->hgatp, stap_mode);
+ }
+
+ page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation;
+
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ if (riscv_cpu_virt_enabled(env) && !first_stage) {
+ cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT;
+ } else {
+ cs->exception_index = page_fault_exceptions ?
+ RISCV_EXCP_INST_PAGE_FAULT : RISCV_EXCP_INST_ACCESS_FAULT;
+ }
+ break;
+ case MMU_DATA_LOAD:
+ if (two_stage && !first_stage) {
+ cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
+ } else {
+ cs->exception_index = page_fault_exceptions ?
+ RISCV_EXCP_LOAD_PAGE_FAULT : RISCV_EXCP_LOAD_ACCESS_FAULT;
+ }
+ break;
+ case MMU_DATA_STORE:
+ if (two_stage && !first_stage) {
+ cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
+ } else {
+ cs->exception_index = page_fault_exceptions ?
+ RISCV_EXCP_STORE_PAGE_FAULT : RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ env->badaddr = address;
+ env->two_stage_lookup = two_stage;
+}
+
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ hwaddr phys_addr;
+ int prot;
+ int mmu_idx = cpu_mmu_index(&cpu->env, false);
+
+ if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx,
+ true, riscv_cpu_virt_enabled(env), true)) {
+ return -1;
+ }
+
+ if (riscv_cpu_virt_enabled(env)) {
+ if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL,
+ 0, mmu_idx, false, true, true)) {
+ return -1;
+ }
+ }
+
+ return phys_addr & TARGET_PAGE_MASK;
+}
+
+void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ if (access_type == MMU_DATA_STORE) {
+ cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+ } else if (access_type == MMU_DATA_LOAD) {
+ cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
+ } else {
+ cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT;
+ }
+
+ env->badaddr = addr;
+ env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
+ riscv_cpu_two_stage_lookup(mmu_idx);
+ riscv_raise_exception(&cpu->env, cs->exception_index, retaddr);
+}
+
+void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+ MMUAccessType access_type, int mmu_idx,
+ uintptr_t retaddr)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ cs->exception_index = RISCV_EXCP_INST_ADDR_MIS;
+ break;
+ case MMU_DATA_LOAD:
+ cs->exception_index = RISCV_EXCP_LOAD_ADDR_MIS;
+ break;
+ case MMU_DATA_STORE:
+ cs->exception_index = RISCV_EXCP_STORE_AMO_ADDR_MIS;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ env->badaddr = addr;
+ env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
+ riscv_cpu_two_stage_lookup(mmu_idx);
+ riscv_raise_exception(env, cs->exception_index, retaddr);
+}
+
+bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ vaddr im_address;
+ hwaddr pa = 0;
+ int prot, prot2, prot_pmp;
+ bool pmp_violation = false;
+ bool first_stage_error = true;
+ bool two_stage_lookup = false;
+ int ret = TRANSLATE_FAIL;
+ int mode = mmu_idx;
+ /* default TLB page size */
+ target_ulong tlb_size = TARGET_PAGE_SIZE;
+
+ env->guest_phys_fault_addr = 0;
+
+ qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
+ __func__, address, access_type, mmu_idx);
+
+ /* MPRV does not affect the virtual-machine load/store
+ instructions, HLV, HLVX, and HSV. */
+ if (riscv_cpu_two_stage_lookup(mmu_idx)) {
+ mode = get_field(env->hstatus, HSTATUS_SPVP);
+ } else if (mode == PRV_M && access_type != MMU_INST_FETCH &&
+ get_field(env->mstatus, MSTATUS_MPRV)) {
+ mode = get_field(env->mstatus, MSTATUS_MPP);
+ if (riscv_has_ext(env, RVH) && get_field(env->mstatus, MSTATUS_MPV)) {
+ two_stage_lookup = true;
+ }
+ }
+
+ if (riscv_cpu_virt_enabled(env) ||
+ ((riscv_cpu_two_stage_lookup(mmu_idx) || two_stage_lookup) &&
+ access_type != MMU_INST_FETCH)) {
+ /* Two stage lookup */
+ ret = get_physical_address(env, &pa, &prot, address,
+ &env->guest_phys_fault_addr, access_type,
+ mmu_idx, true, true, false);
+
+ /*
+ * A G-stage exception may be triggered during two state lookup.
+ * And the env->guest_phys_fault_addr has already been set in
+ * get_physical_address().
+ */
+ if (ret == TRANSLATE_G_STAGE_FAIL) {
+ first_stage_error = false;
+ access_type = MMU_DATA_LOAD;
+ }
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
+ TARGET_FMT_plx " prot %d\n",
+ __func__, address, ret, pa, prot);
+
+ if (ret == TRANSLATE_SUCCESS) {
+ /* Second stage lookup */
+ im_address = pa;
+
+ ret = get_physical_address(env, &pa, &prot2, im_address, NULL,
+ access_type, mmu_idx, false, true,
+ false);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical "
+ TARGET_FMT_plx " prot %d\n",
+ __func__, im_address, ret, pa, prot2);
+
+ prot &= prot2;
+
+ if (ret == TRANSLATE_SUCCESS) {
+ ret = get_physical_address_pmp(env, &prot_pmp, &tlb_size, pa,
+ size, access_type, mode);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s PMP address=" TARGET_FMT_plx " ret %d prot"
+ " %d tlb_size " TARGET_FMT_lu "\n",
+ __func__, pa, ret, prot_pmp, tlb_size);
+
+ prot &= prot_pmp;
+ }
+
+ if (ret != TRANSLATE_SUCCESS) {
+ /*
+ * Guest physical address translation failed, this is a HS
+ * level exception
+ */
+ first_stage_error = false;
+ env->guest_phys_fault_addr = (im_address |
+ (address &
+ (TARGET_PAGE_SIZE - 1))) >> 2;
+ }
+ }
+ } else {
+ /* Single stage lookup */
+ ret = get_physical_address(env, &pa, &prot, address, NULL,
+ access_type, mmu_idx, true, false, false);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s address=%" VADDR_PRIx " ret %d physical "
+ TARGET_FMT_plx " prot %d\n",
+ __func__, address, ret, pa, prot);
+
+ if (ret == TRANSLATE_SUCCESS) {
+ ret = get_physical_address_pmp(env, &prot_pmp, &tlb_size, pa,
+ size, access_type, mode);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s PMP address=" TARGET_FMT_plx " ret %d prot"
+ " %d tlb_size " TARGET_FMT_lu "\n",
+ __func__, pa, ret, prot_pmp, tlb_size);
+
+ prot &= prot_pmp;
+ }
+ }
+
+ if (ret == TRANSLATE_PMP_FAIL) {
+ pmp_violation = true;
+ }
+
+ if (ret == TRANSLATE_SUCCESS) {
+ tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1),
+ prot, mmu_idx, tlb_size);
+ return true;
+ } else if (probe) {
+ return false;
+ } else {
+ raise_mmu_exception(env, address, access_type, pmp_violation,
+ first_stage_error,
+ riscv_cpu_virt_enabled(env) ||
+ riscv_cpu_two_stage_lookup(mmu_idx));
+ riscv_raise_exception(env, cs->exception_index, retaddr);
+ }
+
+ return true;
+}
+#endif /* !CONFIG_USER_ONLY */
+
+/*
+ * Handle Traps
+ *
+ * Adapted from Spike's processor_t::take_trap.
+ *
+ */
+void riscv_cpu_do_interrupt(CPUState *cs)
+{
+#if !defined(CONFIG_USER_ONLY)
+
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ uint64_t s;
+
+ /* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
+ * so we mask off the MSB and separate into trap type and cause.
+ */
+ bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
+ target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
+ target_ulong deleg = async ? env->mideleg : env->medeleg;
+ bool write_tval = false;
+ target_ulong tval = 0;
+ target_ulong htval = 0;
+ target_ulong mtval2 = 0;
+
+ if (cause == RISCV_EXCP_SEMIHOST) {
+ if (env->priv >= PRV_S) {
+ env->gpr[xA0] = do_common_semihosting(cs);
+ env->pc += 4;
+ return;
+ }
+ cause = RISCV_EXCP_BREAKPOINT;
+ }
+
+ if (!async) {
+ /* set tval to badaddr for traps with address information */
+ switch (cause) {
+ case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
+ case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
+ case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
+ case RISCV_EXCP_INST_ADDR_MIS:
+ case RISCV_EXCP_INST_ACCESS_FAULT:
+ case RISCV_EXCP_LOAD_ADDR_MIS:
+ case RISCV_EXCP_STORE_AMO_ADDR_MIS:
+ case RISCV_EXCP_LOAD_ACCESS_FAULT:
+ case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
+ case RISCV_EXCP_INST_PAGE_FAULT:
+ case RISCV_EXCP_LOAD_PAGE_FAULT:
+ case RISCV_EXCP_STORE_PAGE_FAULT:
+ write_tval = true;
+ tval = env->badaddr;
+ break;
+ default:
+ break;
+ }
+ /* ecall is dispatched as one cause so translate based on mode */
+ if (cause == RISCV_EXCP_U_ECALL) {
+ assert(env->priv <= 3);
+
+ if (env->priv == PRV_M) {
+ cause = RISCV_EXCP_M_ECALL;
+ } else if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
+ cause = RISCV_EXCP_VS_ECALL;
+ } else if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) {
+ cause = RISCV_EXCP_S_ECALL;
+ } else if (env->priv == PRV_U) {
+ cause = RISCV_EXCP_U_ECALL;
+ }
+ }
+ }
+
+ trace_riscv_trap(env->mhartid, async, cause, env->pc, tval,
+ riscv_cpu_get_trap_name(cause, async));
+
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: hart:"TARGET_FMT_ld", async:%d, cause:"TARGET_FMT_lx", "
+ "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n",
+ __func__, env->mhartid, async, cause, env->pc, tval,
+ riscv_cpu_get_trap_name(cause, async));
+
+ if (env->priv <= PRV_S &&
+ cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
+ /* handle the trap in S-mode */
+ if (riscv_has_ext(env, RVH)) {
+ target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
+
+ if (env->two_stage_lookup && write_tval) {
+ /*
+ * If we are writing a guest virtual address to stval, set
+ * this to 1. If we are trapping to VS we will set this to 0
+ * later.
+ */
+ env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 1);
+ } else {
+ /* For other HS-mode traps, we set this to 0. */
+ env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 0);
+ }
+
+ if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1)) {
+ /* Trap to VS mode */
+ /*
+ * See if we need to adjust cause. Yes if its VS mode interrupt
+ * no if hypervisor has delegated one of hs mode's interrupt
+ */
+ if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
+ cause == IRQ_VS_EXT) {
+ cause = cause - 1;
+ }
+ env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 0);
+ } else if (riscv_cpu_virt_enabled(env)) {
+ /* Trap into HS mode, from virt */
+ riscv_cpu_swap_hypervisor_regs(env);
+ env->hstatus = set_field(env->hstatus, HSTATUS_SPVP,
+ env->priv);
+ env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
+ riscv_cpu_virt_enabled(env));
+
+ htval = env->guest_phys_fault_addr;
+
+ riscv_cpu_set_virt_enabled(env, 0);
+ } else {
+ /* Trap into HS mode */
+ env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
+ htval = env->guest_phys_fault_addr;
+ }
+ }
+
+ s = env->mstatus;
+ s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
+ s = set_field(s, MSTATUS_SPP, env->priv);
+ s = set_field(s, MSTATUS_SIE, 0);
+ env->mstatus = s;
+ env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
+ env->sepc = env->pc;
+ env->stval = tval;
+ env->htval = htval;
+ env->pc = (env->stvec >> 2 << 2) +
+ ((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
+ riscv_cpu_set_mode(env, PRV_S);
+ } else {
+ /* handle the trap in M-mode */
+ if (riscv_has_ext(env, RVH)) {
+ if (riscv_cpu_virt_enabled(env)) {
+ riscv_cpu_swap_hypervisor_regs(env);
+ }
+ env->mstatus = set_field(env->mstatus, MSTATUS_MPV,
+ riscv_cpu_virt_enabled(env));
+ if (riscv_cpu_virt_enabled(env) && tval) {
+ env->mstatus = set_field(env->mstatus, MSTATUS_GVA, 1);
+ }
+
+ mtval2 = env->guest_phys_fault_addr;
+
+ /* Trapping to M mode, virt is disabled */
+ riscv_cpu_set_virt_enabled(env, 0);
+ }
+
+ s = env->mstatus;
+ s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
+ s = set_field(s, MSTATUS_MPP, env->priv);
+ s = set_field(s, MSTATUS_MIE, 0);
+ env->mstatus = s;
+ env->mcause = cause | ~(((target_ulong)-1) >> async);
+ env->mepc = env->pc;
+ env->mtval = tval;
+ env->mtval2 = mtval2;
+ env->pc = (env->mtvec >> 2 << 2) +
+ ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
+ riscv_cpu_set_mode(env, PRV_M);
+ }
+
+ /* NOTE: it is not necessary to yield load reservations here. It is only
+ * necessary for an SC from "another hart" to cause a load reservation
+ * to be yielded. Refer to the memory consistency model section of the
+ * RISC-V ISA Specification.
+ */
+
+ env->two_stage_lookup = false;
+#endif
+ cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */
+}
diff --git a/target/riscv/cpu_user.h b/target/riscv/cpu_user.h
new file mode 100644
index 000000000..02afad608
--- /dev/null
+++ b/target/riscv/cpu_user.h
@@ -0,0 +1,19 @@
+#ifndef TARGET_RISCV_CPU_USER_H
+#define TARGET_RISCV_CPU_USER_H
+
+#define xRA 1 /* return address (aka link register) */
+#define xSP 2 /* stack pointer */
+#define xGP 3 /* global pointer */
+#define xTP 4 /* thread pointer */
+
+#define xA0 10 /* gpr[10-17] are syscall arguments */
+#define xA1 11
+#define xA2 12
+#define xA3 13
+#define xA4 14
+#define xA5 15
+#define xA6 16
+#define xA7 17 /* syscall number for RVI ABI */
+#define xT0 5 /* syscall number for RVE ABI */
+
+#endif
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
new file mode 100644
index 000000000..9f4195489
--- /dev/null
+++ b/target/riscv/csr.c
@@ -0,0 +1,2098 @@
+/*
+ * RISC-V Control and Status Registers.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
+
+/* CSR function table public API */
+void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops)
+{
+ *ops = csr_ops[csrno & (CSR_TABLE_SIZE - 1)];
+}
+
+void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
+{
+ csr_ops[csrno & (CSR_TABLE_SIZE - 1)] = *ops;
+}
+
+/* Predicates */
+static RISCVException fs(CPURISCVState *env, int csrno)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* loose check condition for fcsr in vector extension */
+ if ((csrno == CSR_FCSR) && (env->misa_ext & RVV)) {
+ return RISCV_EXCP_NONE;
+ }
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+#endif
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException vs(CPURISCVState *env, int csrno)
+{
+ if (env->misa_ext & RVV) {
+ return RISCV_EXCP_NONE;
+ }
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException ctr(CPURISCVState *env, int csrno)
+{
+#if !defined(CONFIG_USER_ONLY)
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+
+ if (!cpu->cfg.ext_counters) {
+ /* The Counters extensions is not enabled */
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (riscv_cpu_virt_enabled(env)) {
+ switch (csrno) {
+ case CSR_CYCLE:
+ if (!get_field(env->hcounteren, COUNTEREN_CY) &&
+ get_field(env->mcounteren, COUNTEREN_CY)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ case CSR_TIME:
+ if (!get_field(env->hcounteren, COUNTEREN_TM) &&
+ get_field(env->mcounteren, COUNTEREN_TM)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ case CSR_INSTRET:
+ if (!get_field(env->hcounteren, COUNTEREN_IR) &&
+ get_field(env->mcounteren, COUNTEREN_IR)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
+ if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) &&
+ get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ }
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ switch (csrno) {
+ case CSR_CYCLEH:
+ if (!get_field(env->hcounteren, COUNTEREN_CY) &&
+ get_field(env->mcounteren, COUNTEREN_CY)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ case CSR_TIMEH:
+ if (!get_field(env->hcounteren, COUNTEREN_TM) &&
+ get_field(env->mcounteren, COUNTEREN_TM)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ case CSR_INSTRETH:
+ if (!get_field(env->hcounteren, COUNTEREN_IR) &&
+ get_field(env->mcounteren, COUNTEREN_IR)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
+ if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) &&
+ get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ break;
+ }
+ }
+ }
+#endif
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException ctr32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return ctr(env, csrno);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static RISCVException any(CPURISCVState *env, int csrno)
+{
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException any32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return any(env, csrno);
+
+}
+
+static RISCVException smode(CPURISCVState *env, int csrno)
+{
+ if (riscv_has_ext(env, RVS)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException hmode(CPURISCVState *env, int csrno)
+{
+ if (riscv_has_ext(env, RVS) &&
+ riscv_has_ext(env, RVH)) {
+ /* Hypervisor extension is supported */
+ if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
+ env->priv == PRV_M) {
+ return RISCV_EXCP_NONE;
+ } else {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException hmode32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ if (riscv_cpu_virt_enabled(env)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ } else {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+
+ return hmode(env, csrno);
+
+}
+
+/* Checks if PointerMasking registers could be accessed */
+static RISCVException pointer_masking(CPURISCVState *env, int csrno)
+{
+ /* Check if j-ext is present */
+ if (riscv_has_ext(env, RVJ)) {
+ return RISCV_EXCP_NONE;
+ }
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException pmp(CPURISCVState *env, int csrno)
+{
+ if (riscv_feature(env, RISCV_FEATURE_PMP)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException epmp(CPURISCVState *env, int csrno)
+{
+ if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+#endif
+
+/* User Floating-Point CSRs */
+static RISCVException read_fflags(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = riscv_cpu_get_fflags(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_fflags(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ env->mstatus |= MSTATUS_FS;
+#endif
+ riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_frm(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->frm;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_frm(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ env->mstatus |= MSTATUS_FS;
+#endif
+ env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_fcsr(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT)
+ | (env->frm << FSR_RD_SHIFT);
+ if (vs(env, csrno) >= 0) {
+ *val |= (env->vxrm << FSR_VXRM_SHIFT)
+ | (env->vxsat << FSR_VXSAT_SHIFT);
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_fcsr(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ env->mstatus |= MSTATUS_FS;
+#endif
+ env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
+ if (vs(env, csrno) >= 0) {
+ env->vxrm = (val & FSR_VXRM) >> FSR_VXRM_SHIFT;
+ env->vxsat = (val & FSR_VXSAT) >> FSR_VXSAT_SHIFT;
+ }
+ riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vtype(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vtype;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vl(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vl;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vxrm(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vxrm;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vxrm(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vxrm = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vxsat(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vxsat;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vxsat(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vxsat = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vstart(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vstart;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstart(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vstart = val;
+ return RISCV_EXCP_NONE;
+}
+
+/* User Timers and Counters */
+static RISCVException read_instret(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (icount_enabled()) {
+ *val = icount_get();
+ } else {
+ *val = cpu_get_host_ticks();
+ }
+#else
+ *val = cpu_get_host_ticks();
+#endif
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_instreth(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (icount_enabled()) {
+ *val = icount_get() >> 32;
+ } else {
+ *val = cpu_get_host_ticks() >> 32;
+ }
+#else
+ *val = cpu_get_host_ticks() >> 32;
+#endif
+ return RISCV_EXCP_NONE;
+}
+
+#if defined(CONFIG_USER_ONLY)
+static RISCVException read_time(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = cpu_get_host_ticks();
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_timeh(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = cpu_get_host_ticks() >> 32;
+ return RISCV_EXCP_NONE;
+}
+
+#else /* CONFIG_USER_ONLY */
+
+static RISCVException read_time(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;
+
+ if (!env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ *val = env->rdtime_fn(env->rdtime_fn_arg) + delta;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_timeh(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;
+
+ if (!env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32;
+ return RISCV_EXCP_NONE;
+}
+
+/* Machine constants */
+
+#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP)
+#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP)
+#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
+
+static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
+ VS_MODE_INTERRUPTS;
+static const target_ulong vs_delegable_ints = VS_MODE_INTERRUPTS;
+static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
+ VS_MODE_INTERRUPTS;
+#define DELEGABLE_EXCPS ((1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | \
+ (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | \
+ (1ULL << (RISCV_EXCP_ILLEGAL_INST)) | \
+ (1ULL << (RISCV_EXCP_BREAKPOINT)) | \
+ (1ULL << (RISCV_EXCP_LOAD_ADDR_MIS)) | \
+ (1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT)) | \
+ (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) | \
+ (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) | \
+ (1ULL << (RISCV_EXCP_U_ECALL)) | \
+ (1ULL << (RISCV_EXCP_S_ECALL)) | \
+ (1ULL << (RISCV_EXCP_VS_ECALL)) | \
+ (1ULL << (RISCV_EXCP_M_ECALL)) | \
+ (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | \
+ (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | \
+ (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | \
+ (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | \
+ (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | \
+ (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | \
+ (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)))
+static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS &
+ ~((1ULL << (RISCV_EXCP_S_ECALL)) |
+ (1ULL << (RISCV_EXCP_VS_ECALL)) |
+ (1ULL << (RISCV_EXCP_M_ECALL)) |
+ (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) |
+ (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) |
+ (1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) |
+ (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)));
+static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
+ SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
+ SSTATUS_SUM | SSTATUS_MXR;
+static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
+static const target_ulong hip_writable_mask = MIP_VSSIP;
+static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
+static const target_ulong vsip_writable_mask = MIP_VSSIP;
+
+static const char valid_vm_1_10_32[16] = {
+ [VM_1_10_MBARE] = 1,
+ [VM_1_10_SV32] = 1
+};
+
+static const char valid_vm_1_10_64[16] = {
+ [VM_1_10_MBARE] = 1,
+ [VM_1_10_SV39] = 1,
+ [VM_1_10_SV48] = 1,
+ [VM_1_10_SV57] = 1
+};
+
+/* Machine Information Registers */
+static RISCVException read_zero(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = 0;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mhartid(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mhartid;
+ return RISCV_EXCP_NONE;
+}
+
+/* Machine Trap Setup */
+
+/* We do not store SD explicitly, only compute it on demand. */
+static uint64_t add_status_sd(RISCVMXL xl, uint64_t status)
+{
+ if ((status & MSTATUS_FS) == MSTATUS_FS ||
+ (status & MSTATUS_XS) == MSTATUS_XS) {
+ switch (xl) {
+ case MXL_RV32:
+ return status | MSTATUS32_SD;
+ case MXL_RV64:
+ return status | MSTATUS64_SD;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ return status;
+}
+
+static RISCVException read_mstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static int validate_vm(CPURISCVState *env, target_ulong vm)
+{
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ return valid_vm_1_10_32[vm & 0xf];
+ } else {
+ return valid_vm_1_10_64[vm & 0xf];
+ }
+}
+
+static RISCVException write_mstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus = env->mstatus;
+ uint64_t mask = 0;
+
+ /* flush tlb on mstatus fields that affect VM */
+ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
+ MSTATUS_MPRV | MSTATUS_SUM)) {
+ tlb_flush(env_cpu(env));
+ }
+ mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
+ MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
+ MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
+ MSTATUS_TW;
+
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ /*
+ * RV32: MPV and GVA are not in mstatus. The current plan is to
+ * add them to mstatush. For now, we just don't support it.
+ */
+ mask |= MSTATUS_MPV | MSTATUS_GVA;
+ }
+
+ mstatus = (mstatus & ~mask) | (val & mask);
+
+ if (riscv_cpu_mxl(env) == MXL_RV64) {
+ /* SXL and UXL fields are for now read only */
+ mstatus = set_field(mstatus, MSTATUS64_SXL, MXL_RV64);
+ mstatus = set_field(mstatus, MSTATUS64_UXL, MXL_RV64);
+ }
+ env->mstatus = mstatus;
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mstatush(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mstatus >> 32;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mstatush(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t valh = (uint64_t)val << 32;
+ uint64_t mask = MSTATUS_MPV | MSTATUS_GVA;
+
+ if ((valh ^ env->mstatus) & (MSTATUS_MPV)) {
+ tlb_flush(env_cpu(env));
+ }
+
+ env->mstatus = (env->mstatus & ~mask) | (valh & mask);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_misa(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ target_ulong misa;
+
+ switch (env->misa_mxl) {
+ case MXL_RV32:
+ misa = (target_ulong)MXL_RV32 << 30;
+ break;
+#ifdef TARGET_RISCV64
+ case MXL_RV64:
+ misa = (target_ulong)MXL_RV64 << 62;
+ break;
+#endif
+ default:
+ g_assert_not_reached();
+ }
+
+ *val = misa | env->misa_ext;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_misa(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ if (!riscv_feature(env, RISCV_FEATURE_MISA)) {
+ /* drop write to misa */
+ return RISCV_EXCP_NONE;
+ }
+
+ /* 'I' or 'E' must be present */
+ if (!(val & (RVI | RVE))) {
+ /* It is not, drop write to misa */
+ return RISCV_EXCP_NONE;
+ }
+
+ /* 'E' excludes all other extensions */
+ if (val & RVE) {
+ /* when we support 'E' we can do "val = RVE;" however
+ * for now we just drop writes if 'E' is present.
+ */
+ return RISCV_EXCP_NONE;
+ }
+
+ /*
+ * misa.MXL writes are not supported by QEMU.
+ * Drop writes to those bits.
+ */
+
+ /* Mask extensions that are not supported by this hart */
+ val &= env->misa_ext_mask;
+
+ /* Mask extensions that are not supported by QEMU */
+ val &= (RVI | RVE | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
+
+ /* 'D' depends on 'F', so clear 'D' if 'F' is not present */
+ if ((val & RVD) && !(val & RVF)) {
+ val &= ~RVD;
+ }
+
+ /* Suppress 'C' if next instruction is not aligned
+ * TODO: this should check next_pc
+ */
+ if ((val & RVC) && (GETPC() & ~3) != 0) {
+ val &= ~RVC;
+ }
+
+ /* If nothing changed, do nothing. */
+ if (val == env->misa_ext) {
+ return RISCV_EXCP_NONE;
+ }
+
+ /* flush translation cache */
+ tb_flush(env_cpu(env));
+ env->misa_ext = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_medeleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->medeleg;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_medeleg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->medeleg = (env->medeleg & ~DELEGABLE_EXCPS) | (val & DELEGABLE_EXCPS);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mideleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mideleg;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mideleg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
+ if (riscv_has_ext(env, RVH)) {
+ env->mideleg |= VS_MODE_INTERRUPTS;
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mie(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mie;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mie(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mie = (env->mie & ~all_ints) | (val & all_ints);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mtvec(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mtvec;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mtvec(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+ if ((val & 3) < 2) {
+ env->mtvec = val;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n");
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mcounteren(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mcounteren;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mcounteren(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mcounteren = val;
+ return RISCV_EXCP_NONE;
+}
+
+/* Machine Trap Handling */
+static RISCVException read_mscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mscratch;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mscratch(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mscratch = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mepc(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mepc;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mepc(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mepc = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mcause(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mcause;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mcause(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mcause = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mtval(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mtval;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mtval(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mtval = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_mip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+ /* Allow software control of delegable interrupts not claimed by hardware */
+ target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
+ uint32_t old_mip;
+
+ if (mask) {
+ old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
+ } else {
+ old_mip = env->mip;
+ }
+
+ if (ret_value) {
+ *ret_value = old_mip;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+/* Supervisor Trap Setup */
+static RISCVException read_sstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ target_ulong mask = (sstatus_v1_10_mask);
+
+ /* TODO: Use SXL not MXL. */
+ *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong mask = (sstatus_v1_10_mask);
+ target_ulong newval = (env->mstatus & ~mask) | (val & mask);
+ return write_mstatus(env, CSR_MSTATUS, newval);
+}
+
+static RISCVException read_vsie(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ /* Shift the VS bits to their S bit location in vsie */
+ *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_sie(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (riscv_cpu_virt_enabled(env)) {
+ read_vsie(env, CSR_VSIE, val);
+ } else {
+ *val = env->mie & env->mideleg;
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vsie(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ /* Shift the S bits to their VS bit location in mie */
+ target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
+ ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
+ return write_mie(env, CSR_MIE, newval);
+}
+
+static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
+{
+ if (riscv_cpu_virt_enabled(env)) {
+ write_vsie(env, CSR_VSIE, val);
+ } else {
+ target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
+ (val & S_MODE_INTERRUPTS);
+ write_mie(env, CSR_MIE, newval);
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_stvec(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->stvec;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_stvec(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+ if ((val & 3) < 2) {
+ env->stvec = val;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n");
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_scounteren(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->scounteren;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_scounteren(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->scounteren = val;
+ return RISCV_EXCP_NONE;
+}
+
+/* Supervisor Trap Handling */
+static RISCVException read_sscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->sscratch;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sscratch(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->sscratch = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_sepc(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->sepc;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sepc(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->sepc = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_scause(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->scause;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_scause(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->scause = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_stval(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->stval;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_stval(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->stval = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_vsip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ /* Shift the S bits to their VS bit location in mip */
+ int ret = rmw_mip(env, 0, ret_value, new_value << 1,
+ (write_mask << 1) & vsip_writable_mask & env->hideleg);
+
+ if (ret_value) {
+ *ret_value &= VS_MODE_INTERRUPTS;
+ /* Shift the VS bits to their S bit location in vsip */
+ *ret_value >>= 1;
+ }
+ return ret;
+}
+
+static RISCVException rmw_sip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int ret;
+
+ if (riscv_cpu_virt_enabled(env)) {
+ ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
+ } else {
+ ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
+ write_mask & env->mideleg & sip_writable_mask);
+ }
+
+ if (ret_value) {
+ *ret_value &= env->mideleg;
+ }
+ return ret;
+}
+
+/* Supervisor Protection and Translation */
+static RISCVException read_satp(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ *val = 0;
+ return RISCV_EXCP_NONE;
+ }
+
+ if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ } else {
+ *val = env->satp;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_satp(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong vm, mask, asid;
+
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ vm = validate_vm(env, get_field(val, SATP32_MODE));
+ mask = (val ^ env->satp) & (SATP32_MODE | SATP32_ASID | SATP32_PPN);
+ asid = (val ^ env->satp) & SATP32_ASID;
+ } else {
+ vm = validate_vm(env, get_field(val, SATP64_MODE));
+ mask = (val ^ env->satp) & (SATP64_MODE | SATP64_ASID | SATP64_PPN);
+ asid = (val ^ env->satp) & SATP64_ASID;
+ }
+
+ if (vm && mask) {
+ if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ } else {
+ if (asid) {
+ tlb_flush(env_cpu(env));
+ }
+ env->satp = val;
+ }
+ }
+ return RISCV_EXCP_NONE;
+}
+
+/* Hypervisor Extensions */
+static RISCVException read_hstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->hstatus;
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ /* We only support 64-bit VSXL */
+ *val = set_field(*val, HSTATUS_VSXL, 2);
+ }
+ /* We only support little endian */
+ *val = set_field(*val, HSTATUS_VSBE, 0);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->hstatus = val;
+ if (riscv_cpu_mxl(env) != MXL_RV32 && get_field(val, HSTATUS_VSXL) != 2) {
+ qemu_log_mask(LOG_UNIMP, "QEMU does not support mixed HSXLEN options.");
+ }
+ if (get_field(val, HSTATUS_VSBE) != 0) {
+ qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests.");
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_hedeleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->hedeleg;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hedeleg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->hedeleg = val & vs_delegable_excps;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_hideleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->hideleg;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hideleg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->hideleg = val & vs_delegable_ints;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_hvip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int ret = rmw_mip(env, 0, ret_value, new_value,
+ write_mask & hvip_writable_mask);
+
+ if (ret_value) {
+ *ret_value &= hvip_writable_mask;
+ }
+ return ret;
+}
+
+static RISCVException rmw_hip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int ret = rmw_mip(env, 0, ret_value, new_value,
+ write_mask & hip_writable_mask);
+
+ if (ret_value) {
+ *ret_value &= hip_writable_mask;
+ }
+ return ret;
+}
+
+static RISCVException read_hie(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mie & VS_MODE_INTERRUPTS;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hie(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
+ return write_mie(env, CSR_MIE, newval);
+}
+
+static RISCVException read_hcounteren(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->hcounteren;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hcounteren(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->hcounteren = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hgeie(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ if (val) {
+ qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_htval(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->htval;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_htval(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->htval = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_htinst(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->htinst;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_htinst(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hgeip(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ if (val) {
+ qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_hgatp(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->hgatp;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hgatp(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->hgatp = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_htimedelta(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (!env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ *val = env->htimedelta;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_htimedelta(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ if (!env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val);
+ } else {
+ env->htimedelta = val;
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_htimedeltah(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (!env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ *val = env->htimedelta >> 32;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_htimedeltah(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ if (!env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val);
+ return RISCV_EXCP_NONE;
+}
+
+/* Virtual CSR Registers */
+static RISCVException read_vsstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vsstatus;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vsstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mask = (target_ulong)-1;
+ env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val;
+ return RISCV_EXCP_NONE;
+}
+
+static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->vstvec;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstvec(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vstvec = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vsscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vsscratch;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vsscratch(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vsscratch = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vsepc(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vsepc;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vsepc(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vsepc = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vscause(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vscause;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vscause(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vscause = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vstval(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vstval;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstval(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vstval = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vsatp(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vsatp;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vsatp(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->vsatp = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mtval2(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mtval2;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mtval2(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mtval2 = val;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mtinst(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mtinst;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mtinst(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->mtinst = val;
+ return RISCV_EXCP_NONE;
+}
+
+/* Physical Memory Protection */
+static RISCVException read_mseccfg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = mseccfg_csr_read(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mseccfg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ mseccfg_csr_write(env, val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_pmpcfg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_pmpcfg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_pmpaddr(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_pmpaddr(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val);
+ return RISCV_EXCP_NONE;
+}
+
+/*
+ * Functions to access Pointer Masking feature registers
+ * We have to check if current priv lvl could modify
+ * csr in given mode
+ */
+static bool check_pm_current_disabled(CPURISCVState *env, int csrno)
+{
+ int csr_priv = get_field(csrno, 0x300);
+ int pm_current;
+
+ /*
+ * If priv lvls differ that means we're accessing csr from higher priv lvl,
+ * so allow the access
+ */
+ if (env->priv != csr_priv) {
+ return false;
+ }
+ switch (env->priv) {
+ case PRV_M:
+ pm_current = get_field(env->mmte, M_PM_CURRENT);
+ break;
+ case PRV_S:
+ pm_current = get_field(env->mmte, S_PM_CURRENT);
+ break;
+ case PRV_U:
+ pm_current = get_field(env->mmte, U_PM_CURRENT);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ /* It's same priv lvl, so we allow to modify csr only if pm.current==1 */
+ return !pm_current;
+}
+
+static RISCVException read_mmte(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mmte & MMTE_MASK;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mmte(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+ target_ulong wpri_val = val & MMTE_MASK;
+
+ if (val != wpri_val) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
+ "MMTE: WPRI violation written 0x", val,
+ "vs expected 0x", wpri_val);
+ }
+ /* for machine mode pm.current is hardwired to 1 */
+ wpri_val |= MMTE_M_PM_CURRENT;
+
+ /* hardwiring pm.instruction bit to 0, since it's not supported yet */
+ wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN);
+ env->mmte = wpri_val | PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_smte(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mmte & SMTE_MASK;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_smte(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong wpri_val = val & SMTE_MASK;
+
+ if (val != wpri_val) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
+ "SMTE: WPRI violation written 0x", val,
+ "vs expected 0x", wpri_val);
+ }
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ wpri_val |= (env->mmte & ~SMTE_MASK);
+ write_mmte(env, csrno, wpri_val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_umte(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mmte & UMTE_MASK;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_umte(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong wpri_val = val & UMTE_MASK;
+
+ if (val != wpri_val) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
+ "UMTE: WPRI violation written 0x", val,
+ "vs expected 0x", wpri_val);
+ }
+
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ wpri_val |= (env->mmte & ~UMTE_MASK);
+ write_mmte(env, csrno, wpri_val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mpmmask(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mpmmask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mpmmask(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ env->mpmmask = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_spmmask(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->spmmask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_spmmask(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->spmmask = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_upmmask(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->upmmask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_upmmask(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->upmmask = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mpmbase(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mpmbase;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mpmbase(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ env->mpmbase = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_spmbase(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->spmbase;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_spmbase(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->spmbase = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_upmbase(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->upmbase;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_upmbase(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->upmbase = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+#endif
+
+/*
+ * riscv_csrrw - read and/or update control and status register
+ *
+ * csrr <-> riscv_csrrw(env, csrno, ret_value, 0, 0);
+ * csrrw <-> riscv_csrrw(env, csrno, ret_value, value, -1);
+ * csrrs <-> riscv_csrrw(env, csrno, ret_value, -1, value);
+ * csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value);
+ */
+
+RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ RISCVException ret;
+ target_ulong old_value;
+ RISCVCPU *cpu = env_archcpu(env);
+ int read_only = get_field(csrno, 0xC00) == 3;
+
+ /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
+#if !defined(CONFIG_USER_ONLY)
+ int effective_priv = env->priv;
+
+ if (riscv_has_ext(env, RVH) &&
+ env->priv == PRV_S &&
+ !riscv_cpu_virt_enabled(env)) {
+ /*
+ * We are in S mode without virtualisation, therefore we are in HS Mode.
+ * Add 1 to the effective privledge level to allow us to access the
+ * Hypervisor CSRs.
+ */
+ effective_priv++;
+ }
+
+ if (!env->debugger && (effective_priv < get_field(csrno, 0x300))) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+#endif
+ if (write_mask && read_only) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ /* ensure the CSR extension is enabled. */
+ if (!cpu->cfg.ext_icsr) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ /* check predicate */
+ if (!csr_ops[csrno].predicate) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ ret = csr_ops[csrno].predicate(env, csrno);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ /* execute combined read/write operation if it exists */
+ if (csr_ops[csrno].op) {
+ return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask);
+ }
+
+ /* if no accessor exists then return failure */
+ if (!csr_ops[csrno].read) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ /* read old value */
+ ret = csr_ops[csrno].read(env, csrno, &old_value);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ /* write value if writable and write mask set, otherwise drop writes */
+ if (write_mask) {
+ new_value = (old_value & ~write_mask) | (new_value & write_mask);
+ if (csr_ops[csrno].write) {
+ ret = csr_ops[csrno].write(env, csrno, new_value);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+ }
+ }
+
+ /* return old value */
+ if (ret_value) {
+ *ret_value = old_value;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+/*
+ * Debugger support. If not in user mode, set env->debugger before the
+ * riscv_csrrw call and clear it after the call.
+ */
+RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask)
+{
+ RISCVException ret;
+#if !defined(CONFIG_USER_ONLY)
+ env->debugger = true;
+#endif
+ ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask);
+#if !defined(CONFIG_USER_ONLY)
+ env->debugger = false;
+#endif
+ return ret;
+}
+
+/* Control and Status Register function table */
+riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
+ /* User Floating-Point CSRs */
+ [CSR_FFLAGS] = { "fflags", fs, read_fflags, write_fflags },
+ [CSR_FRM] = { "frm", fs, read_frm, write_frm },
+ [CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
+ /* Vector CSRs */
+ [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart },
+ [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat },
+ [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm },
+ [CSR_VL] = { "vl", vs, read_vl },
+ [CSR_VTYPE] = { "vtype", vs, read_vtype },
+ /* User Timers and Counters */
+ [CSR_CYCLE] = { "cycle", ctr, read_instret },
+ [CSR_INSTRET] = { "instret", ctr, read_instret },
+ [CSR_CYCLEH] = { "cycleh", ctr32, read_instreth },
+ [CSR_INSTRETH] = { "instreth", ctr32, read_instreth },
+
+ /*
+ * In privileged mode, the monitor will have to emulate TIME CSRs only if
+ * rdtime callback is not provided by machine/platform emulation.
+ */
+ [CSR_TIME] = { "time", ctr, read_time },
+ [CSR_TIMEH] = { "timeh", ctr32, read_timeh },
+
+#if !defined(CONFIG_USER_ONLY)
+ /* Machine Timers and Counters */
+ [CSR_MCYCLE] = { "mcycle", any, read_instret },
+ [CSR_MINSTRET] = { "minstret", any, read_instret },
+ [CSR_MCYCLEH] = { "mcycleh", any32, read_instreth },
+ [CSR_MINSTRETH] = { "minstreth", any32, read_instreth },
+
+ /* Machine Information Registers */
+ [CSR_MVENDORID] = { "mvendorid", any, read_zero },
+ [CSR_MARCHID] = { "marchid", any, read_zero },
+ [CSR_MIMPID] = { "mimpid", any, read_zero },
+ [CSR_MHARTID] = { "mhartid", any, read_mhartid },
+
+ /* Machine Trap Setup */
+ [CSR_MSTATUS] = { "mstatus", any, read_mstatus, write_mstatus },
+ [CSR_MISA] = { "misa", any, read_misa, write_misa },
+ [CSR_MIDELEG] = { "mideleg", any, read_mideleg, write_mideleg },
+ [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg },
+ [CSR_MIE] = { "mie", any, read_mie, write_mie },
+ [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec },
+ [CSR_MCOUNTEREN] = { "mcounteren", any, read_mcounteren, write_mcounteren },
+
+ [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush },
+
+ /* Machine Trap Handling */
+ [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch },
+ [CSR_MEPC] = { "mepc", any, read_mepc, write_mepc },
+ [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause },
+ [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval },
+ [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip },
+
+ /* Supervisor Trap Setup */
+ [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus },
+ [CSR_SIE] = { "sie", smode, read_sie, write_sie },
+ [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
+ [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, write_scounteren },
+
+ /* Supervisor Trap Handling */
+ [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch },
+ [CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc },
+ [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause },
+ [CSR_STVAL] = { "stval", smode, read_stval, write_stval },
+ [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip },
+
+ /* Supervisor Protection and Translation */
+ [CSR_SATP] = { "satp", smode, read_satp, write_satp },
+
+ [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus },
+ [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg },
+ [CSR_HIDELEG] = { "hideleg", hmode, read_hideleg, write_hideleg },
+ [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip },
+ [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip },
+ [CSR_HIE] = { "hie", hmode, read_hie, write_hie },
+ [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren },
+ [CSR_HGEIE] = { "hgeie", hmode, read_zero, write_hgeie },
+ [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval },
+ [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst },
+ [CSR_HGEIP] = { "hgeip", hmode, read_zero, write_hgeip },
+ [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp },
+ [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta },
+ [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah },
+
+ [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, write_vsstatus },
+ [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip },
+ [CSR_VSIE] = { "vsie", hmode, read_vsie, write_vsie },
+ [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec },
+ [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, write_vsscratch },
+ [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc },
+ [CSR_VSCAUSE] = { "vscause", hmode, read_vscause, write_vscause },
+ [CSR_VSTVAL] = { "vstval", hmode, read_vstval, write_vstval },
+ [CSR_VSATP] = { "vsatp", hmode, read_vsatp, write_vsatp },
+
+ [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2 },
+ [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst },
+
+ /* Physical Memory Protection */
+ [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg },
+ [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg },
+ [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg },
+ [CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg },
+ [CSR_PMPCFG3] = { "pmpcfg3", pmp, read_pmpcfg, write_pmpcfg },
+ [CSR_PMPADDR0] = { "pmpaddr0", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR1] = { "pmpaddr1", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR2] = { "pmpaddr2", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR3] = { "pmpaddr3", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR4] = { "pmpaddr4", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR5] = { "pmpaddr5", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR6] = { "pmpaddr6", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR7] = { "pmpaddr7", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR8] = { "pmpaddr8", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR9] = { "pmpaddr9", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR10] = { "pmpaddr10", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR11] = { "pmpaddr11", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR12] = { "pmpaddr12", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR13] = { "pmpaddr13", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr },
+
+ /* User Pointer Masking */
+ [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte },
+ [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask, write_upmmask },
+ [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase, write_upmbase },
+ /* Machine Pointer Masking */
+ [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte },
+ [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask, write_mpmmask },
+ [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase, write_mpmbase },
+ /* Supervisor Pointer Masking */
+ [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte },
+ [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask, write_spmmask },
+ [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, write_spmbase },
+
+ /* Performance Counters */
+ [CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_zero },
+ [CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_zero },
+ [CSR_HPMCOUNTER5] = { "hpmcounter5", ctr, read_zero },
+ [CSR_HPMCOUNTER6] = { "hpmcounter6", ctr, read_zero },
+ [CSR_HPMCOUNTER7] = { "hpmcounter7", ctr, read_zero },
+ [CSR_HPMCOUNTER8] = { "hpmcounter8", ctr, read_zero },
+ [CSR_HPMCOUNTER9] = { "hpmcounter9", ctr, read_zero },
+ [CSR_HPMCOUNTER10] = { "hpmcounter10", ctr, read_zero },
+ [CSR_HPMCOUNTER11] = { "hpmcounter11", ctr, read_zero },
+ [CSR_HPMCOUNTER12] = { "hpmcounter12", ctr, read_zero },
+ [CSR_HPMCOUNTER13] = { "hpmcounter13", ctr, read_zero },
+ [CSR_HPMCOUNTER14] = { "hpmcounter14", ctr, read_zero },
+ [CSR_HPMCOUNTER15] = { "hpmcounter15", ctr, read_zero },
+ [CSR_HPMCOUNTER16] = { "hpmcounter16", ctr, read_zero },
+ [CSR_HPMCOUNTER17] = { "hpmcounter17", ctr, read_zero },
+ [CSR_HPMCOUNTER18] = { "hpmcounter18", ctr, read_zero },
+ [CSR_HPMCOUNTER19] = { "hpmcounter19", ctr, read_zero },
+ [CSR_HPMCOUNTER20] = { "hpmcounter20", ctr, read_zero },
+ [CSR_HPMCOUNTER21] = { "hpmcounter21", ctr, read_zero },
+ [CSR_HPMCOUNTER22] = { "hpmcounter22", ctr, read_zero },
+ [CSR_HPMCOUNTER23] = { "hpmcounter23", ctr, read_zero },
+ [CSR_HPMCOUNTER24] = { "hpmcounter24", ctr, read_zero },
+ [CSR_HPMCOUNTER25] = { "hpmcounter25", ctr, read_zero },
+ [CSR_HPMCOUNTER26] = { "hpmcounter26", ctr, read_zero },
+ [CSR_HPMCOUNTER27] = { "hpmcounter27", ctr, read_zero },
+ [CSR_HPMCOUNTER28] = { "hpmcounter28", ctr, read_zero },
+ [CSR_HPMCOUNTER29] = { "hpmcounter29", ctr, read_zero },
+ [CSR_HPMCOUNTER30] = { "hpmcounter30", ctr, read_zero },
+ [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_zero },
+
+ [CSR_MHPMCOUNTER3] = { "mhpmcounter3", any, read_zero },
+ [CSR_MHPMCOUNTER4] = { "mhpmcounter4", any, read_zero },
+ [CSR_MHPMCOUNTER5] = { "mhpmcounter5", any, read_zero },
+ [CSR_MHPMCOUNTER6] = { "mhpmcounter6", any, read_zero },
+ [CSR_MHPMCOUNTER7] = { "mhpmcounter7", any, read_zero },
+ [CSR_MHPMCOUNTER8] = { "mhpmcounter8", any, read_zero },
+ [CSR_MHPMCOUNTER9] = { "mhpmcounter9", any, read_zero },
+ [CSR_MHPMCOUNTER10] = { "mhpmcounter10", any, read_zero },
+ [CSR_MHPMCOUNTER11] = { "mhpmcounter11", any, read_zero },
+ [CSR_MHPMCOUNTER12] = { "mhpmcounter12", any, read_zero },
+ [CSR_MHPMCOUNTER13] = { "mhpmcounter13", any, read_zero },
+ [CSR_MHPMCOUNTER14] = { "mhpmcounter14", any, read_zero },
+ [CSR_MHPMCOUNTER15] = { "mhpmcounter15", any, read_zero },
+ [CSR_MHPMCOUNTER16] = { "mhpmcounter16", any, read_zero },
+ [CSR_MHPMCOUNTER17] = { "mhpmcounter17", any, read_zero },
+ [CSR_MHPMCOUNTER18] = { "mhpmcounter18", any, read_zero },
+ [CSR_MHPMCOUNTER19] = { "mhpmcounter19", any, read_zero },
+ [CSR_MHPMCOUNTER20] = { "mhpmcounter20", any, read_zero },
+ [CSR_MHPMCOUNTER21] = { "mhpmcounter21", any, read_zero },
+ [CSR_MHPMCOUNTER22] = { "mhpmcounter22", any, read_zero },
+ [CSR_MHPMCOUNTER23] = { "mhpmcounter23", any, read_zero },
+ [CSR_MHPMCOUNTER24] = { "mhpmcounter24", any, read_zero },
+ [CSR_MHPMCOUNTER25] = { "mhpmcounter25", any, read_zero },
+ [CSR_MHPMCOUNTER26] = { "mhpmcounter26", any, read_zero },
+ [CSR_MHPMCOUNTER27] = { "mhpmcounter27", any, read_zero },
+ [CSR_MHPMCOUNTER28] = { "mhpmcounter28", any, read_zero },
+ [CSR_MHPMCOUNTER29] = { "mhpmcounter29", any, read_zero },
+ [CSR_MHPMCOUNTER30] = { "mhpmcounter30", any, read_zero },
+ [CSR_MHPMCOUNTER31] = { "mhpmcounter31", any, read_zero },
+
+ [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_zero },
+ [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_zero },
+ [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_zero },
+ [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_zero },
+ [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_zero },
+ [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_zero },
+ [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_zero },
+ [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_zero },
+ [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_zero },
+ [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_zero },
+ [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_zero },
+ [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_zero },
+ [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_zero },
+ [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_zero },
+ [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_zero },
+ [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_zero },
+ [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_zero },
+ [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_zero },
+ [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_zero },
+ [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_zero },
+ [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_zero },
+ [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_zero },
+ [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_zero },
+ [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_zero },
+ [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_zero },
+ [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_zero },
+ [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_zero },
+ [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_zero },
+ [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_zero },
+
+ [CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_zero },
+ [CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_zero },
+ [CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_zero },
+ [CSR_HPMCOUNTER6H] = { "hpmcounter6h", ctr32, read_zero },
+ [CSR_HPMCOUNTER7H] = { "hpmcounter7h", ctr32, read_zero },
+ [CSR_HPMCOUNTER8H] = { "hpmcounter8h", ctr32, read_zero },
+ [CSR_HPMCOUNTER9H] = { "hpmcounter9h", ctr32, read_zero },
+ [CSR_HPMCOUNTER10H] = { "hpmcounter10h", ctr32, read_zero },
+ [CSR_HPMCOUNTER11H] = { "hpmcounter11h", ctr32, read_zero },
+ [CSR_HPMCOUNTER12H] = { "hpmcounter12h", ctr32, read_zero },
+ [CSR_HPMCOUNTER13H] = { "hpmcounter13h", ctr32, read_zero },
+ [CSR_HPMCOUNTER14H] = { "hpmcounter14h", ctr32, read_zero },
+ [CSR_HPMCOUNTER15H] = { "hpmcounter15h", ctr32, read_zero },
+ [CSR_HPMCOUNTER16H] = { "hpmcounter16h", ctr32, read_zero },
+ [CSR_HPMCOUNTER17H] = { "hpmcounter17h", ctr32, read_zero },
+ [CSR_HPMCOUNTER18H] = { "hpmcounter18h", ctr32, read_zero },
+ [CSR_HPMCOUNTER19H] = { "hpmcounter19h", ctr32, read_zero },
+ [CSR_HPMCOUNTER20H] = { "hpmcounter20h", ctr32, read_zero },
+ [CSR_HPMCOUNTER21H] = { "hpmcounter21h", ctr32, read_zero },
+ [CSR_HPMCOUNTER22H] = { "hpmcounter22h", ctr32, read_zero },
+ [CSR_HPMCOUNTER23H] = { "hpmcounter23h", ctr32, read_zero },
+ [CSR_HPMCOUNTER24H] = { "hpmcounter24h", ctr32, read_zero },
+ [CSR_HPMCOUNTER25H] = { "hpmcounter25h", ctr32, read_zero },
+ [CSR_HPMCOUNTER26H] = { "hpmcounter26h", ctr32, read_zero },
+ [CSR_HPMCOUNTER27H] = { "hpmcounter27h", ctr32, read_zero },
+ [CSR_HPMCOUNTER28H] = { "hpmcounter28h", ctr32, read_zero },
+ [CSR_HPMCOUNTER29H] = { "hpmcounter29h", ctr32, read_zero },
+ [CSR_HPMCOUNTER30H] = { "hpmcounter30h", ctr32, read_zero },
+ [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_zero },
+
+ [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", any32, read_zero },
+ [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", any32, read_zero },
+ [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", any32, read_zero },
+ [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", any32, read_zero },
+ [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", any32, read_zero },
+ [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", any32, read_zero },
+ [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", any32, read_zero },
+ [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", any32, read_zero },
+ [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", any32, read_zero },
+ [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", any32, read_zero },
+ [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", any32, read_zero },
+ [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", any32, read_zero },
+ [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", any32, read_zero },
+ [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", any32, read_zero },
+ [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", any32, read_zero },
+ [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", any32, read_zero },
+ [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", any32, read_zero },
+ [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", any32, read_zero },
+ [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", any32, read_zero },
+ [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", any32, read_zero },
+ [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", any32, read_zero },
+ [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", any32, read_zero },
+ [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", any32, read_zero },
+ [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", any32, read_zero },
+ [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", any32, read_zero },
+ [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", any32, read_zero },
+ [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", any32, read_zero },
+ [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", any32, read_zero },
+ [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", any32, read_zero },
+#endif /* !CONFIG_USER_ONLY */
+};
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
new file mode 100644
index 000000000..d62f47090
--- /dev/null
+++ b/target/riscv/fpu_helper.c
@@ -0,0 +1,376 @@
+/*
+ * RISC-V FPU Emulation Helpers for QEMU.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+#include "internals.h"
+
+target_ulong riscv_cpu_get_fflags(CPURISCVState *env)
+{
+ int soft = get_float_exception_flags(&env->fp_status);
+ target_ulong hard = 0;
+
+ hard |= (soft & float_flag_inexact) ? FPEXC_NX : 0;
+ hard |= (soft & float_flag_underflow) ? FPEXC_UF : 0;
+ hard |= (soft & float_flag_overflow) ? FPEXC_OF : 0;
+ hard |= (soft & float_flag_divbyzero) ? FPEXC_DZ : 0;
+ hard |= (soft & float_flag_invalid) ? FPEXC_NV : 0;
+
+ return hard;
+}
+
+void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong hard)
+{
+ int soft = 0;
+
+ soft |= (hard & FPEXC_NX) ? float_flag_inexact : 0;
+ soft |= (hard & FPEXC_UF) ? float_flag_underflow : 0;
+ soft |= (hard & FPEXC_OF) ? float_flag_overflow : 0;
+ soft |= (hard & FPEXC_DZ) ? float_flag_divbyzero : 0;
+ soft |= (hard & FPEXC_NV) ? float_flag_invalid : 0;
+
+ set_float_exception_flags(soft, &env->fp_status);
+}
+
+void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm)
+{
+ int softrm;
+
+ if (rm == 7) {
+ rm = env->frm;
+ }
+ switch (rm) {
+ case 0:
+ softrm = float_round_nearest_even;
+ break;
+ case 1:
+ softrm = float_round_to_zero;
+ break;
+ case 2:
+ softrm = float_round_down;
+ break;
+ case 3:
+ softrm = float_round_up;
+ break;
+ case 4:
+ softrm = float_round_ties_away;
+ break;
+ default:
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+
+ set_float_rounding_mode(softrm, &env->fp_status);
+}
+
+static uint64_t do_fmadd_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2,
+ uint64_t rs3, int flags)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ float32 frs3 = check_nanbox_s(rs3);
+ return nanbox_s(float32_muladd(frs1, frs2, frs3, flags, &env->fp_status));
+}
+
+uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return do_fmadd_s(env, frs1, frs2, frs3, 0);
+}
+
+uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return float64_muladd(frs1, frs2, frs3, 0, &env->fp_status);
+}
+
+uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return do_fmadd_s(env, frs1, frs2, frs3, float_muladd_negate_c);
+}
+
+uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c,
+ &env->fp_status);
+}
+
+uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return do_fmadd_s(env, frs1, frs2, frs3, float_muladd_negate_product);
+}
+
+uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return float64_muladd(frs1, frs2, frs3, float_muladd_negate_product,
+ &env->fp_status);
+}
+
+uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return do_fmadd_s(env, frs1, frs2, frs3,
+ float_muladd_negate_c | float_muladd_negate_product);
+}
+
+uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3)
+{
+ return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c |
+ float_muladd_negate_product, &env->fp_status);
+}
+
+uint64_t helper_fadd_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return nanbox_s(float32_add(frs1, frs2, &env->fp_status));
+}
+
+uint64_t helper_fsub_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return nanbox_s(float32_sub(frs1, frs2, &env->fp_status));
+}
+
+uint64_t helper_fmul_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return nanbox_s(float32_mul(frs1, frs2, &env->fp_status));
+}
+
+uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return nanbox_s(float32_div(frs1, frs2, &env->fp_status));
+}
+
+uint64_t helper_fmin_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return nanbox_s(env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float32_minnum(frs1, frs2, &env->fp_status) :
+ float32_minimum_number(frs1, frs2, &env->fp_status));
+}
+
+uint64_t helper_fmax_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return nanbox_s(env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float32_maxnum(frs1, frs2, &env->fp_status) :
+ float32_maximum_number(frs1, frs2, &env->fp_status));
+}
+
+uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return nanbox_s(float32_sqrt(frs1, &env->fp_status));
+}
+
+target_ulong helper_fle_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return float32_le(frs1, frs2, &env->fp_status);
+}
+
+target_ulong helper_flt_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return float32_lt(frs1, frs2, &env->fp_status);
+}
+
+target_ulong helper_feq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ float32 frs2 = check_nanbox_s(rs2);
+ return float32_eq_quiet(frs1, frs2, &env->fp_status);
+}
+
+target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return float32_to_int32(frs1, &env->fp_status);
+}
+
+target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return (int32_t)float32_to_uint32(frs1, &env->fp_status);
+}
+
+target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return float32_to_int64(frs1, &env->fp_status);
+}
+
+target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return float32_to_uint64(frs1, &env->fp_status);
+}
+
+uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
+{
+ return nanbox_s(int32_to_float32((int32_t)rs1, &env->fp_status));
+}
+
+uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1)
+{
+ return nanbox_s(uint32_to_float32((uint32_t)rs1, &env->fp_status));
+}
+
+uint64_t helper_fcvt_s_l(CPURISCVState *env, target_ulong rs1)
+{
+ return nanbox_s(int64_to_float32(rs1, &env->fp_status));
+}
+
+uint64_t helper_fcvt_s_lu(CPURISCVState *env, target_ulong rs1)
+{
+ return nanbox_s(uint64_to_float32(rs1, &env->fp_status));
+}
+
+target_ulong helper_fclass_s(uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return fclass_s(frs1);
+}
+
+uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_add(frs1, frs2, &env->fp_status);
+}
+
+uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_sub(frs1, frs2, &env->fp_status);
+}
+
+uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_mul(frs1, frs2, &env->fp_status);
+}
+
+uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_div(frs1, frs2, &env->fp_status);
+}
+
+uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float64_minnum(frs1, frs2, &env->fp_status) :
+ float64_minimum_number(frs1, frs2, &env->fp_status);
+}
+
+uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float64_maxnum(frs1, frs2, &env->fp_status) :
+ float64_maximum_number(frs1, frs2, &env->fp_status);
+}
+
+uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
+{
+ return nanbox_s(float64_to_float32(rs1, &env->fp_status));
+}
+
+uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
+{
+ float32 frs1 = check_nanbox_s(rs1);
+ return float32_to_float64(frs1, &env->fp_status);
+}
+
+uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
+{
+ return float64_sqrt(frs1, &env->fp_status);
+}
+
+target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_le(frs1, frs2, &env->fp_status);
+}
+
+target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_lt(frs1, frs2, &env->fp_status);
+}
+
+target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ return float64_eq_quiet(frs1, frs2, &env->fp_status);
+}
+
+target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
+{
+ return float64_to_int32(frs1, &env->fp_status);
+}
+
+target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
+{
+ return (int32_t)float64_to_uint32(frs1, &env->fp_status);
+}
+
+target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
+{
+ return float64_to_int64(frs1, &env->fp_status);
+}
+
+target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
+{
+ return float64_to_uint64(frs1, &env->fp_status);
+}
+
+uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
+{
+ return int32_to_float64((int32_t)rs1, &env->fp_status);
+}
+
+uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1)
+{
+ return uint32_to_float64((uint32_t)rs1, &env->fp_status);
+}
+
+uint64_t helper_fcvt_d_l(CPURISCVState *env, target_ulong rs1)
+{
+ return int64_to_float64(rs1, &env->fp_status);
+}
+
+uint64_t helper_fcvt_d_lu(CPURISCVState *env, target_ulong rs1)
+{
+ return uint64_to_float64(rs1, &env->fp_status);
+}
+
+target_ulong helper_fclass_d(uint64_t frs1)
+{
+ return fclass_d(frs1);
+}
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
new file mode 100644
index 000000000..23429179e
--- /dev/null
+++ b/target/riscv/gdbstub.c
@@ -0,0 +1,212 @@
+/*
+ * RISC-V GDB Server Stub
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "exec/gdbstub.h"
+#include "cpu.h"
+
+int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ if (n < 32) {
+ return gdb_get_regl(mem_buf, env->gpr[n]);
+ } else if (n == 32) {
+ return gdb_get_regl(mem_buf, env->pc);
+ }
+ return 0;
+}
+
+int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ if (n == 0) {
+ /* discard writes to x0 */
+ return sizeof(target_ulong);
+ } else if (n < 32) {
+ env->gpr[n] = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ } else if (n == 32) {
+ env->pc = ldtul_p(mem_buf);
+ return sizeof(target_ulong);
+ }
+ return 0;
+}
+
+static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
+{
+ if (n < 32) {
+ if (env->misa_ext & RVD) {
+ return gdb_get_reg64(buf, env->fpr[n]);
+ }
+ if (env->misa_ext & RVF) {
+ return gdb_get_reg32(buf, env->fpr[n]);
+ }
+ /* there is hole between ft11 and fflags in fpu.xml */
+ } else if (n < 36 && n > 32) {
+ target_ulong val = 0;
+ int result;
+ /*
+ * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP
+ * register 33, so we recalculate the map index.
+ * This also works for CSR_FRM and CSR_FCSR.
+ */
+ result = riscv_csrrw_debug(env, n - 32, &val,
+ 0, 0);
+ if (result == RISCV_EXCP_NONE) {
+ return gdb_get_regl(buf, val);
+ }
+ }
+ return 0;
+}
+
+static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
+ return sizeof(uint64_t);
+ /* there is hole between ft11 and fflags in fpu.xml */
+ } else if (n < 36 && n > 32) {
+ target_ulong val = ldtul_p(mem_buf);
+ int result;
+ /*
+ * CSR_FFLAGS is at index 1 in csr_register, and gdb says it is FP
+ * register 33, so we recalculate the map index.
+ * This also works for CSR_FRM and CSR_FCSR.
+ */
+ result = riscv_csrrw_debug(env, n - 32, NULL,
+ val, -1);
+ if (result == RISCV_EXCP_NONE) {
+ return sizeof(target_ulong);
+ }
+ }
+ return 0;
+}
+
+static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
+{
+ if (n < CSR_TABLE_SIZE) {
+ target_ulong val = 0;
+ int result;
+
+ result = riscv_csrrw_debug(env, n, &val, 0, 0);
+ if (result == RISCV_EXCP_NONE) {
+ return gdb_get_regl(buf, val);
+ }
+ }
+ return 0;
+}
+
+static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+ if (n < CSR_TABLE_SIZE) {
+ target_ulong val = ldtul_p(mem_buf);
+ int result;
+
+ result = riscv_csrrw_debug(env, n, NULL, val, -1);
+ if (result == RISCV_EXCP_NONE) {
+ return sizeof(target_ulong);
+ }
+ }
+ return 0;
+}
+
+static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
+{
+ if (n == 0) {
+#ifdef CONFIG_USER_ONLY
+ return gdb_get_regl(buf, 0);
+#else
+ return gdb_get_regl(buf, cs->priv);
+#endif
+ }
+ return 0;
+}
+
+static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
+{
+ if (n == 0) {
+#ifndef CONFIG_USER_ONLY
+ cs->priv = ldtul_p(mem_buf) & 0x3;
+ if (cs->priv == PRV_H) {
+ cs->priv = PRV_S;
+ }
+#endif
+ return sizeof(target_ulong);
+ }
+ return 0;
+}
+
+static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ GString *s = g_string_new(NULL);
+ riscv_csr_predicate_fn predicate;
+ int bitsize = 16 << env->misa_mxl_max;
+ int i;
+
+ g_string_printf(s, "<?xml version=\"1.0\"?>");
+ g_string_append_printf(s, "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">");
+ g_string_append_printf(s, "<feature name=\"org.gnu.gdb.riscv.csr\">");
+
+ for (i = 0; i < CSR_TABLE_SIZE; i++) {
+ predicate = csr_ops[i].predicate;
+ if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) {
+ if (csr_ops[i].name) {
+ g_string_append_printf(s, "<reg name=\"%s\"", csr_ops[i].name);
+ } else {
+ g_string_append_printf(s, "<reg name=\"csr%03x\"", i);
+ }
+ g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
+ g_string_append_printf(s, " regnum=\"%d\"/>", base_reg + i);
+ }
+ }
+
+ g_string_append_printf(s, "</feature>");
+
+ cpu->dyn_csr_xml = g_string_free(s, false);
+ return CSR_TABLE_SIZE;
+}
+
+void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ if (env->misa_ext & RVD) {
+ gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+ 36, "riscv-64bit-fpu.xml", 0);
+ } else if (env->misa_ext & RVF) {
+ gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+ 36, "riscv-32bit-fpu.xml", 0);
+ }
+#if defined(TARGET_RISCV32)
+ gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
+ 1, "riscv-32bit-virtual.xml", 0);
+#elif defined(TARGET_RISCV64)
+ gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
+ 1, "riscv-64bit-virtual.xml", 0);
+#endif
+
+ gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
+ riscv_gen_dynamic_csr_xml(cs, cs->gdb_num_regs),
+ "riscv-csr.xml", 0);
+}
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
new file mode 100644
index 000000000..c7a537622
--- /dev/null
+++ b/target/riscv/helper.h
@@ -0,0 +1,1149 @@
+/* Exceptions */
+DEF_HELPER_2(raise_exception, noreturn, env, i32)
+
+/* Floating Point - rounding mode */
+DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_WG, void, env, i32)
+
+/* Floating Point - fused */
+DEF_HELPER_FLAGS_4(fmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fnmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+
+/* Floating Point - Single Precision */
+DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmul_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_3(fle_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_2(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_1(fclass_s, TCG_CALL_NO_RWG_SE, tl, i64)
+
+/* Floating Point - Double Precision */
+DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmul_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(fcvt_s_d, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_d_s, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_3(fle_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_2(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64)
+
+/* Bitmanip */
+DEF_HELPER_FLAGS_2(clmul, TCG_CALL_NO_RWG_SE, tl, tl, tl)
+DEF_HELPER_FLAGS_2(clmulr, TCG_CALL_NO_RWG_SE, tl, tl, tl)
+
+/* Special functions */
+DEF_HELPER_2(csrr, tl, env, int)
+DEF_HELPER_3(csrw, void, env, int, tl)
+DEF_HELPER_4(csrrw, tl, env, int, tl, tl)
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(wfi, void, env)
+DEF_HELPER_1(tlb_flush, void, env)
+#endif
+
+/* Hypervisor functions */
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_1(hyp_tlb_flush, void, env)
+DEF_HELPER_1(hyp_gvma_tlb_flush, void, env)
+DEF_HELPER_2(hyp_hlvx_hu, tl, env, tl)
+DEF_HELPER_2(hyp_hlvx_wu, tl, env, tl)
+#endif
+
+/* Vector functions */
+DEF_HELPER_3(vsetvl, tl, env, tl, tl)
+DEF_HELPER_5(vlb_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_b_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlb_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlh_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlh_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlh_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlh_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlh_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlh_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlw_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlw_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlw_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlw_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_b_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vle_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_b_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbu_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhu_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhu_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhu_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhu_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhu_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhu_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwu_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwu_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwu_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwu_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_b_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsb_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsh_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsh_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsh_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsh_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsh_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsh_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsw_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsw_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsw_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vsw_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_b_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_h_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_w_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vse_v_d_mask, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_6(vlsb_v_b, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsb_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsb_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsb_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsh_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsh_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsh_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsw_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsw_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlse_v_b, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlse_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlse_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlse_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsbu_v_b, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsbu_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsbu_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlsbu_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlshu_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlshu_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlshu_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlswu_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlswu_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssb_v_b, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssb_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssb_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssb_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssh_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssh_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssh_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssw_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vssw_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vsse_v_b, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vsse_v_h, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vsse_v_w, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vsse_v_d, void, ptr, ptr, tl, tl, env, i32)
+DEF_HELPER_6(vlxb_v_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxb_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxb_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxb_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxh_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxh_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxh_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxe_v_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxe_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxe_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxe_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxbu_v_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxbu_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxbu_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxbu_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxhu_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxhu_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxhu_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxwu_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vlxwu_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxb_v_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxb_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxb_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxb_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxh_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxh_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxh_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxe_v_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxe_v_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxe_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsxe_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_5(vlbff_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbff_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhff_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vleff_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vleff_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vleff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vleff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbuff_v_b, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbuff_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbuff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlbuff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhuff_v_h, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhuff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlhuff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwuff_v_w, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_5(vlwuff_v_d, void, ptr, ptr, tl, env, i32)
+DEF_HELPER_6(vamoswapw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoswapd_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoaddw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoaddd_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoxorw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoxord_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoandw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoandd_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoorw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoord_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamominw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomind_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomaxw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomaxd_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamominuw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamominud_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomaxuw_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomaxud_v_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoswapw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoaddw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoxorw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoandw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamoorw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamominw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomaxw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamominuw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vamomaxuw_v_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsub_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadd_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vadd_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vadd_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vadd_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsub_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsub_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsub_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsub_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrsub_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrsub_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrsub_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrsub_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_FLAGS_4(vec_rsubs8, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
+DEF_HELPER_FLAGS_4(vec_rsubs16, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
+DEF_HELPER_FLAGS_4(vec_rsubs32, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
+DEF_HELPER_FLAGS_4(vec_rsubs64, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32)
+
+DEF_HELPER_6(vwaddu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwaddu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwaddu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsubu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsubu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsubu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsub_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwaddu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwaddu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwaddu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsubu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsubu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsubu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwadd_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwadd_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwadd_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsub_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsub_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsub_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwaddu_wv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwaddu_wv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwaddu_wv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsubu_wv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsubu_wv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsubu_wv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwadd_wv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwadd_wv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwadd_wv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsub_wv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsub_wv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsub_wv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwaddu_wx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwaddu_wx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwaddu_wx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsubu_wx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsubu_wx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsubu_wx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwadd_wx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwadd_wx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwadd_wx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsub_wx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsub_wx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsub_wx_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vadc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsbc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsbc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsbc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsbc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vvm_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vvm_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vvm_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vvm_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vadc_vxm_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vadc_vxm_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vadc_vxm_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vadc_vxm_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsbc_vxm_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsbc_vxm_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsbc_vxm_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsbc_vxm_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadc_vxm_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadc_vxm_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadc_vxm_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadc_vxm_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vxm_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vxm_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vxm_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsbc_vxm_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vand_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vand_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vand_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vand_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vor_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vor_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vor_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vor_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vxor_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vxor_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vxor_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vxor_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vand_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vand_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vand_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vand_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vor_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vor_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vor_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vor_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vxor_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vxor_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vxor_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vxor_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vsll_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsll_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsll_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsll_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsrl_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsrl_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsrl_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsrl_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsra_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsra_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsra_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsra_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsll_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsll_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsll_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsll_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsrl_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsrl_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsrl_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsrl_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsra_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsra_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsra_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsra_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vnsrl_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnsrl_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnsrl_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnsra_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnsra_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnsra_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnsrl_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnsrl_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnsrl_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnsra_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnsra_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnsra_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vmseq_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmseq_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmseq_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmseq_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsne_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsne_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsne_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsne_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmslt_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmslt_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmslt_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmslt_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsle_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsle_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsle_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmsle_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmseq_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmseq_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmseq_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmseq_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsne_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsne_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsne_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsne_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsltu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmslt_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmslt_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmslt_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmslt_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsleu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsle_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsle_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsle_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsle_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgtu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgtu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgtu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgtu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgt_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgt_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgt_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmsgt_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vminu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vminu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vminu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vminu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmin_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmin_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmin_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmin_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmax_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmax_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmax_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmax_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vminu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vminu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vminu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vminu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmin_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmin_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmin_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmin_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmaxu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmax_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmax_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmax_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmax_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vmul_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmul_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulh_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulh_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulh_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulh_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmul_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmul_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmul_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmul_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulh_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulh_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulh_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulh_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmulhsu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vdivu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdivu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdivu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdivu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdiv_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdiv_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdiv_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdiv_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vremu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vremu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vremu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vremu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrem_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrem_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrem_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrem_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vdivu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdivu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdivu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdivu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdiv_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdiv_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdiv_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vdiv_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vremu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vremu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vremu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vremu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrem_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrem_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrem_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrem_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vwmul_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmulu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmulu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmulu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmulsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmulsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmulsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmul_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmul_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmul_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmulu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmulu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmulu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmulsu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmulsu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmulsu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vmacc_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmacc_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmacc_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmacc_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmacc_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmacc_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsac_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadd_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadd_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadd_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmadd_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnmsub_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vwmaccu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmaccu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmaccu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmacc_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmaccsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmaccsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmaccsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwmaccu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmacc_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmacc_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmacc_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccsu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccsu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccsu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccus_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccus_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwmaccus_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vmerge_vvm_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmerge_vvm_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmerge_vvm_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmerge_vvm_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmerge_vxm_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmerge_vxm_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmerge_vxm_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vmerge_vxm_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_4(vmv_v_v_b, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vmv_v_v_h, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vmv_v_v_w, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vmv_v_v_d, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vmv_v_x_b, void, ptr, i64, env, i32)
+DEF_HELPER_4(vmv_v_x_h, void, ptr, i64, env, i32)
+DEF_HELPER_4(vmv_v_x_w, void, ptr, i64, env, i32)
+DEF_HELPER_4(vmv_v_x_d, void, ptr, i64, env, i32)
+
+DEF_HELPER_6(vsaddu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssubu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssubu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssubu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssubu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssub_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsaddu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsadd_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsadd_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsadd_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsadd_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssubu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssubu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssubu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssubu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssub_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssub_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssub_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssub_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vaadd_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vaadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vaadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vaadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vasub_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vasub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vasub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vasub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vaadd_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vaadd_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vaadd_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vaadd_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vasub_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vasub_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vasub_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vasub_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vsmul_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsmul_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vsmul_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsmul_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsmul_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vsmul_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vwsmaccu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmaccu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmaccu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmacc_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmaccsu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmaccsu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmaccsu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwsmaccu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmacc_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmacc_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmacc_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccsu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccsu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccsu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccus_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccus_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vwsmaccus_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vssrl_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssrl_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssrl_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssrl_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssra_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssra_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssra_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssra_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vssrl_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssrl_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssrl_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssrl_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssra_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssra_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssra_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vssra_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vnclip_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnclip_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnclip_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnclipu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnclipu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnclipu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vnclipu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnclipu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnclipu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnclip_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnclip_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vnclip_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vfadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfadd_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfadd_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfadd_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsub_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsub_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsub_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfrsub_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfrsub_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfrsub_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vfwadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwadd_wv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwadd_wv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwsub_wv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwsub_wv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwadd_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwadd_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwsub_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwsub_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwadd_wf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwadd_wf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwsub_wf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwsub_wf_w, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vfmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmul_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfdiv_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfdiv_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfdiv_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmul_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmul_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmul_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfdiv_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfdiv_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfdiv_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfrdiv_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfrdiv_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfrdiv_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vfwmul_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwmul_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwmul_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwmul_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vfmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmacc_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmacc_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmsac_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmsac_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmadd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmadd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmadd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmsub_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmsub_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfnmsub_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmacc_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmacc_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmsac_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmsac_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmadd_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmadd_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmadd_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmadd_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmadd_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmadd_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmsub_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmsub_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmsub_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmsub_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmsub_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfnmsub_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vfwmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwnmacc_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwnmacc_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwnmsac_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwnmsac_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwnmacc_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwnmacc_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwnmsac_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfwnmsac_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_5(vfsqrt_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfsqrt_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfsqrt_v_d, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vfmin_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmin_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmin_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmax_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmax_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmax_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfmin_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmin_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmin_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmax_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmax_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmax_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vfsgnj_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnj_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnj_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnjn_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnjn_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnjn_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnjx_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnjx_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnjx_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfsgnj_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnj_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnj_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnjn_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnjn_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnjn_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnjx_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnjx_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfsgnjx_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_6(vmfeq_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfeq_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfeq_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfne_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfne_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfne_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmflt_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmflt_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmflt_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfle_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfle_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfle_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmfeq_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfeq_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfeq_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfne_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfne_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfne_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmflt_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmflt_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmflt_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfle_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfle_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfle_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfgt_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfgt_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfgt_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfge_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfge_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmfge_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmford_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmford_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmford_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmford_vf_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmford_vf_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vmford_vf_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_5(vfclass_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfclass_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfclass_v_d, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vfmerge_vfm_h, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmerge_vfm_w, void, ptr, ptr, i64, ptr, env, i32)
+DEF_HELPER_6(vfmerge_vfm_d, void, ptr, ptr, i64, ptr, env, i32)
+
+DEF_HELPER_5(vfcvt_xu_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_xu_f_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_xu_f_v_d, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_x_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_x_f_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_x_f_v_d, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_f_xu_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_f_xu_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_f_xu_v_d, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_f_x_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_f_x_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfcvt_f_x_v_d, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_5(vfwcvt_xu_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_xu_f_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_x_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_x_f_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_f_xu_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_f_xu_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_f_x_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_f_x_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_f_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfwcvt_f_f_v_w, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_5(vfncvt_xu_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_xu_f_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_x_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_x_f_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_f_xu_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_f_xu_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_f_x_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_f_x_v_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_f_f_v_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vfncvt_f_f_v_w, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredsum_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmaxu_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmaxu_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmaxu_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmaxu_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmax_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmax_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmax_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredminu_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredminu_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredminu_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredminu_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmin_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredand_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredand_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredand_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredand_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredor_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredor_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredor_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredor_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredxor_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredxor_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredxor_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vredxor_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vwredsumu_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwredsumu_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwredsumu_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwredsum_vs_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vfredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredsum_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredmax_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredmax_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredmax_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredmin_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredmin_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfredmin_vs_d, void, ptr, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vfwredsum_vs_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vfwredsum_vs_w, void, ptr, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vmand_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmnand_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmandnot_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmxor_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmor_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmnor_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmornot_mm, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vmxnor_mm, void, ptr, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_4(vmpopc_m, tl, ptr, ptr, env, i32)
+
+DEF_HELPER_4(vmfirst_m, tl, ptr, ptr, env, i32)
+
+DEF_HELPER_5(vmsbf_m, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vmsif_m, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(vmsof_m, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_5(viota_m_b, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(viota_m_h, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(viota_m_w, void, ptr, ptr, ptr, env, i32)
+DEF_HELPER_5(viota_m_d, void, ptr, ptr, ptr, env, i32)
+
+DEF_HELPER_4(vid_v_b, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vid_v_h, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vid_v_w, void, ptr, ptr, env, i32)
+DEF_HELPER_4(vid_v_d, void, ptr, ptr, env, i32)
+
+DEF_HELPER_6(vslideup_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslideup_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslideup_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslideup_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslidedown_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslidedown_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslidedown_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslidedown_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1up_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1up_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1up_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1up_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1down_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1down_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1down_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vslide1down_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vrgather_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrgather_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrgather_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrgather_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vrgather_vx_b, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrgather_vx_h, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrgather_vx_w, void, ptr, ptr, tl, ptr, env, i32)
+DEF_HELPER_6(vrgather_vx_d, void, ptr, ptr, tl, ptr, env, i32)
+
+DEF_HELPER_6(vcompress_vm_b, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vcompress_vm_h, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vcompress_vm_w, void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_6(vcompress_vm_d, void, ptr, ptr, ptr, ptr, env, i32)
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
new file mode 100644
index 000000000..2e9212663
--- /dev/null
+++ b/target/riscv/insn16.decode
@@ -0,0 +1,162 @@
+#
+# RISC-V translation routines for the RVXI Base Integer Instruction Set.
+#
+# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2 or later, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Fields:
+%rd 7:5
+%rs1_3 7:3 !function=ex_rvc_register
+%rs2_3 2:3 !function=ex_rvc_register
+%rs2_5 2:5
+
+# Immediates:
+%imm_ci 12:s1 2:5
+%nzuimm_ciw 7:4 11:2 5:1 6:1 !function=ex_shift_2
+%uimm_cl_d 5:2 10:3 !function=ex_shift_3
+%uimm_cl_w 5:1 10:3 6:1 !function=ex_shift_2
+%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1
+%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1
+
+%shimm_6bit 12:1 2:5 !function=ex_rvc_shifti
+%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3
+%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2
+%uimm_6bit_sd 7:3 10:3 !function=ex_shift_3
+%uimm_6bit_sw 7:2 9:4 !function=ex_shift_2
+
+%imm_addi16sp 12:s1 3:2 5:1 2:1 6:1 !function=ex_shift_4
+%imm_lui 12:s1 2:5 !function=ex_shift_12
+
+
+# Argument sets imported from insn32.decode:
+&empty !extern
+&r rd rs1 rs2 !extern
+&i imm rs1 rd !extern
+&s imm rs1 rs2 !extern
+&j imm rd !extern
+&b imm rs2 rs1 !extern
+&u imm rd !extern
+&shift shamt rs1 rd !extern
+
+
+# Formats 16:
+@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd
+@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd
+@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
+@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
+@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3
+@cs_d ... ... ... .. ... .. &s imm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
+@cs_w ... ... ... .. ... .. &s imm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
+@cj ... ........... .. &j imm=%imm_cj
+@cb_z ... ... ... .. ... .. &b imm=%imm_cb rs1=%rs1_3 rs2=0
+
+@c_ldsp ... . ..... ..... .. &i imm=%uimm_6bit_ld rs1=2 %rd
+@c_lwsp ... . ..... ..... .. &i imm=%uimm_6bit_lw rs1=2 %rd
+@c_sdsp ... . ..... ..... .. &s imm=%uimm_6bit_sd rs1=2 rs2=%rs2_5
+@c_swsp ... . ..... ..... .. &s imm=%uimm_6bit_sw rs1=2 rs2=%rs2_5
+@c_li ... . ..... ..... .. &i imm=%imm_ci rs1=0 %rd
+@c_lui ... . ..... ..... .. &u imm=%imm_lui %rd
+@c_jalr ... . ..... ..... .. &i imm=0 rs1=%rd
+@c_mv ... . ..... ..... .. &i imm=0 rs1=%rs2_5 %rd
+
+@c_addi4spn ... . ..... ..... .. &i imm=%nzuimm_ciw rs1=2 rd=%rs2_3
+@c_addi16sp ... . ..... ..... .. &i imm=%imm_addi16sp rs1=2 rd=2
+
+@c_shift ... . .. ... ..... .. \
+ &shift rd=%rs1_3 rs1=%rs1_3 shamt=%shimm_6bit
+@c_shift2 ... . .. ... ..... .. \
+ &shift rd=%rd rs1=%rd shamt=%shimm_6bit
+
+@c_andi ... . .. ... ..... .. &i imm=%imm_ci rs1=%rs1_3 rd=%rs1_3
+
+# *** RV32/64C Standard Extension (Quadrant 0) ***
+{
+ # Opcode of all zeros is illegal; rd != 0, nzuimm == 0 is reserved.
+ illegal 000 000 000 00 --- 00
+ addi 000 ... ... .. ... 00 @c_addi4spn
+}
+fld 001 ... ... .. ... 00 @cl_d
+lw 010 ... ... .. ... 00 @cl_w
+fsd 101 ... ... .. ... 00 @cs_d
+sw 110 ... ... .. ... 00 @cs_w
+
+# *** RV32C and RV64C specific Standard Extension (Quadrant 0) ***
+{
+ ld 011 ... ... .. ... 00 @cl_d
+ flw 011 ... ... .. ... 00 @cl_w
+}
+{
+ sd 111 ... ... .. ... 00 @cs_d
+ fsw 111 ... ... .. ... 00 @cs_w
+}
+
+# *** RV32/64C Standard Extension (Quadrant 1) ***
+addi 000 . ..... ..... 01 @ci
+addi 010 . ..... ..... 01 @c_li
+{
+ illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0
+ addi 011 . 00010 ..... 01 @c_addi16sp
+ lui 011 . ..... ..... 01 @c_lui
+}
+srli 100 . 00 ... ..... 01 @c_shift
+srai 100 . 01 ... ..... 01 @c_shift
+andi 100 . 10 ... ..... 01 @c_andi
+sub 100 0 11 ... 00 ... 01 @cs_2
+xor 100 0 11 ... 01 ... 01 @cs_2
+or 100 0 11 ... 10 ... 01 @cs_2
+and 100 0 11 ... 11 ... 01 @cs_2
+jal 101 ........... 01 @cj rd=0 # C.J
+beq 110 ... ... ..... 01 @cb_z
+bne 111 ... ... ..... 01 @cb_z
+
+# *** RV64C and RV32C specific Standard Extension (Quadrant 1) ***
+{
+ c64_illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0
+ addiw 001 . ..... ..... 01 @ci
+ jal 001 ........... 01 @cj rd=1 # C.JAL
+}
+subw 100 1 11 ... 00 ... 01 @cs_2
+addw 100 1 11 ... 01 ... 01 @cs_2
+
+# *** RV32/64C Standard Extension (Quadrant 2) ***
+slli 000 . ..... ..... 10 @c_shift2
+fld 001 . ..... ..... 10 @c_ldsp
+{
+ illegal 010 - 00000 ----- 10 # c.lwsp, RES rd=0
+ lw 010 . ..... ..... 10 @c_lwsp
+}
+{
+ illegal 100 0 00000 00000 10 # c.jr, RES rs1=0
+ jalr 100 0 ..... 00000 10 @c_jalr rd=0 # C.JR
+ addi 100 0 ..... ..... 10 @c_mv
+}
+{
+ ebreak 100 1 00000 00000 10
+ jalr 100 1 ..... 00000 10 @c_jalr rd=1 # C.JALR
+ add 100 1 ..... ..... 10 @cr
+}
+fsd 101 ...... ..... 10 @c_sdsp
+sw 110 . ..... ..... 10 @c_swsp
+
+# *** RV32C and RV64C specific Standard Extension (Quadrant 2) ***
+{
+ c64_illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0
+ ld 011 . ..... ..... 10 @c_ldsp
+ flw 011 . ..... ..... 10 @c_lwsp
+}
+{
+ sd 111 . ..... ..... 10 @c_sdsp
+ fsw 111 . ..... ..... 10 @c_swsp
+}
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
new file mode 100644
index 000000000..2f251dac1
--- /dev/null
+++ b/target/riscv/insn32.decode
@@ -0,0 +1,728 @@
+#
+# RISC-V translation routines for the RVXI Base Integer Instruction Set.
+#
+# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2 or later, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Fields:
+%rs3 27:5
+%rs2 20:5
+%rs1 15:5
+%rd 7:5
+%sh5 20:5
+
+%sh7 20:7
+%csr 20:12
+%rm 12:3
+%nf 29:3 !function=ex_plus_1
+
+# immediates:
+%imm_i 20:s12
+%imm_s 25:s7 7:5
+%imm_b 31:s1 7:1 25:6 8:4 !function=ex_shift_1
+%imm_j 31:s1 12:8 20:1 21:10 !function=ex_shift_1
+%imm_u 12:s20 !function=ex_shift_12
+
+# Argument sets:
+&empty
+&b imm rs2 rs1
+&i imm rs1 rd
+&j imm rd
+&r rd rs1 rs2
+&r2 rd rs1
+&r2_s rs1 rs2
+&s imm rs1 rs2
+&u imm rd
+&shift shamt rs1 rd
+&atomic aq rl rs2 rs1 rd
+&rmrr vm rd rs1 rs2
+&rmr vm rd rs2
+&rwdvm vm wd rd rs1 rs2
+&r2nfvm vm rd rs1 nf
+&rnfvm vm rd rs1 rs2 nf
+
+# Formats 32:
+@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
+@i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd
+@b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1
+@s ....... ..... ..... ... ..... ....... &s imm=%imm_s %rs2 %rs1
+@u .................... ..... ....... &u imm=%imm_u %rd
+@j .................... ..... ....... &j imm=%imm_j %rd
+
+@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh7 %rs1 %rd
+@csr ............ ..... ... ..... ....... %csr %rs1 %rd
+
+@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd
+@atom_st ..... aq:1 rl:1 ..... ........ ..... ....... &atomic %rs2 %rs1 %rd
+
+@r4_rm ..... .. ..... ..... ... ..... ....... %rs3 %rs2 %rs1 %rm %rd
+@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
+@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd
+@r2 ....... ..... ..... ... ..... ....... &r2 %rs1 %rd
+@r2_nfvm ... ... vm:1 ..... ..... ... ..... ....... &r2nfvm %nf %rs1 %rd
+@r2_vm ...... vm:1 ..... ..... ... ..... ....... &rmr %rs2 %rd
+@r1_vm ...... vm:1 ..... ..... ... ..... ....... %rd
+@r_nfvm ... ... vm:1 ..... ..... ... ..... ....... &rnfvm %nf %rs2 %rs1 %rd
+@r2rd ....... ..... ..... ... ..... ....... %rs2 %rd
+@r_vm ...... vm:1 ..... ..... ... ..... ....... &rmrr %rs2 %rs1 %rd
+@r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd
+@r_vm_0 ...... . ..... ..... ... ..... ....... &rmrr vm=0 %rs2 %rs1 %rd
+@r_wdvm ..... wd:1 vm:1 ..... ..... ... ..... ....... &rwdvm %rs2 %rs1 %rd
+@r2_zimm . zimm:11 ..... ... ..... ....... %rs1 %rd
+@r2_s ....... ..... ..... ... ..... ....... %rs2 %rs1
+
+@hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1
+@hfence_vvma ....... ..... ..... ... ..... ....... %rs2 %rs1
+
+@sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1
+@sfence_vm ....... ..... ..... ... ..... ....... %rs1
+
+# Formats 64:
+@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
+
+# *** Privileged Instructions ***
+ecall 000000000000 00000 000 00000 1110011
+ebreak 000000000001 00000 000 00000 1110011
+uret 0000000 00010 00000 000 00000 1110011
+sret 0001000 00010 00000 000 00000 1110011
+mret 0011000 00010 00000 000 00000 1110011
+wfi 0001000 00101 00000 000 00000 1110011
+sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma
+sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm
+
+# *** RV32I Base Instruction Set ***
+lui .................... ..... 0110111 @u
+auipc .................... ..... 0010111 @u
+jal .................... ..... 1101111 @j
+jalr ............ ..... 000 ..... 1100111 @i
+beq ....... ..... ..... 000 ..... 1100011 @b
+bne ....... ..... ..... 001 ..... 1100011 @b
+blt ....... ..... ..... 100 ..... 1100011 @b
+bge ....... ..... ..... 101 ..... 1100011 @b
+bltu ....... ..... ..... 110 ..... 1100011 @b
+bgeu ....... ..... ..... 111 ..... 1100011 @b
+lb ............ ..... 000 ..... 0000011 @i
+lh ............ ..... 001 ..... 0000011 @i
+lw ............ ..... 010 ..... 0000011 @i
+lbu ............ ..... 100 ..... 0000011 @i
+lhu ............ ..... 101 ..... 0000011 @i
+sb ....... ..... ..... 000 ..... 0100011 @s
+sh ....... ..... ..... 001 ..... 0100011 @s
+sw ....... ..... ..... 010 ..... 0100011 @s
+addi ............ ..... 000 ..... 0010011 @i
+slti ............ ..... 010 ..... 0010011 @i
+sltiu ............ ..... 011 ..... 0010011 @i
+xori ............ ..... 100 ..... 0010011 @i
+ori ............ ..... 110 ..... 0010011 @i
+andi ............ ..... 111 ..... 0010011 @i
+slli 00000. ...... ..... 001 ..... 0010011 @sh
+srli 00000. ...... ..... 101 ..... 0010011 @sh
+srai 01000. ...... ..... 101 ..... 0010011 @sh
+add 0000000 ..... ..... 000 ..... 0110011 @r
+sub 0100000 ..... ..... 000 ..... 0110011 @r
+sll 0000000 ..... ..... 001 ..... 0110011 @r
+slt 0000000 ..... ..... 010 ..... 0110011 @r
+sltu 0000000 ..... ..... 011 ..... 0110011 @r
+xor 0000000 ..... ..... 100 ..... 0110011 @r
+srl 0000000 ..... ..... 101 ..... 0110011 @r
+sra 0100000 ..... ..... 101 ..... 0110011 @r
+or 0000000 ..... ..... 110 ..... 0110011 @r
+and 0000000 ..... ..... 111 ..... 0110011 @r
+fence ---- pred:4 succ:4 ----- 000 ----- 0001111
+fence_i ---- ---- ---- ----- 001 ----- 0001111
+csrrw ............ ..... 001 ..... 1110011 @csr
+csrrs ............ ..... 010 ..... 1110011 @csr
+csrrc ............ ..... 011 ..... 1110011 @csr
+csrrwi ............ ..... 101 ..... 1110011 @csr
+csrrsi ............ ..... 110 ..... 1110011 @csr
+csrrci ............ ..... 111 ..... 1110011 @csr
+
+# *** RV64I Base Instruction Set (in addition to RV32I) ***
+lwu ............ ..... 110 ..... 0000011 @i
+ld ............ ..... 011 ..... 0000011 @i
+sd ....... ..... ..... 011 ..... 0100011 @s
+addiw ............ ..... 000 ..... 0011011 @i
+slliw 0000000 ..... ..... 001 ..... 0011011 @sh5
+srliw 0000000 ..... ..... 101 ..... 0011011 @sh5
+sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5
+addw 0000000 ..... ..... 000 ..... 0111011 @r
+subw 0100000 ..... ..... 000 ..... 0111011 @r
+sllw 0000000 ..... ..... 001 ..... 0111011 @r
+srlw 0000000 ..... ..... 101 ..... 0111011 @r
+sraw 0100000 ..... ..... 101 ..... 0111011 @r
+
+# *** RV32M Standard Extension ***
+mul 0000001 ..... ..... 000 ..... 0110011 @r
+mulh 0000001 ..... ..... 001 ..... 0110011 @r
+mulhsu 0000001 ..... ..... 010 ..... 0110011 @r
+mulhu 0000001 ..... ..... 011 ..... 0110011 @r
+div 0000001 ..... ..... 100 ..... 0110011 @r
+divu 0000001 ..... ..... 101 ..... 0110011 @r
+rem 0000001 ..... ..... 110 ..... 0110011 @r
+remu 0000001 ..... ..... 111 ..... 0110011 @r
+
+# *** RV64M Standard Extension (in addition to RV32M) ***
+mulw 0000001 ..... ..... 000 ..... 0111011 @r
+divw 0000001 ..... ..... 100 ..... 0111011 @r
+divuw 0000001 ..... ..... 101 ..... 0111011 @r
+remw 0000001 ..... ..... 110 ..... 0111011 @r
+remuw 0000001 ..... ..... 111 ..... 0111011 @r
+
+# *** RV32A Standard Extension ***
+lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld
+sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st
+amoswap_w 00001 . . ..... ..... 010 ..... 0101111 @atom_st
+amoadd_w 00000 . . ..... ..... 010 ..... 0101111 @atom_st
+amoxor_w 00100 . . ..... ..... 010 ..... 0101111 @atom_st
+amoand_w 01100 . . ..... ..... 010 ..... 0101111 @atom_st
+amoor_w 01000 . . ..... ..... 010 ..... 0101111 @atom_st
+amomin_w 10000 . . ..... ..... 010 ..... 0101111 @atom_st
+amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st
+amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st
+amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st
+
+# *** RV64A Standard Extension (in addition to RV32A) ***
+lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld
+sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st
+amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st
+amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st
+amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st
+amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st
+amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st
+amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st
+
+# *** RV32F Standard Extension ***
+flw ............ ..... 010 ..... 0000111 @i
+fsw ....... ..... ..... 010 ..... 0100111 @s
+fmadd_s ..... 00 ..... ..... ... ..... 1000011 @r4_rm
+fmsub_s ..... 00 ..... ..... ... ..... 1000111 @r4_rm
+fnmsub_s ..... 00 ..... ..... ... ..... 1001011 @r4_rm
+fnmadd_s ..... 00 ..... ..... ... ..... 1001111 @r4_rm
+fadd_s 0000000 ..... ..... ... ..... 1010011 @r_rm
+fsub_s 0000100 ..... ..... ... ..... 1010011 @r_rm
+fmul_s 0001000 ..... ..... ... ..... 1010011 @r_rm
+fdiv_s 0001100 ..... ..... ... ..... 1010011 @r_rm
+fsqrt_s 0101100 00000 ..... ... ..... 1010011 @r2_rm
+fsgnj_s 0010000 ..... ..... 000 ..... 1010011 @r
+fsgnjn_s 0010000 ..... ..... 001 ..... 1010011 @r
+fsgnjx_s 0010000 ..... ..... 010 ..... 1010011 @r
+fmin_s 0010100 ..... ..... 000 ..... 1010011 @r
+fmax_s 0010100 ..... ..... 001 ..... 1010011 @r
+fcvt_w_s 1100000 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_wu_s 1100000 00001 ..... ... ..... 1010011 @r2_rm
+fmv_x_w 1110000 00000 ..... 000 ..... 1010011 @r2
+feq_s 1010000 ..... ..... 010 ..... 1010011 @r
+flt_s 1010000 ..... ..... 001 ..... 1010011 @r
+fle_s 1010000 ..... ..... 000 ..... 1010011 @r
+fclass_s 1110000 00000 ..... 001 ..... 1010011 @r2
+fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm
+fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2
+
+# *** RV64F Standard Extension (in addition to RV32F) ***
+fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm
+fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm
+
+# *** RV32D Standard Extension ***
+fld ............ ..... 011 ..... 0000111 @i
+fsd ....... ..... ..... 011 ..... 0100111 @s
+fmadd_d ..... 01 ..... ..... ... ..... 1000011 @r4_rm
+fmsub_d ..... 01 ..... ..... ... ..... 1000111 @r4_rm
+fnmsub_d ..... 01 ..... ..... ... ..... 1001011 @r4_rm
+fnmadd_d ..... 01 ..... ..... ... ..... 1001111 @r4_rm
+fadd_d 0000001 ..... ..... ... ..... 1010011 @r_rm
+fsub_d 0000101 ..... ..... ... ..... 1010011 @r_rm
+fmul_d 0001001 ..... ..... ... ..... 1010011 @r_rm
+fdiv_d 0001101 ..... ..... ... ..... 1010011 @r_rm
+fsqrt_d 0101101 00000 ..... ... ..... 1010011 @r2_rm
+fsgnj_d 0010001 ..... ..... 000 ..... 1010011 @r
+fsgnjn_d 0010001 ..... ..... 001 ..... 1010011 @r
+fsgnjx_d 0010001 ..... ..... 010 ..... 1010011 @r
+fmin_d 0010101 ..... ..... 000 ..... 1010011 @r
+fmax_d 0010101 ..... ..... 001 ..... 1010011 @r
+fcvt_s_d 0100000 00001 ..... ... ..... 1010011 @r2_rm
+fcvt_d_s 0100001 00000 ..... ... ..... 1010011 @r2_rm
+feq_d 1010001 ..... ..... 010 ..... 1010011 @r
+flt_d 1010001 ..... ..... 001 ..... 1010011 @r
+fle_d 1010001 ..... ..... 000 ..... 1010011 @r
+fclass_d 1110001 00000 ..... 001 ..... 1010011 @r2
+fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm
+fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm
+fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm
+
+# *** RV64D Standard Extension (in addition to RV32D) ***
+fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm
+fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2
+fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm
+fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2
+
+# *** RV32H Base Instruction Set ***
+hlv_b 0110000 00000 ..... 100 ..... 1110011 @r2
+hlv_bu 0110000 00001 ..... 100 ..... 1110011 @r2
+hlv_h 0110010 00000 ..... 100 ..... 1110011 @r2
+hlv_hu 0110010 00001 ..... 100 ..... 1110011 @r2
+hlvx_hu 0110010 00011 ..... 100 ..... 1110011 @r2
+hlv_w 0110100 00000 ..... 100 ..... 1110011 @r2
+hlvx_wu 0110100 00011 ..... 100 ..... 1110011 @r2
+hsv_b 0110001 ..... ..... 100 00000 1110011 @r2_s
+hsv_h 0110011 ..... ..... 100 00000 1110011 @r2_s
+hsv_w 0110101 ..... ..... 100 00000 1110011 @r2_s
+hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma
+hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma
+
+# *** RV64H Base Instruction Set ***
+hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2
+hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2
+hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s
+
+# *** Vector loads and stores are encoded within LOADFP/STORE-FP ***
+vlb_v ... 100 . 00000 ..... 000 ..... 0000111 @r2_nfvm
+vlh_v ... 100 . 00000 ..... 101 ..... 0000111 @r2_nfvm
+vlw_v ... 100 . 00000 ..... 110 ..... 0000111 @r2_nfvm
+vle_v ... 000 . 00000 ..... 111 ..... 0000111 @r2_nfvm
+vlbu_v ... 000 . 00000 ..... 000 ..... 0000111 @r2_nfvm
+vlhu_v ... 000 . 00000 ..... 101 ..... 0000111 @r2_nfvm
+vlwu_v ... 000 . 00000 ..... 110 ..... 0000111 @r2_nfvm
+vlbff_v ... 100 . 10000 ..... 000 ..... 0000111 @r2_nfvm
+vlhff_v ... 100 . 10000 ..... 101 ..... 0000111 @r2_nfvm
+vlwff_v ... 100 . 10000 ..... 110 ..... 0000111 @r2_nfvm
+vleff_v ... 000 . 10000 ..... 111 ..... 0000111 @r2_nfvm
+vlbuff_v ... 000 . 10000 ..... 000 ..... 0000111 @r2_nfvm
+vlhuff_v ... 000 . 10000 ..... 101 ..... 0000111 @r2_nfvm
+vlwuff_v ... 000 . 10000 ..... 110 ..... 0000111 @r2_nfvm
+vsb_v ... 000 . 00000 ..... 000 ..... 0100111 @r2_nfvm
+vsh_v ... 000 . 00000 ..... 101 ..... 0100111 @r2_nfvm
+vsw_v ... 000 . 00000 ..... 110 ..... 0100111 @r2_nfvm
+vse_v ... 000 . 00000 ..... 111 ..... 0100111 @r2_nfvm
+
+vlsb_v ... 110 . ..... ..... 000 ..... 0000111 @r_nfvm
+vlsh_v ... 110 . ..... ..... 101 ..... 0000111 @r_nfvm
+vlsw_v ... 110 . ..... ..... 110 ..... 0000111 @r_nfvm
+vlse_v ... 010 . ..... ..... 111 ..... 0000111 @r_nfvm
+vlsbu_v ... 010 . ..... ..... 000 ..... 0000111 @r_nfvm
+vlshu_v ... 010 . ..... ..... 101 ..... 0000111 @r_nfvm
+vlswu_v ... 010 . ..... ..... 110 ..... 0000111 @r_nfvm
+vssb_v ... 010 . ..... ..... 000 ..... 0100111 @r_nfvm
+vssh_v ... 010 . ..... ..... 101 ..... 0100111 @r_nfvm
+vssw_v ... 010 . ..... ..... 110 ..... 0100111 @r_nfvm
+vsse_v ... 010 . ..... ..... 111 ..... 0100111 @r_nfvm
+
+vlxb_v ... 111 . ..... ..... 000 ..... 0000111 @r_nfvm
+vlxh_v ... 111 . ..... ..... 101 ..... 0000111 @r_nfvm
+vlxw_v ... 111 . ..... ..... 110 ..... 0000111 @r_nfvm
+vlxe_v ... 011 . ..... ..... 111 ..... 0000111 @r_nfvm
+vlxbu_v ... 011 . ..... ..... 000 ..... 0000111 @r_nfvm
+vlxhu_v ... 011 . ..... ..... 101 ..... 0000111 @r_nfvm
+vlxwu_v ... 011 . ..... ..... 110 ..... 0000111 @r_nfvm
+# Vector ordered-indexed and unordered-indexed store insns.
+vsxb_v ... -11 . ..... ..... 000 ..... 0100111 @r_nfvm
+vsxh_v ... -11 . ..... ..... 101 ..... 0100111 @r_nfvm
+vsxw_v ... -11 . ..... ..... 110 ..... 0100111 @r_nfvm
+vsxe_v ... -11 . ..... ..... 111 ..... 0100111 @r_nfvm
+
+#*** Vector AMO operations are encoded under the standard AMO major opcode ***
+vamoswapw_v 00001 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamoaddw_v 00000 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamoxorw_v 00100 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamoandw_v 01100 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamoorw_v 01000 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamominw_v 10000 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamomaxw_v 10100 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamominuw_v 11000 . . ..... ..... 110 ..... 0101111 @r_wdvm
+vamomaxuw_v 11100 . . ..... ..... 110 ..... 0101111 @r_wdvm
+
+# *** new major opcode OP-V ***
+vadd_vv 000000 . ..... ..... 000 ..... 1010111 @r_vm
+vadd_vx 000000 . ..... ..... 100 ..... 1010111 @r_vm
+vadd_vi 000000 . ..... ..... 011 ..... 1010111 @r_vm
+vsub_vv 000010 . ..... ..... 000 ..... 1010111 @r_vm
+vsub_vx 000010 . ..... ..... 100 ..... 1010111 @r_vm
+vrsub_vx 000011 . ..... ..... 100 ..... 1010111 @r_vm
+vrsub_vi 000011 . ..... ..... 011 ..... 1010111 @r_vm
+vwaddu_vv 110000 . ..... ..... 010 ..... 1010111 @r_vm
+vwaddu_vx 110000 . ..... ..... 110 ..... 1010111 @r_vm
+vwadd_vv 110001 . ..... ..... 010 ..... 1010111 @r_vm
+vwadd_vx 110001 . ..... ..... 110 ..... 1010111 @r_vm
+vwsubu_vv 110010 . ..... ..... 010 ..... 1010111 @r_vm
+vwsubu_vx 110010 . ..... ..... 110 ..... 1010111 @r_vm
+vwsub_vv 110011 . ..... ..... 010 ..... 1010111 @r_vm
+vwsub_vx 110011 . ..... ..... 110 ..... 1010111 @r_vm
+vwaddu_wv 110100 . ..... ..... 010 ..... 1010111 @r_vm
+vwaddu_wx 110100 . ..... ..... 110 ..... 1010111 @r_vm
+vwadd_wv 110101 . ..... ..... 010 ..... 1010111 @r_vm
+vwadd_wx 110101 . ..... ..... 110 ..... 1010111 @r_vm
+vwsubu_wv 110110 . ..... ..... 010 ..... 1010111 @r_vm
+vwsubu_wx 110110 . ..... ..... 110 ..... 1010111 @r_vm
+vwsub_wv 110111 . ..... ..... 010 ..... 1010111 @r_vm
+vwsub_wx 110111 . ..... ..... 110 ..... 1010111 @r_vm
+vadc_vvm 010000 1 ..... ..... 000 ..... 1010111 @r_vm_1
+vadc_vxm 010000 1 ..... ..... 100 ..... 1010111 @r_vm_1
+vadc_vim 010000 1 ..... ..... 011 ..... 1010111 @r_vm_1
+vmadc_vvm 010001 1 ..... ..... 000 ..... 1010111 @r_vm_1
+vmadc_vxm 010001 1 ..... ..... 100 ..... 1010111 @r_vm_1
+vmadc_vim 010001 1 ..... ..... 011 ..... 1010111 @r_vm_1
+vsbc_vvm 010010 1 ..... ..... 000 ..... 1010111 @r_vm_1
+vsbc_vxm 010010 1 ..... ..... 100 ..... 1010111 @r_vm_1
+vmsbc_vvm 010011 1 ..... ..... 000 ..... 1010111 @r_vm_1
+vmsbc_vxm 010011 1 ..... ..... 100 ..... 1010111 @r_vm_1
+vand_vv 001001 . ..... ..... 000 ..... 1010111 @r_vm
+vand_vx 001001 . ..... ..... 100 ..... 1010111 @r_vm
+vand_vi 001001 . ..... ..... 011 ..... 1010111 @r_vm
+vor_vv 001010 . ..... ..... 000 ..... 1010111 @r_vm
+vor_vx 001010 . ..... ..... 100 ..... 1010111 @r_vm
+vor_vi 001010 . ..... ..... 011 ..... 1010111 @r_vm
+vxor_vv 001011 . ..... ..... 000 ..... 1010111 @r_vm
+vxor_vx 001011 . ..... ..... 100 ..... 1010111 @r_vm
+vxor_vi 001011 . ..... ..... 011 ..... 1010111 @r_vm
+vsll_vv 100101 . ..... ..... 000 ..... 1010111 @r_vm
+vsll_vx 100101 . ..... ..... 100 ..... 1010111 @r_vm
+vsll_vi 100101 . ..... ..... 011 ..... 1010111 @r_vm
+vsrl_vv 101000 . ..... ..... 000 ..... 1010111 @r_vm
+vsrl_vx 101000 . ..... ..... 100 ..... 1010111 @r_vm
+vsrl_vi 101000 . ..... ..... 011 ..... 1010111 @r_vm
+vsra_vv 101001 . ..... ..... 000 ..... 1010111 @r_vm
+vsra_vx 101001 . ..... ..... 100 ..... 1010111 @r_vm
+vsra_vi 101001 . ..... ..... 011 ..... 1010111 @r_vm
+vnsrl_vv 101100 . ..... ..... 000 ..... 1010111 @r_vm
+vnsrl_vx 101100 . ..... ..... 100 ..... 1010111 @r_vm
+vnsrl_vi 101100 . ..... ..... 011 ..... 1010111 @r_vm
+vnsra_vv 101101 . ..... ..... 000 ..... 1010111 @r_vm
+vnsra_vx 101101 . ..... ..... 100 ..... 1010111 @r_vm
+vnsra_vi 101101 . ..... ..... 011 ..... 1010111 @r_vm
+vmseq_vv 011000 . ..... ..... 000 ..... 1010111 @r_vm
+vmseq_vx 011000 . ..... ..... 100 ..... 1010111 @r_vm
+vmseq_vi 011000 . ..... ..... 011 ..... 1010111 @r_vm
+vmsne_vv 011001 . ..... ..... 000 ..... 1010111 @r_vm
+vmsne_vx 011001 . ..... ..... 100 ..... 1010111 @r_vm
+vmsne_vi 011001 . ..... ..... 011 ..... 1010111 @r_vm
+vmsltu_vv 011010 . ..... ..... 000 ..... 1010111 @r_vm
+vmsltu_vx 011010 . ..... ..... 100 ..... 1010111 @r_vm
+vmslt_vv 011011 . ..... ..... 000 ..... 1010111 @r_vm
+vmslt_vx 011011 . ..... ..... 100 ..... 1010111 @r_vm
+vmsleu_vv 011100 . ..... ..... 000 ..... 1010111 @r_vm
+vmsleu_vx 011100 . ..... ..... 100 ..... 1010111 @r_vm
+vmsleu_vi 011100 . ..... ..... 011 ..... 1010111 @r_vm
+vmsle_vv 011101 . ..... ..... 000 ..... 1010111 @r_vm
+vmsle_vx 011101 . ..... ..... 100 ..... 1010111 @r_vm
+vmsle_vi 011101 . ..... ..... 011 ..... 1010111 @r_vm
+vmsgtu_vx 011110 . ..... ..... 100 ..... 1010111 @r_vm
+vmsgtu_vi 011110 . ..... ..... 011 ..... 1010111 @r_vm
+vmsgt_vx 011111 . ..... ..... 100 ..... 1010111 @r_vm
+vmsgt_vi 011111 . ..... ..... 011 ..... 1010111 @r_vm
+vminu_vv 000100 . ..... ..... 000 ..... 1010111 @r_vm
+vminu_vx 000100 . ..... ..... 100 ..... 1010111 @r_vm
+vmin_vv 000101 . ..... ..... 000 ..... 1010111 @r_vm
+vmin_vx 000101 . ..... ..... 100 ..... 1010111 @r_vm
+vmaxu_vv 000110 . ..... ..... 000 ..... 1010111 @r_vm
+vmaxu_vx 000110 . ..... ..... 100 ..... 1010111 @r_vm
+vmax_vv 000111 . ..... ..... 000 ..... 1010111 @r_vm
+vmax_vx 000111 . ..... ..... 100 ..... 1010111 @r_vm
+vmul_vv 100101 . ..... ..... 010 ..... 1010111 @r_vm
+vmul_vx 100101 . ..... ..... 110 ..... 1010111 @r_vm
+vmulh_vv 100111 . ..... ..... 010 ..... 1010111 @r_vm
+vmulh_vx 100111 . ..... ..... 110 ..... 1010111 @r_vm
+vmulhu_vv 100100 . ..... ..... 010 ..... 1010111 @r_vm
+vmulhu_vx 100100 . ..... ..... 110 ..... 1010111 @r_vm
+vmulhsu_vv 100110 . ..... ..... 010 ..... 1010111 @r_vm
+vmulhsu_vx 100110 . ..... ..... 110 ..... 1010111 @r_vm
+vdivu_vv 100000 . ..... ..... 010 ..... 1010111 @r_vm
+vdivu_vx 100000 . ..... ..... 110 ..... 1010111 @r_vm
+vdiv_vv 100001 . ..... ..... 010 ..... 1010111 @r_vm
+vdiv_vx 100001 . ..... ..... 110 ..... 1010111 @r_vm
+vremu_vv 100010 . ..... ..... 010 ..... 1010111 @r_vm
+vremu_vx 100010 . ..... ..... 110 ..... 1010111 @r_vm
+vrem_vv 100011 . ..... ..... 010 ..... 1010111 @r_vm
+vrem_vx 100011 . ..... ..... 110 ..... 1010111 @r_vm
+vwmulu_vv 111000 . ..... ..... 010 ..... 1010111 @r_vm
+vwmulu_vx 111000 . ..... ..... 110 ..... 1010111 @r_vm
+vwmulsu_vv 111010 . ..... ..... 010 ..... 1010111 @r_vm
+vwmulsu_vx 111010 . ..... ..... 110 ..... 1010111 @r_vm
+vwmul_vv 111011 . ..... ..... 010 ..... 1010111 @r_vm
+vwmul_vx 111011 . ..... ..... 110 ..... 1010111 @r_vm
+vmacc_vv 101101 . ..... ..... 010 ..... 1010111 @r_vm
+vmacc_vx 101101 . ..... ..... 110 ..... 1010111 @r_vm
+vnmsac_vv 101111 . ..... ..... 010 ..... 1010111 @r_vm
+vnmsac_vx 101111 . ..... ..... 110 ..... 1010111 @r_vm
+vmadd_vv 101001 . ..... ..... 010 ..... 1010111 @r_vm
+vmadd_vx 101001 . ..... ..... 110 ..... 1010111 @r_vm
+vnmsub_vv 101011 . ..... ..... 010 ..... 1010111 @r_vm
+vnmsub_vx 101011 . ..... ..... 110 ..... 1010111 @r_vm
+vwmaccu_vv 111100 . ..... ..... 010 ..... 1010111 @r_vm
+vwmaccu_vx 111100 . ..... ..... 110 ..... 1010111 @r_vm
+vwmacc_vv 111101 . ..... ..... 010 ..... 1010111 @r_vm
+vwmacc_vx 111101 . ..... ..... 110 ..... 1010111 @r_vm
+vwmaccsu_vv 111110 . ..... ..... 010 ..... 1010111 @r_vm
+vwmaccsu_vx 111110 . ..... ..... 110 ..... 1010111 @r_vm
+vwmaccus_vx 111111 . ..... ..... 110 ..... 1010111 @r_vm
+vmv_v_v 010111 1 00000 ..... 000 ..... 1010111 @r2
+vmv_v_x 010111 1 00000 ..... 100 ..... 1010111 @r2
+vmv_v_i 010111 1 00000 ..... 011 ..... 1010111 @r2
+vmerge_vvm 010111 0 ..... ..... 000 ..... 1010111 @r_vm_0
+vmerge_vxm 010111 0 ..... ..... 100 ..... 1010111 @r_vm_0
+vmerge_vim 010111 0 ..... ..... 011 ..... 1010111 @r_vm_0
+vsaddu_vv 100000 . ..... ..... 000 ..... 1010111 @r_vm
+vsaddu_vx 100000 . ..... ..... 100 ..... 1010111 @r_vm
+vsaddu_vi 100000 . ..... ..... 011 ..... 1010111 @r_vm
+vsadd_vv 100001 . ..... ..... 000 ..... 1010111 @r_vm
+vsadd_vx 100001 . ..... ..... 100 ..... 1010111 @r_vm
+vsadd_vi 100001 . ..... ..... 011 ..... 1010111 @r_vm
+vssubu_vv 100010 . ..... ..... 000 ..... 1010111 @r_vm
+vssubu_vx 100010 . ..... ..... 100 ..... 1010111 @r_vm
+vssub_vv 100011 . ..... ..... 000 ..... 1010111 @r_vm
+vssub_vx 100011 . ..... ..... 100 ..... 1010111 @r_vm
+vaadd_vv 100100 . ..... ..... 000 ..... 1010111 @r_vm
+vaadd_vx 100100 . ..... ..... 100 ..... 1010111 @r_vm
+vaadd_vi 100100 . ..... ..... 011 ..... 1010111 @r_vm
+vasub_vv 100110 . ..... ..... 000 ..... 1010111 @r_vm
+vasub_vx 100110 . ..... ..... 100 ..... 1010111 @r_vm
+vsmul_vv 100111 . ..... ..... 000 ..... 1010111 @r_vm
+vsmul_vx 100111 . ..... ..... 100 ..... 1010111 @r_vm
+vwsmaccu_vv 111100 . ..... ..... 000 ..... 1010111 @r_vm
+vwsmaccu_vx 111100 . ..... ..... 100 ..... 1010111 @r_vm
+vwsmacc_vv 111101 . ..... ..... 000 ..... 1010111 @r_vm
+vwsmacc_vx 111101 . ..... ..... 100 ..... 1010111 @r_vm
+vwsmaccsu_vv 111110 . ..... ..... 000 ..... 1010111 @r_vm
+vwsmaccsu_vx 111110 . ..... ..... 100 ..... 1010111 @r_vm
+vwsmaccus_vx 111111 . ..... ..... 100 ..... 1010111 @r_vm
+vssrl_vv 101010 . ..... ..... 000 ..... 1010111 @r_vm
+vssrl_vx 101010 . ..... ..... 100 ..... 1010111 @r_vm
+vssrl_vi 101010 . ..... ..... 011 ..... 1010111 @r_vm
+vssra_vv 101011 . ..... ..... 000 ..... 1010111 @r_vm
+vssra_vx 101011 . ..... ..... 100 ..... 1010111 @r_vm
+vssra_vi 101011 . ..... ..... 011 ..... 1010111 @r_vm
+vnclipu_vv 101110 . ..... ..... 000 ..... 1010111 @r_vm
+vnclipu_vx 101110 . ..... ..... 100 ..... 1010111 @r_vm
+vnclipu_vi 101110 . ..... ..... 011 ..... 1010111 @r_vm
+vnclip_vv 101111 . ..... ..... 000 ..... 1010111 @r_vm
+vnclip_vx 101111 . ..... ..... 100 ..... 1010111 @r_vm
+vnclip_vi 101111 . ..... ..... 011 ..... 1010111 @r_vm
+vfadd_vv 000000 . ..... ..... 001 ..... 1010111 @r_vm
+vfadd_vf 000000 . ..... ..... 101 ..... 1010111 @r_vm
+vfsub_vv 000010 . ..... ..... 001 ..... 1010111 @r_vm
+vfsub_vf 000010 . ..... ..... 101 ..... 1010111 @r_vm
+vfrsub_vf 100111 . ..... ..... 101 ..... 1010111 @r_vm
+vfwadd_vv 110000 . ..... ..... 001 ..... 1010111 @r_vm
+vfwadd_vf 110000 . ..... ..... 101 ..... 1010111 @r_vm
+vfwadd_wv 110100 . ..... ..... 001 ..... 1010111 @r_vm
+vfwadd_wf 110100 . ..... ..... 101 ..... 1010111 @r_vm
+vfwsub_vv 110010 . ..... ..... 001 ..... 1010111 @r_vm
+vfwsub_vf 110010 . ..... ..... 101 ..... 1010111 @r_vm
+vfwsub_wv 110110 . ..... ..... 001 ..... 1010111 @r_vm
+vfwsub_wf 110110 . ..... ..... 101 ..... 1010111 @r_vm
+vfmul_vv 100100 . ..... ..... 001 ..... 1010111 @r_vm
+vfmul_vf 100100 . ..... ..... 101 ..... 1010111 @r_vm
+vfdiv_vv 100000 . ..... ..... 001 ..... 1010111 @r_vm
+vfdiv_vf 100000 . ..... ..... 101 ..... 1010111 @r_vm
+vfrdiv_vf 100001 . ..... ..... 101 ..... 1010111 @r_vm
+vfwmul_vv 111000 . ..... ..... 001 ..... 1010111 @r_vm
+vfwmul_vf 111000 . ..... ..... 101 ..... 1010111 @r_vm
+vfmacc_vv 101100 . ..... ..... 001 ..... 1010111 @r_vm
+vfnmacc_vv 101101 . ..... ..... 001 ..... 1010111 @r_vm
+vfnmacc_vf 101101 . ..... ..... 101 ..... 1010111 @r_vm
+vfmacc_vf 101100 . ..... ..... 101 ..... 1010111 @r_vm
+vfmsac_vv 101110 . ..... ..... 001 ..... 1010111 @r_vm
+vfmsac_vf 101110 . ..... ..... 101 ..... 1010111 @r_vm
+vfnmsac_vv 101111 . ..... ..... 001 ..... 1010111 @r_vm
+vfnmsac_vf 101111 . ..... ..... 101 ..... 1010111 @r_vm
+vfmadd_vv 101000 . ..... ..... 001 ..... 1010111 @r_vm
+vfmadd_vf 101000 . ..... ..... 101 ..... 1010111 @r_vm
+vfnmadd_vv 101001 . ..... ..... 001 ..... 1010111 @r_vm
+vfnmadd_vf 101001 . ..... ..... 101 ..... 1010111 @r_vm
+vfmsub_vv 101010 . ..... ..... 001 ..... 1010111 @r_vm
+vfmsub_vf 101010 . ..... ..... 101 ..... 1010111 @r_vm
+vfnmsub_vv 101011 . ..... ..... 001 ..... 1010111 @r_vm
+vfnmsub_vf 101011 . ..... ..... 101 ..... 1010111 @r_vm
+vfwmacc_vv 111100 . ..... ..... 001 ..... 1010111 @r_vm
+vfwmacc_vf 111100 . ..... ..... 101 ..... 1010111 @r_vm
+vfwnmacc_vv 111101 . ..... ..... 001 ..... 1010111 @r_vm
+vfwnmacc_vf 111101 . ..... ..... 101 ..... 1010111 @r_vm
+vfwmsac_vv 111110 . ..... ..... 001 ..... 1010111 @r_vm
+vfwmsac_vf 111110 . ..... ..... 101 ..... 1010111 @r_vm
+vfwnmsac_vv 111111 . ..... ..... 001 ..... 1010111 @r_vm
+vfwnmsac_vf 111111 . ..... ..... 101 ..... 1010111 @r_vm
+vfsqrt_v 100011 . ..... 00000 001 ..... 1010111 @r2_vm
+vfmin_vv 000100 . ..... ..... 001 ..... 1010111 @r_vm
+vfmin_vf 000100 . ..... ..... 101 ..... 1010111 @r_vm
+vfmax_vv 000110 . ..... ..... 001 ..... 1010111 @r_vm
+vfmax_vf 000110 . ..... ..... 101 ..... 1010111 @r_vm
+vfsgnj_vv 001000 . ..... ..... 001 ..... 1010111 @r_vm
+vfsgnj_vf 001000 . ..... ..... 101 ..... 1010111 @r_vm
+vfsgnjn_vv 001001 . ..... ..... 001 ..... 1010111 @r_vm
+vfsgnjn_vf 001001 . ..... ..... 101 ..... 1010111 @r_vm
+vfsgnjx_vv 001010 . ..... ..... 001 ..... 1010111 @r_vm
+vfsgnjx_vf 001010 . ..... ..... 101 ..... 1010111 @r_vm
+vmfeq_vv 011000 . ..... ..... 001 ..... 1010111 @r_vm
+vmfeq_vf 011000 . ..... ..... 101 ..... 1010111 @r_vm
+vmfne_vv 011100 . ..... ..... 001 ..... 1010111 @r_vm
+vmfne_vf 011100 . ..... ..... 101 ..... 1010111 @r_vm
+vmflt_vv 011011 . ..... ..... 001 ..... 1010111 @r_vm
+vmflt_vf 011011 . ..... ..... 101 ..... 1010111 @r_vm
+vmfle_vv 011001 . ..... ..... 001 ..... 1010111 @r_vm
+vmfle_vf 011001 . ..... ..... 101 ..... 1010111 @r_vm
+vmfgt_vf 011101 . ..... ..... 101 ..... 1010111 @r_vm
+vmfge_vf 011111 . ..... ..... 101 ..... 1010111 @r_vm
+vmford_vv 011010 . ..... ..... 001 ..... 1010111 @r_vm
+vmford_vf 011010 . ..... ..... 101 ..... 1010111 @r_vm
+vfclass_v 100011 . ..... 10000 001 ..... 1010111 @r2_vm
+vfmerge_vfm 010111 0 ..... ..... 101 ..... 1010111 @r_vm_0
+vfmv_v_f 010111 1 00000 ..... 101 ..... 1010111 @r2
+vfcvt_xu_f_v 100010 . ..... 00000 001 ..... 1010111 @r2_vm
+vfcvt_x_f_v 100010 . ..... 00001 001 ..... 1010111 @r2_vm
+vfcvt_f_xu_v 100010 . ..... 00010 001 ..... 1010111 @r2_vm
+vfcvt_f_x_v 100010 . ..... 00011 001 ..... 1010111 @r2_vm
+vfwcvt_xu_f_v 100010 . ..... 01000 001 ..... 1010111 @r2_vm
+vfwcvt_x_f_v 100010 . ..... 01001 001 ..... 1010111 @r2_vm
+vfwcvt_f_xu_v 100010 . ..... 01010 001 ..... 1010111 @r2_vm
+vfwcvt_f_x_v 100010 . ..... 01011 001 ..... 1010111 @r2_vm
+vfwcvt_f_f_v 100010 . ..... 01100 001 ..... 1010111 @r2_vm
+vfncvt_xu_f_v 100010 . ..... 10000 001 ..... 1010111 @r2_vm
+vfncvt_x_f_v 100010 . ..... 10001 001 ..... 1010111 @r2_vm
+vfncvt_f_xu_v 100010 . ..... 10010 001 ..... 1010111 @r2_vm
+vfncvt_f_x_v 100010 . ..... 10011 001 ..... 1010111 @r2_vm
+vfncvt_f_f_v 100010 . ..... 10100 001 ..... 1010111 @r2_vm
+vredsum_vs 000000 . ..... ..... 010 ..... 1010111 @r_vm
+vredand_vs 000001 . ..... ..... 010 ..... 1010111 @r_vm
+vredor_vs 000010 . ..... ..... 010 ..... 1010111 @r_vm
+vredxor_vs 000011 . ..... ..... 010 ..... 1010111 @r_vm
+vredminu_vs 000100 . ..... ..... 010 ..... 1010111 @r_vm
+vredmin_vs 000101 . ..... ..... 010 ..... 1010111 @r_vm
+vredmaxu_vs 000110 . ..... ..... 010 ..... 1010111 @r_vm
+vredmax_vs 000111 . ..... ..... 010 ..... 1010111 @r_vm
+vwredsumu_vs 110000 . ..... ..... 000 ..... 1010111 @r_vm
+vwredsum_vs 110001 . ..... ..... 000 ..... 1010111 @r_vm
+# Vector ordered and unordered reduction sum
+vfredsum_vs 0000-1 . ..... ..... 001 ..... 1010111 @r_vm
+vfredmin_vs 000101 . ..... ..... 001 ..... 1010111 @r_vm
+vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm
+# Vector widening ordered and unordered float reduction sum
+vfwredsum_vs 1100-1 . ..... ..... 001 ..... 1010111 @r_vm
+vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r
+vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r
+vmandnot_mm 011000 - ..... ..... 010 ..... 1010111 @r
+vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r
+vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r
+vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r
+vmornot_mm 011100 - ..... ..... 010 ..... 1010111 @r
+vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r
+vmpopc_m 010100 . ..... ----- 010 ..... 1010111 @r2_vm
+vmfirst_m 010101 . ..... ----- 010 ..... 1010111 @r2_vm
+vmsbf_m 010110 . ..... 00001 010 ..... 1010111 @r2_vm
+vmsif_m 010110 . ..... 00011 010 ..... 1010111 @r2_vm
+vmsof_m 010110 . ..... 00010 010 ..... 1010111 @r2_vm
+viota_m 010110 . ..... 10000 010 ..... 1010111 @r2_vm
+vid_v 010110 . 00000 10001 010 ..... 1010111 @r1_vm
+vext_x_v 001100 1 ..... ..... 010 ..... 1010111 @r
+vmv_s_x 001101 1 00000 ..... 110 ..... 1010111 @r2
+vfmv_f_s 001100 1 ..... 00000 001 ..... 1010111 @r2rd
+vfmv_s_f 001101 1 00000 ..... 101 ..... 1010111 @r2
+vslideup_vx 001110 . ..... ..... 100 ..... 1010111 @r_vm
+vslideup_vi 001110 . ..... ..... 011 ..... 1010111 @r_vm
+vslide1up_vx 001110 . ..... ..... 110 ..... 1010111 @r_vm
+vslidedown_vx 001111 . ..... ..... 100 ..... 1010111 @r_vm
+vslidedown_vi 001111 . ..... ..... 011 ..... 1010111 @r_vm
+vslide1down_vx 001111 . ..... ..... 110 ..... 1010111 @r_vm
+vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm
+vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm
+vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm
+vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r
+
+vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm
+vsetvl 1000000 ..... ..... 111 ..... 1010111 @r
+
+#*** Vector AMO operations (in addition to Zvamo) ***
+vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+
+# *** RV32 Zba Standard Extension ***
+sh1add 0010000 .......... 010 ..... 0110011 @r
+sh2add 0010000 .......... 100 ..... 0110011 @r
+sh3add 0010000 .......... 110 ..... 0110011 @r
+
+# *** RV64 Zba Standard Extension (in addition to RV32 Zba) ***
+add_uw 0000100 .......... 000 ..... 0111011 @r
+sh1add_uw 0010000 .......... 010 ..... 0111011 @r
+sh2add_uw 0010000 .......... 100 ..... 0111011 @r
+sh3add_uw 0010000 .......... 110 ..... 0111011 @r
+slli_uw 00001 ............ 001 ..... 0011011 @sh
+
+# *** RV32 Zbb Standard Extension ***
+andn 0100000 .......... 111 ..... 0110011 @r
+clz 011000 000000 ..... 001 ..... 0010011 @r2
+cpop 011000 000010 ..... 001 ..... 0010011 @r2
+ctz 011000 000001 ..... 001 ..... 0010011 @r2
+max 0000101 .......... 110 ..... 0110011 @r
+maxu 0000101 .......... 111 ..... 0110011 @r
+min 0000101 .......... 100 ..... 0110011 @r
+minu 0000101 .......... 101 ..... 0110011 @r
+orc_b 001010 000111 ..... 101 ..... 0010011 @r2
+orn 0100000 .......... 110 ..... 0110011 @r
+# The encoding for rev8 differs between RV32 and RV64.
+# rev8_32 denotes the RV32 variant.
+rev8_32 011010 011000 ..... 101 ..... 0010011 @r2
+rol 0110000 .......... 001 ..... 0110011 @r
+ror 0110000 .......... 101 ..... 0110011 @r
+rori 01100 ............ 101 ..... 0010011 @sh
+sext_b 011000 000100 ..... 001 ..... 0010011 @r2
+sext_h 011000 000101 ..... 001 ..... 0010011 @r2
+xnor 0100000 .......... 100 ..... 0110011 @r
+# The encoding for zext.h differs between RV32 and RV64.
+# zext_h_32 denotes the RV32 variant.
+zext_h_32 0000100 00000 ..... 100 ..... 0110011 @r2
+
+# *** RV64 Zbb Standard Extension (in addition to RV32 Zbb) ***
+clzw 0110000 00000 ..... 001 ..... 0011011 @r2
+ctzw 0110000 00001 ..... 001 ..... 0011011 @r2
+cpopw 0110000 00010 ..... 001 ..... 0011011 @r2
+# The encoding for rev8 differs between RV32 and RV64.
+# When executing on RV64, the encoding used in RV32 is an illegal
+# instruction, so we use different handler functions to differentiate.
+rev8_64 011010 111000 ..... 101 ..... 0010011 @r2
+rolw 0110000 .......... 001 ..... 0111011 @r
+roriw 0110000 .......... 101 ..... 0011011 @sh5
+rorw 0110000 .......... 101 ..... 0111011 @r
+# The encoding for zext.h differs between RV32 and RV64.
+# When executing on RV64, the encoding used in RV32 is an illegal
+# instruction, so we use different handler functions to differentiate.
+zext_h_64 0000100 00000 ..... 100 ..... 0111011 @r2
+
+# *** RV32 Zbc Standard Extension ***
+clmul 0000101 .......... 001 ..... 0110011 @r
+clmulh 0000101 .......... 011 ..... 0110011 @r
+clmulr 0000101 .......... 010 ..... 0110011 @r
+
+# *** RV32 Zbs Standard Extension ***
+bclr 0100100 .......... 001 ..... 0110011 @r
+bclri 01001. ........... 001 ..... 0010011 @sh
+bext 0100100 .......... 101 ..... 0110011 @r
+bexti 01001. ........... 101 ..... 0010011 @sh
+binv 0110100 .......... 001 ..... 0110011 @r
+binvi 01101. ........... 001 ..... 0010011 @sh
+bset 0010100 .......... 001 ..... 0110011 @r
+bseti 00101. ........... 001 ..... 0010011 @sh
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
new file mode 100644
index 000000000..75c6ef80a
--- /dev/null
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -0,0 +1,128 @@
+/*
+ * RISC-V translation routines for the RISC-V privileged instructions.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
+{
+ /* always generates U-level ECALL, fixed in do_interrupt handler */
+ generate_exception(ctx, RISCV_EXCP_U_ECALL);
+ return true;
+}
+
+static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
+{
+ target_ulong ebreak_addr = ctx->base.pc_next;
+ target_ulong pre_addr = ebreak_addr - 4;
+ target_ulong post_addr = ebreak_addr + 4;
+ uint32_t pre = 0;
+ uint32_t ebreak = 0;
+ uint32_t post = 0;
+
+ /*
+ * The RISC-V semihosting spec specifies the following
+ * three-instruction sequence to flag a semihosting call:
+ *
+ * slli zero, zero, 0x1f 0x01f01013
+ * ebreak 0x00100073
+ * srai zero, zero, 0x7 0x40705013
+ *
+ * The two shift operations on the zero register are no-ops, used
+ * here to signify a semihosting exception, rather than a breakpoint.
+ *
+ * Uncompressed instructions are required so that the sequence is easy
+ * to validate.
+ *
+ * The three instructions are required to lie in the same page so
+ * that no exception will be raised when fetching them.
+ */
+
+ if ((pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) {
+ pre = opcode_at(&ctx->base, pre_addr);
+ ebreak = opcode_at(&ctx->base, ebreak_addr);
+ post = opcode_at(&ctx->base, post_addr);
+ }
+
+ if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
+ generate_exception(ctx, RISCV_EXCP_SEMIHOST);
+ } else {
+ generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
+ }
+ return true;
+}
+
+static bool trans_uret(DisasContext *ctx, arg_uret *a)
+{
+ return false;
+}
+
+static bool trans_sret(DisasContext *ctx, arg_sret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+
+ if (has_ext(ctx, RVS)) {
+ gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ } else {
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_mret(DisasContext *ctx, arg_mret *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ gen_helper_wfi(cpu_env);
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
+{
+#ifndef CONFIG_USER_ONLY
+ gen_helper_tlb_flush(cpu_env);
+ return true;
+#endif
+ return false;
+}
+
+static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
+{
+ return false;
+}
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
new file mode 100644
index 000000000..40fe132b0
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -0,0 +1,226 @@
+/*
+ * RISC-V translation routines for the RV64A Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ if (a->rl) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+ src1 = gen_pm_adjust_address(ctx, src1);
+ tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
+ if (a->aq) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+
+ /* Put addr in load_res, data in load_val. */
+ tcg_gen_mov_tl(load_res, src1);
+ gen_set_gpr(ctx, a->rd, load_val);
+
+ return true;
+}
+
+static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv dest, src1, src2;
+ TCGLabel *l1 = gen_new_label();
+ TCGLabel *l2 = gen_new_label();
+
+ src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ src1 = gen_pm_adjust_address(ctx, src1);
+ tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
+
+ /*
+ * Note that the TCG atomic primitives are SC,
+ * so we can ignore AQ/RL along this path.
+ */
+ dest = dest_gpr(ctx, a->rd);
+ src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+ tcg_gen_atomic_cmpxchg_tl(dest, load_res, load_val, src2,
+ ctx->mem_idx, mop);
+ tcg_gen_setcond_tl(TCG_COND_NE, dest, dest, load_val);
+ gen_set_gpr(ctx, a->rd, dest);
+ tcg_gen_br(l2);
+
+ gen_set_label(l1);
+ /*
+ * Address comparison failure. However, we still need to
+ * provide the memory barrier implied by AQ/RL.
+ */
+ tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL);
+ gen_set_gpr(ctx, a->rd, tcg_constant_tl(1));
+
+ gen_set_label(l2);
+ /*
+ * Clear the load reservation, since an SC must fail if there is
+ * an SC to any address, in between an LR and SC pair.
+ */
+ tcg_gen_movi_tl(load_res, -1);
+
+ return true;
+}
+
+static bool gen_amo(DisasContext *ctx, arg_atomic *a,
+ void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
+ MemOp mop)
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ src1 = gen_pm_adjust_address(ctx, src1);
+ func(dest, src1, src2, ctx->mem_idx, mop);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_lr(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_sc(ctx, a, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
+{
+ REQUIRE_EXT(ctx, RVA);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL));
+}
+
+static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
+}
+
+static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
+}
+
+static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
+}
diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc
new file mode 100644
index 000000000..c8d31907c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvb.c.inc
@@ -0,0 +1,506 @@
+/*
+ * RISC-V translation routines for the Zb[abcs] Standard Extension.
+ *
+ * Copyright (c) 2020 Kito Cheng, kito.cheng@sifive.com
+ * Copyright (c) 2020 Frank Chang, frank.chang@sifive.com
+ * Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define REQUIRE_ZBA(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zba) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZBB(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zbb) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZBC(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zbc) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZBS(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_zbs) { \
+ return false; \
+ } \
+} while (0)
+
+static void gen_clz(TCGv ret, TCGv arg1)
+{
+ tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS);
+}
+
+static void gen_clzw(TCGv ret, TCGv arg1)
+{
+ TCGv t = tcg_temp_new();
+ tcg_gen_shli_tl(t, arg1, 32);
+ tcg_gen_clzi_tl(ret, t, 32);
+ tcg_temp_free(t);
+}
+
+static bool trans_clz(DisasContext *ctx, arg_clz *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary_per_ol(ctx, a, EXT_NONE, gen_clz, gen_clzw);
+}
+
+static void gen_ctz(TCGv ret, TCGv arg1)
+{
+ tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS);
+}
+
+static void gen_ctzw(TCGv ret, TCGv arg1)
+{
+ tcg_gen_ctzi_tl(ret, arg1, 32);
+}
+
+static bool trans_ctz(DisasContext *ctx, arg_ctz *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary_per_ol(ctx, a, EXT_ZERO, gen_ctz, gen_ctzw);
+}
+
+static bool trans_cpop(DisasContext *ctx, arg_cpop *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl);
+}
+
+static bool trans_andn(DisasContext *ctx, arg_andn *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_andc_tl);
+}
+
+static bool trans_orn(DisasContext *ctx, arg_orn *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_orc_tl);
+}
+
+static bool trans_xnor(DisasContext *ctx, arg_xnor *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_eqv_tl);
+}
+
+static bool trans_min(DisasContext *ctx, arg_min *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smin_tl);
+}
+
+static bool trans_max(DisasContext *ctx, arg_max *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_smax_tl);
+}
+
+static bool trans_minu(DisasContext *ctx, arg_minu *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umin_tl);
+}
+
+static bool trans_maxu(DisasContext *ctx, arg_maxu *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_arith(ctx, a, EXT_SIGN, tcg_gen_umax_tl);
+}
+
+static bool trans_sext_b(DisasContext *ctx, arg_sext_b *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl);
+}
+
+static bool trans_sext_h(DisasContext *ctx, arg_sext_h *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl);
+}
+
+static void gen_sbop_mask(TCGv ret, TCGv shamt)
+{
+ tcg_gen_movi_tl(ret, 1);
+ tcg_gen_shl_tl(ret, ret, shamt);
+}
+
+static void gen_bset(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ TCGv t = tcg_temp_new();
+
+ gen_sbop_mask(t, shamt);
+ tcg_gen_or_tl(ret, arg1, t);
+
+ tcg_temp_free(t);
+}
+
+static bool trans_bset(DisasContext *ctx, arg_bset *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_bset);
+}
+
+static bool trans_bseti(DisasContext *ctx, arg_bseti *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bset);
+}
+
+static void gen_bclr(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ TCGv t = tcg_temp_new();
+
+ gen_sbop_mask(t, shamt);
+ tcg_gen_andc_tl(ret, arg1, t);
+
+ tcg_temp_free(t);
+}
+
+static bool trans_bclr(DisasContext *ctx, arg_bclr *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_bclr);
+}
+
+static bool trans_bclri(DisasContext *ctx, arg_bclri *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bclr);
+}
+
+static void gen_binv(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ TCGv t = tcg_temp_new();
+
+ gen_sbop_mask(t, shamt);
+ tcg_gen_xor_tl(ret, arg1, t);
+
+ tcg_temp_free(t);
+}
+
+static bool trans_binv(DisasContext *ctx, arg_binv *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_binv);
+}
+
+static bool trans_binvi(DisasContext *ctx, arg_binvi *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_binv);
+}
+
+static void gen_bext(TCGv ret, TCGv arg1, TCGv shamt)
+{
+ tcg_gen_shr_tl(ret, arg1, shamt);
+ tcg_gen_andi_tl(ret, ret, 1);
+}
+
+static bool trans_bext(DisasContext *ctx, arg_bext *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift(ctx, a, EXT_NONE, gen_bext);
+}
+
+static bool trans_bexti(DisasContext *ctx, arg_bexti *a)
+{
+ REQUIRE_ZBS(ctx);
+ return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext);
+}
+
+static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+
+ /* truncate to 32-bits */
+ tcg_gen_trunc_tl_i32(t1, arg1);
+ tcg_gen_trunc_tl_i32(t2, arg2);
+
+ tcg_gen_rotr_i32(t1, t1, t2);
+
+ /* sign-extend 64-bits */
+ tcg_gen_ext_i32_tl(ret, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+static bool trans_ror(DisasContext *ctx, arg_ror *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotr_tl, gen_rorw);
+}
+
+static void gen_roriw(TCGv ret, TCGv arg1, target_long shamt)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t1, arg1);
+ tcg_gen_rotri_i32(t1, t1, shamt);
+ tcg_gen_ext_i32_tl(ret, t1);
+
+ tcg_temp_free_i32(t1);
+}
+
+static bool trans_rori(DisasContext *ctx, arg_rori *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
+ tcg_gen_rotri_tl, gen_roriw);
+}
+
+static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+
+ /* truncate to 32-bits */
+ tcg_gen_trunc_tl_i32(t1, arg1);
+ tcg_gen_trunc_tl_i32(t2, arg2);
+
+ tcg_gen_rotl_i32(t1, t1, t2);
+
+ /* sign-extend 64-bits */
+ tcg_gen_ext_i32_tl(ret, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+static bool trans_rol(DisasContext *ctx, arg_rol *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotl_tl, gen_rolw);
+}
+
+static void gen_rev8_32(TCGv ret, TCGv src1)
+{
+ tcg_gen_bswap32_tl(ret, src1, TCG_BSWAP_OS);
+}
+
+static bool trans_rev8_32(DisasContext *ctx, arg_rev8_32 *a)
+{
+ REQUIRE_32BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, gen_rev8_32);
+}
+
+static bool trans_rev8_64(DisasContext *ctx, arg_rev8_64 *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_bswap_tl);
+}
+
+static void gen_orc_b(TCGv ret, TCGv source1)
+{
+ TCGv tmp = tcg_temp_new();
+ TCGv low7 = tcg_constant_tl(dup_const_tl(MO_8, 0x7f));
+
+ /* Set msb in each byte if the byte was non-zero. */
+ tcg_gen_and_tl(tmp, source1, low7);
+ tcg_gen_add_tl(tmp, tmp, low7);
+ tcg_gen_or_tl(tmp, tmp, source1);
+
+ /* Extract the msb to the lsb in each byte */
+ tcg_gen_andc_tl(tmp, tmp, low7);
+ tcg_gen_shri_tl(tmp, tmp, 7);
+
+ /* Replicate the lsb of each byte across the byte. */
+ tcg_gen_muli_tl(ret, tmp, 0xff);
+
+ tcg_temp_free(tmp);
+}
+
+static bool trans_orc_b(DisasContext *ctx, arg_orc_b *a)
+{
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_ZERO, gen_orc_b);
+}
+
+#define GEN_SHADD(SHAMT) \
+static void gen_sh##SHAMT##add(TCGv ret, TCGv arg1, TCGv arg2) \
+{ \
+ TCGv t = tcg_temp_new(); \
+ \
+ tcg_gen_shli_tl(t, arg1, SHAMT); \
+ tcg_gen_add_tl(ret, t, arg2); \
+ \
+ tcg_temp_free(t); \
+}
+
+GEN_SHADD(1)
+GEN_SHADD(2)
+GEN_SHADD(3)
+
+#define GEN_TRANS_SHADD(SHAMT) \
+static bool trans_sh##SHAMT##add(DisasContext *ctx, arg_sh##SHAMT##add *a) \
+{ \
+ REQUIRE_ZBA(ctx); \
+ return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add); \
+}
+
+GEN_TRANS_SHADD(1)
+GEN_TRANS_SHADD(2)
+GEN_TRANS_SHADD(3)
+
+static bool trans_zext_h_32(DisasContext *ctx, arg_zext_h_32 *a)
+{
+ REQUIRE_32BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl);
+}
+
+static bool trans_zext_h_64(DisasContext *ctx, arg_zext_h_64 *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl);
+}
+
+static bool trans_clzw(DisasContext *ctx, arg_clzw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_NONE, gen_clzw);
+}
+
+static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ return gen_unary(ctx, a, EXT_ZERO, gen_ctzw);
+}
+
+static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl);
+}
+
+static bool trans_rorw(DisasContext *ctx, arg_rorw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_NONE, gen_rorw);
+}
+
+static bool trans_roriw(DisasContext *ctx, arg_roriw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw);
+}
+
+static bool trans_rolw(DisasContext *ctx, arg_rolw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBB(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_NONE, gen_rolw);
+}
+
+#define GEN_SHADD_UW(SHAMT) \
+static void gen_sh##SHAMT##add_uw(TCGv ret, TCGv arg1, TCGv arg2) \
+{ \
+ TCGv t = tcg_temp_new(); \
+ \
+ tcg_gen_ext32u_tl(t, arg1); \
+ \
+ tcg_gen_shli_tl(t, t, SHAMT); \
+ tcg_gen_add_tl(ret, t, arg2); \
+ \
+ tcg_temp_free(t); \
+}
+
+GEN_SHADD_UW(1)
+GEN_SHADD_UW(2)
+GEN_SHADD_UW(3)
+
+#define GEN_TRANS_SHADD_UW(SHAMT) \
+static bool trans_sh##SHAMT##add_uw(DisasContext *ctx, \
+ arg_sh##SHAMT##add_uw *a) \
+{ \
+ REQUIRE_64BIT(ctx); \
+ REQUIRE_ZBA(ctx); \
+ return gen_arith(ctx, a, EXT_NONE, gen_sh##SHAMT##add_uw); \
+}
+
+GEN_TRANS_SHADD_UW(1)
+GEN_TRANS_SHADD_UW(2)
+GEN_TRANS_SHADD_UW(3)
+
+static void gen_add_uw(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv t = tcg_temp_new();
+ tcg_gen_ext32u_tl(t, arg1);
+ tcg_gen_add_tl(ret, t, arg2);
+ tcg_temp_free(t);
+}
+
+static bool trans_add_uw(DisasContext *ctx, arg_add_uw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBA(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_add_uw);
+}
+
+static void gen_slli_uw(TCGv dest, TCGv src, target_long shamt)
+{
+ tcg_gen_deposit_z_tl(dest, src, shamt, MIN(32, TARGET_LONG_BITS - shamt));
+}
+
+static bool trans_slli_uw(DisasContext *ctx, arg_slli_uw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_ZBA(ctx);
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_slli_uw);
+}
+
+static bool trans_clmul(DisasContext *ctx, arg_clmul *a)
+{
+ REQUIRE_ZBC(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_helper_clmul);
+}
+
+static void gen_clmulh(TCGv dst, TCGv src1, TCGv src2)
+{
+ gen_helper_clmulr(dst, src1, src2);
+ tcg_gen_shri_tl(dst, dst, 1);
+}
+
+static bool trans_clmulh(DisasContext *ctx, arg_clmulr *a)
+{
+ REQUIRE_ZBC(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_clmulh);
+}
+
+static bool trans_clmulr(DisasContext *ctx, arg_clmulh *a)
+{
+ REQUIRE_ZBC(ctx);
+ return gen_arith(ctx, a, EXT_NONE, gen_helper_clmulr);
+}
diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc
new file mode 100644
index 000000000..64fb0046f
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvd.c.inc
@@ -0,0 +1,449 @@
+/*
+ * RISC-V translation routines for the RV64D Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool trans_fld(DisasContext *ctx, arg_fld *a)
+{
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEQ);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
+{
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEQ);
+
+ return true;
+}
+
+static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
+{
+ if (a->rs1 == a->rs2) { /* FMOV */
+ tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
+ } else {
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2],
+ cpu_fpr[a->rs1], 0, 63);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ if (a->rs1 == a->rs2) { /* FNEG */
+ tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+ if (a->rs1 == a->rs2) { /* FABS */
+ tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN);
+ } else {
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN);
+ tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
+ tcg_temp_free_i64(t0);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_feq_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_flt_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fle_d(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fclass_d(dest, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_w_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_wu_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_l_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_lu_d(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+#ifdef TARGET_RISCV64
+ gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]);
+ return true;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVD);
+
+#ifdef TARGET_RISCV64
+ tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE));
+ mark_fs_dirty(ctx);
+ return true;
+#else
+ qemu_build_not_reached();
+#endif
+}
diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc
new file mode 100644
index 000000000..b5459249c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvf.c.inc
@@ -0,0 +1,473 @@
+/*
+ * RISC-V translation routines for the RV64F Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define REQUIRE_FPU do {\
+ if (ctx->mstatus_fs == 0) \
+ return false; \
+} while (0)
+
+static bool trans_flw(DisasContext *ctx, arg_flw *a)
+{
+ TCGv_i64 dest;
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ dest = cpu_fpr[a->rd];
+ tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL);
+ gen_nanbox_s(dest, dest);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
+{
+ TCGv addr;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ if (a->imm) {
+ TCGv temp = tcg_temp_new();
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL);
+
+ return true;
+}
+
+static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env,
+ cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ if (a->rs1 == a->rs2) { /* FMOV */
+ gen_check_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
+ } else { /* FSGNJ */
+ TCGv_i64 rs1 = tcg_temp_new_i64();
+ TCGv_i64 rs2 = tcg_temp_new_i64();
+
+ gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]);
+ gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]);
+
+ /* This formulation retains the nanboxing of rs2. */
+ tcg_gen_deposit_i64(cpu_fpr[a->rd], rs2, rs1, 0, 31);
+ tcg_temp_free_i64(rs1);
+ tcg_temp_free_i64(rs2);
+ }
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
+{
+ TCGv_i64 rs1, rs2, mask;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ rs1 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]);
+
+ if (a->rs1 == a->rs2) { /* FNEG */
+ tcg_gen_xori_i64(cpu_fpr[a->rd], rs1, MAKE_64BIT_MASK(31, 1));
+ } else {
+ rs2 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]);
+
+ /*
+ * Replace bit 31 in rs1 with inverse in rs2.
+ * This formulation retains the nanboxing of rs1.
+ */
+ mask = tcg_constant_i64(~MAKE_64BIT_MASK(31, 1));
+ tcg_gen_nor_i64(rs2, rs2, mask);
+ tcg_gen_and_i64(rs1, mask, rs1);
+ tcg_gen_or_i64(cpu_fpr[a->rd], rs1, rs2);
+
+ tcg_temp_free_i64(rs2);
+ }
+ tcg_temp_free_i64(rs1);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a)
+{
+ TCGv_i64 rs1, rs2;
+
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ rs1 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs1, cpu_fpr[a->rs1]);
+
+ if (a->rs1 == a->rs2) { /* FABS */
+ tcg_gen_andi_i64(cpu_fpr[a->rd], rs1, ~MAKE_64BIT_MASK(31, 1));
+ } else {
+ rs2 = tcg_temp_new_i64();
+ gen_check_nanbox_s(rs2, cpu_fpr[a->rs2]);
+
+ /*
+ * Xor bit 31 in rs1 with that in rs2.
+ * This formulation retains the nanboxing of rs1.
+ */
+ tcg_gen_andi_i64(rs2, rs2, MAKE_64BIT_MASK(31, 1));
+ tcg_gen_xor_i64(cpu_fpr[a->rd], rs1, rs2);
+
+ tcg_temp_free_i64(rs2);
+ }
+ tcg_temp_free_i64(rs1);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
+ cpu_fpr[a->rs2]);
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_w_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_wu_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
+{
+ /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+#if defined(TARGET_RISCV64)
+ tcg_gen_ext32s_tl(dest, cpu_fpr[a->rs1]);
+#else
+ tcg_gen_extrl_i64_i32(dest, cpu_fpr[a->rs1]);
+#endif
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_feq_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_flt_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fle_s(dest, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_helper_fclass_s(dest, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
+{
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
+{
+ /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ tcg_gen_extu_tl_i64(cpu_fpr[a->rd], src);
+ gen_nanbox_s(cpu_fpr[a->rd], cpu_fpr[a->rd]);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_l_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_lu_s(dest, cpu_env, cpu_fpr[a->rs1]);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
+
+static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_FPU;
+ REQUIRE_EXT(ctx, RVF);
+
+ TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
+
+ gen_set_rm(ctx, a->rm);
+ gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, src);
+
+ mark_fs_dirty(ctx);
+ return true;
+}
diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc
new file mode 100644
index 000000000..ecbf77ff9
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvh.c.inc
@@ -0,0 +1,186 @@
+/*
+ * RISC-V translation routines for the RVXI Base Integer Instruction Set.
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CONFIG_USER_ONLY
+static bool check_access(DisasContext *ctx)
+{
+ if (!ctx->hlsx) {
+ if (ctx->virt_enabled) {
+ generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT);
+ } else {
+ generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ return false;
+ }
+ return true;
+}
+#endif
+
+static bool do_hlv(DisasContext *ctx, arg_r2 *a, MemOp mop)
+{
+#ifdef CONFIG_USER_ONLY
+ return false;
+#else
+ if (check_access(ctx)) {
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ int mem_idx = ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+ tcg_gen_qemu_ld_tl(dest, addr, mem_idx, mop);
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+#endif
+}
+
+static bool trans_hlv_b(DisasContext *ctx, arg_hlv_b *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_SB);
+}
+
+static bool trans_hlv_h(DisasContext *ctx, arg_hlv_h *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TESW);
+}
+
+static bool trans_hlv_w(DisasContext *ctx, arg_hlv_w *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TESL);
+}
+
+static bool trans_hlv_bu(DisasContext *ctx, arg_hlv_bu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_UB);
+}
+
+static bool trans_hlv_hu(DisasContext *ctx, arg_hlv_hu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TEUW);
+}
+
+static bool do_hsv(DisasContext *ctx, arg_r2_s *a, MemOp mop)
+{
+#ifdef CONFIG_USER_ONLY
+ return false;
+#else
+ if (check_access(ctx)) {
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
+ int mem_idx = ctx->mem_idx | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+ tcg_gen_qemu_st_tl(data, addr, mem_idx, mop);
+ }
+ return true;
+#endif
+}
+
+static bool trans_hsv_b(DisasContext *ctx, arg_hsv_b *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_SB);
+}
+
+static bool trans_hsv_h(DisasContext *ctx, arg_hsv_h *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_TESW);
+}
+
+static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_TESL);
+}
+
+static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TEUL);
+}
+
+static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVH);
+ return do_hlv(ctx, a, MO_TEQ);
+}
+
+static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVH);
+ return do_hsv(ctx, a, MO_TEQ);
+}
+
+#ifndef CONFIG_USER_ONLY
+static bool do_hlvx(DisasContext *ctx, arg_r2 *a,
+ void (*func)(TCGv, TCGv_env, TCGv))
+{
+ if (check_access(ctx)) {
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ func(dest, cpu_env, addr);
+ gen_set_gpr(ctx, a->rd, dest);
+ }
+ return true;
+}
+#endif
+
+static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ return do_hlvx(ctx, a, gen_helper_hyp_hlvx_hu);
+#else
+ return false;
+#endif
+}
+
+static bool trans_hlvx_wu(DisasContext *ctx, arg_hlvx_wu *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ return do_hlvx(ctx, a, gen_helper_hyp_hlvx_wu);
+#else
+ return false;
+#endif
+}
+
+static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ gen_helper_hyp_gvma_tlb_flush(cpu_env);
+ return true;
+#endif
+ return false;
+}
+
+static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a)
+{
+ REQUIRE_EXT(ctx, RVH);
+#ifndef CONFIG_USER_ONLY
+ gen_helper_hyp_tlb_flush(cpu_env);
+ return true;
+#endif
+ return false;
+}
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
new file mode 100644
index 000000000..e51dbc41c
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -0,0 +1,577 @@
+/*
+ * RISC-V translation routines for the RVXI Base Integer Instruction Set.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static bool trans_illegal(DisasContext *ctx, arg_empty *a)
+{
+ gen_exception_illegal(ctx);
+ return true;
+}
+
+static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a)
+{
+ REQUIRE_64BIT(ctx);
+ return trans_illegal(ctx, a);
+}
+
+static bool trans_lui(DisasContext *ctx, arg_lui *a)
+{
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm);
+ }
+ return true;
+}
+
+static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
+{
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next);
+ }
+ return true;
+}
+
+static bool trans_jal(DisasContext *ctx, arg_jal *a)
+{
+ gen_jal(ctx, a->rd, a->imm);
+ return true;
+}
+
+static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
+{
+ TCGLabel *misaligned = NULL;
+
+ tcg_gen_addi_tl(cpu_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
+ tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
+
+ if (!has_ext(ctx, RVC)) {
+ TCGv t0 = tcg_temp_new();
+
+ misaligned = gen_new_label();
+ tcg_gen_andi_tl(t0, cpu_pc, 0x2);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
+ tcg_temp_free(t0);
+ }
+
+ if (a->rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
+ }
+ tcg_gen_lookup_and_goto_ptr();
+
+ if (misaligned) {
+ gen_set_label(misaligned);
+ gen_exception_inst_addr_mis(ctx);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ return true;
+}
+
+static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
+{
+ TCGLabel *l = gen_new_label();
+ TCGv src1 = get_gpr(ctx, a->rs1, EXT_SIGN);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_SIGN);
+
+ tcg_gen_brcond_tl(cond, src1, src2, l);
+ gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
+
+ gen_set_label(l); /* branch taken */
+
+ if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) {
+ /* misaligned */
+ gen_exception_inst_addr_mis(ctx);
+ } else {
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm);
+ }
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ return true;
+}
+
+static bool trans_beq(DisasContext *ctx, arg_beq *a)
+{
+ return gen_branch(ctx, a, TCG_COND_EQ);
+}
+
+static bool trans_bne(DisasContext *ctx, arg_bne *a)
+{
+ return gen_branch(ctx, a, TCG_COND_NE);
+}
+
+static bool trans_blt(DisasContext *ctx, arg_blt *a)
+{
+ return gen_branch(ctx, a, TCG_COND_LT);
+}
+
+static bool trans_bge(DisasContext *ctx, arg_bge *a)
+{
+ return gen_branch(ctx, a, TCG_COND_GE);
+}
+
+static bool trans_bltu(DisasContext *ctx, arg_bltu *a)
+{
+ return gen_branch(ctx, a, TCG_COND_LTU);
+}
+
+static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
+{
+ return gen_branch(ctx, a, TCG_COND_GEU);
+}
+
+static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool trans_lb(DisasContext *ctx, arg_lb *a)
+{
+ return gen_load(ctx, a, MO_SB);
+}
+
+static bool trans_lh(DisasContext *ctx, arg_lh *a)
+{
+ return gen_load(ctx, a, MO_TESW);
+}
+
+static bool trans_lw(DisasContext *ctx, arg_lw *a)
+{
+ return gen_load(ctx, a, MO_TESL);
+}
+
+static bool trans_lbu(DisasContext *ctx, arg_lbu *a)
+{
+ return gen_load(ctx, a, MO_UB);
+}
+
+static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
+{
+ return gen_load(ctx, a, MO_TEUW);
+}
+
+static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
+{
+ TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
+ TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ if (a->imm) {
+ TCGv temp = temp_new(ctx);
+ tcg_gen_addi_tl(temp, addr, a->imm);
+ addr = temp;
+ }
+ addr = gen_pm_adjust_address(ctx, addr);
+
+ tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
+ return true;
+}
+
+static bool trans_sb(DisasContext *ctx, arg_sb *a)
+{
+ return gen_store(ctx, a, MO_SB);
+}
+
+static bool trans_sh(DisasContext *ctx, arg_sh *a)
+{
+ return gen_store(ctx, a, MO_TESW);
+}
+
+static bool trans_sw(DisasContext *ctx, arg_sw *a)
+{
+ return gen_store(ctx, a, MO_TESL);
+}
+
+static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_load(ctx, a, MO_TEUL);
+}
+
+static bool trans_ld(DisasContext *ctx, arg_ld *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_load(ctx, a, MO_TEQ);
+}
+
+static bool trans_sd(DisasContext *ctx, arg_sd *a)
+{
+ REQUIRE_64BIT(ctx);
+ return gen_store(ctx, a, MO_TEQ);
+}
+
+static bool trans_addi(DisasContext *ctx, arg_addi *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
+}
+
+static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2);
+}
+
+static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2);
+}
+
+static bool trans_slti(DisasContext *ctx, arg_slti *a)
+{
+ return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_slt);
+}
+
+static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
+{
+ return gen_arith_imm_tl(ctx, a, EXT_SIGN, gen_sltu);
+}
+
+static bool trans_xori(DisasContext *ctx, arg_xori *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_xori_tl);
+}
+
+static bool trans_ori(DisasContext *ctx, arg_ori *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_ori_tl);
+}
+
+static bool trans_andi(DisasContext *ctx, arg_andi *a)
+{
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_andi_tl);
+}
+
+static bool trans_slli(DisasContext *ctx, arg_slli *a)
+{
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
+}
+
+static void gen_srliw(TCGv dst, TCGv src, target_long shamt)
+{
+ tcg_gen_extract_tl(dst, src, shamt, 32 - shamt);
+}
+
+static bool trans_srli(DisasContext *ctx, arg_srli *a)
+{
+ return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
+ tcg_gen_shri_tl, gen_srliw);
+}
+
+static void gen_sraiw(TCGv dst, TCGv src, target_long shamt)
+{
+ tcg_gen_sextract_tl(dst, src, shamt, 32 - shamt);
+}
+
+static bool trans_srai(DisasContext *ctx, arg_srai *a)
+{
+ return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE,
+ tcg_gen_sari_tl, gen_sraiw);
+}
+
+static bool trans_add(DisasContext *ctx, arg_add *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
+}
+
+static bool trans_sub(DisasContext *ctx, arg_sub *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
+}
+
+static bool trans_sll(DisasContext *ctx, arg_sll *a)
+{
+ return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
+}
+
+static bool trans_slt(DisasContext *ctx, arg_slt *a)
+{
+ return gen_arith(ctx, a, EXT_SIGN, gen_slt);
+}
+
+static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
+{
+ return gen_arith(ctx, a, EXT_SIGN, gen_sltu);
+}
+
+static bool trans_xor(DisasContext *ctx, arg_xor *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_xor_tl);
+}
+
+static bool trans_srl(DisasContext *ctx, arg_srl *a)
+{
+ return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
+}
+
+static bool trans_sra(DisasContext *ctx, arg_sra *a)
+{
+ return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
+}
+
+static bool trans_or(DisasContext *ctx, arg_or *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_or_tl);
+}
+
+static bool trans_and(DisasContext *ctx, arg_and *a)
+{
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_and_tl);
+}
+
+static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl);
+}
+
+static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl);
+}
+
+static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_srliw);
+}
+
+static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_sraiw);
+}
+
+static bool trans_addw(DisasContext *ctx, arg_addw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl);
+}
+
+static bool trans_subw(DisasContext *ctx, arg_subw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl);
+}
+
+static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl);
+}
+
+static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl);
+}
+
+static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
+{
+ REQUIRE_64BIT(ctx);
+ ctx->ol = MXL_RV32;
+ return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl);
+}
+
+static bool trans_fence(DisasContext *ctx, arg_fence *a)
+{
+ /* FENCE is a full memory barrier. */
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+ return true;
+}
+
+static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
+{
+ if (!ctx->ext_ifencei) {
+ return false;
+ }
+
+ /*
+ * FENCE_I is a no-op in QEMU,
+ * however we need to end the translation block
+ */
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_exit_tb(NULL, 0);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool do_csr_post(DisasContext *ctx)
+{
+ /* We may have changed important cpu state -- exit to main loop. */
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_exit_tb(NULL, 0);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool do_csrr(DisasContext *ctx, int rd, int rc)
+{
+ TCGv dest = dest_gpr(ctx, rd);
+ TCGv_i32 csr = tcg_constant_i32(rc);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_csrr(dest, cpu_env, csr);
+ gen_set_gpr(ctx, rd, dest);
+ return do_csr_post(ctx);
+}
+
+static bool do_csrw(DisasContext *ctx, int rc, TCGv src)
+{
+ TCGv_i32 csr = tcg_constant_i32(rc);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_csrw(cpu_env, csr, src);
+ return do_csr_post(ctx);
+}
+
+static bool do_csrrw(DisasContext *ctx, int rd, int rc, TCGv src, TCGv mask)
+{
+ TCGv dest = dest_gpr(ctx, rd);
+ TCGv_i32 csr = tcg_constant_i32(rc);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_csrrw(dest, cpu_env, csr, src, mask);
+ gen_set_gpr(ctx, rd, dest);
+ return do_csr_post(ctx);
+}
+
+static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
+{
+ TCGv src = get_gpr(ctx, a->rs1, EXT_NONE);
+
+ /*
+ * If rd == 0, the insn shall not read the csr, nor cause any of the
+ * side effects that might occur on a csr read.
+ */
+ if (a->rd == 0) {
+ return do_csrw(ctx, a->csr, src);
+ }
+
+ TCGv mask = tcg_constant_tl(-1);
+ return do_csrrw(ctx, a->rd, a->csr, src, mask);
+}
+
+static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv ones = tcg_constant_tl(-1);
+ TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
+ return do_csrrw(ctx, a->rd, a->csr, ones, mask);
+}
+
+static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv mask = get_gpr(ctx, a->rs1, EXT_ZERO);
+ return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
+}
+
+static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
+{
+ TCGv src = tcg_constant_tl(a->rs1);
+
+ /*
+ * If rd == 0, the insn shall not read the csr, nor cause any of the
+ * side effects that might occur on a csr read.
+ */
+ if (a->rd == 0) {
+ return do_csrw(ctx, a->csr, src);
+ }
+
+ TCGv mask = tcg_constant_tl(-1);
+ return do_csrrw(ctx, a->rd, a->csr, src, mask);
+}
+
+static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv ones = tcg_constant_tl(-1);
+ TCGv mask = tcg_constant_tl(a->rs1);
+ return do_csrrw(ctx, a->rd, a->csr, ones, mask);
+}
+
+static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
+{
+ /*
+ * If rs1 == 0, the insn shall not write to the csr at all, nor
+ * cause any of the side effects that might occur on a csr write.
+ * Note that if rs1 specifies a register other than x0, holding
+ * a zero value, the instruction will still attempt to write the
+ * unmodified value back to the csr and will cause side effects.
+ */
+ if (a->rs1 == 0) {
+ return do_csrr(ctx, a->rd, a->csr);
+ }
+
+ TCGv mask = tcg_constant_tl(a->rs1);
+ return do_csrrw(ctx, a->rd, a->csr, ctx->zero, mask);
+}
diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc
new file mode 100644
index 000000000..2af0e5c13
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvm.c.inc
@@ -0,0 +1,271 @@
+/*
+ * RISC-V translation routines for the RV64M Standard Extension.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
+ * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+static bool trans_mul(DisasContext *ctx, arg_mul *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
+}
+
+static void gen_mulh(TCGv ret, TCGv s1, TCGv s2)
+{
+ TCGv discard = tcg_temp_new();
+
+ tcg_gen_muls2_tl(discard, ret, s1, s2);
+ tcg_temp_free(discard);
+}
+
+static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2)
+{
+ tcg_gen_mul_tl(ret, s1, s2);
+ tcg_gen_sari_tl(ret, ret, 32);
+}
+
+static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w);
+}
+
+static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv rl = tcg_temp_new();
+ TCGv rh = tcg_temp_new();
+
+ tcg_gen_mulu2_tl(rl, rh, arg1, arg2);
+ /* fix up for one negative */
+ tcg_gen_sari_tl(rl, arg1, TARGET_LONG_BITS - 1);
+ tcg_gen_and_tl(rl, rl, arg2);
+ tcg_gen_sub_tl(ret, rh, rl);
+
+ tcg_temp_free(rl);
+ tcg_temp_free(rh);
+}
+
+static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2)
+{
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+
+ tcg_gen_ext32s_tl(t1, arg1);
+ tcg_gen_ext32u_tl(t2, arg2);
+ tcg_gen_mul_tl(ret, t1, t2);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ tcg_gen_sari_tl(ret, ret, 32);
+}
+
+static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w);
+}
+
+static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2)
+{
+ TCGv discard = tcg_temp_new();
+
+ tcg_gen_mulu2_tl(discard, ret, s1, s2);
+ tcg_temp_free(discard);
+}
+
+static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ /* gen_mulh_w works for either sign as input. */
+ return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w);
+}
+
+static void gen_div(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp1, temp2, zero, one, mone, min;
+
+ temp1 = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+ mone = tcg_constant_tl(-1);
+ min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
+
+ /*
+ * If overflow, set temp2 to 1, else source2.
+ * This produces the required result of min.
+ */
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
+ tcg_gen_and_tl(temp1, temp1, temp2);
+ tcg_gen_movcond_tl(TCG_COND_NE, temp2, temp1, zero, one, source2);
+
+ /*
+ * If div by zero, set temp1 to -1 and temp2 to 1 to
+ * produce the required result of -1.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, mone, source1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, temp2);
+
+ tcg_gen_div_tl(ret, temp1, temp2);
+
+ tcg_temp_free(temp1);
+ tcg_temp_free(temp2);
+}
+
+static bool trans_div(DisasContext *ctx, arg_div *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_SIGN, gen_div);
+}
+
+static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp1, temp2, zero, one, max;
+
+ temp1 = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+ max = tcg_constant_tl(~0);
+
+ /*
+ * If div by zero, set temp1 to max and temp2 to 1 to
+ * produce the required result of max.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp1, source2, zero, max, source1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
+ tcg_gen_divu_tl(ret, temp1, temp2);
+
+ tcg_temp_free(temp1);
+ tcg_temp_free(temp2);
+}
+
+static bool trans_divu(DisasContext *ctx, arg_divu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_ZERO, gen_divu);
+}
+
+static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp1, temp2, zero, one, mone, min;
+
+ temp1 = tcg_temp_new();
+ temp2 = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+ mone = tcg_constant_tl(-1);
+ min = tcg_constant_tl(1ull << (TARGET_LONG_BITS - 1));
+
+ /*
+ * If overflow, set temp1 to 0, else source1.
+ * This avoids a possible host trap, and produces the required result of 0.
+ */
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp1, source1, min);
+ tcg_gen_setcond_tl(TCG_COND_EQ, temp2, source2, mone);
+ tcg_gen_and_tl(temp1, temp1, temp2);
+ tcg_gen_movcond_tl(TCG_COND_NE, temp1, temp1, zero, zero, source1);
+
+ /*
+ * If div by zero, set temp2 to 1, else source2.
+ * This avoids a possible host trap, but produces an incorrect result.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp2, source2, zero, one, source2);
+
+ tcg_gen_rem_tl(temp1, temp1, temp2);
+
+ /* If div by zero, the required result is the original dividend. */
+ tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp1);
+
+ tcg_temp_free(temp1);
+ tcg_temp_free(temp2);
+}
+
+static bool trans_rem(DisasContext *ctx, arg_rem *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_SIGN, gen_rem);
+}
+
+static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
+{
+ TCGv temp, zero, one;
+
+ temp = tcg_temp_new();
+ zero = tcg_constant_tl(0);
+ one = tcg_constant_tl(1);
+
+ /*
+ * If div by zero, set temp to 1, else source2.
+ * This avoids a possible host trap, but produces an incorrect result.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, temp, source2, zero, one, source2);
+
+ tcg_gen_remu_tl(temp, source1, temp);
+
+ /* If div by zero, the required result is the original dividend. */
+ tcg_gen_movcond_tl(TCG_COND_EQ, ret, source2, zero, source1, temp);
+
+ tcg_temp_free(temp);
+}
+
+static bool trans_remu(DisasContext *ctx, arg_remu *a)
+{
+ REQUIRE_EXT(ctx, RVM);
+ return gen_arith(ctx, a, EXT_ZERO, gen_remu);
+}
+
+static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl);
+}
+
+static bool trans_divw(DisasContext *ctx, arg_divw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_SIGN, gen_div);
+}
+
+static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_ZERO, gen_divu);
+}
+
+static bool trans_remw(DisasContext *ctx, arg_remw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_SIGN, gen_rem);
+}
+
+static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_EXT(ctx, RVM);
+ ctx->ol = MXL_RV32;
+ return gen_arith(ctx, a, EXT_ZERO, gen_remu);
+}
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
new file mode 100644
index 000000000..17ee3babe
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -0,0 +1,2867 @@
+/*
+ * RISC-V translation routines for the RVV Standard Extension.
+ *
+ * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "tcg/tcg-op-gvec.h"
+#include "tcg/tcg-gvec-desc.h"
+#include "internals.h"
+
+static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a)
+{
+ TCGv s1, s2, dst;
+
+ if (!has_ext(ctx, RVV)) {
+ return false;
+ }
+
+ s2 = get_gpr(ctx, a->rs2, EXT_ZERO);
+ dst = dest_gpr(ctx, a->rd);
+
+ /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
+ if (a->rs1 == 0) {
+ /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
+ s1 = tcg_constant_tl(RV_VLEN_MAX);
+ } else {
+ s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ }
+ gen_helper_vsetvl(dst, cpu_env, s1, s2);
+ gen_set_gpr(ctx, a->rd, dst);
+
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ tcg_gen_lookup_and_goto_ptr();
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a)
+{
+ TCGv s1, s2, dst;
+
+ if (!has_ext(ctx, RVV)) {
+ return false;
+ }
+
+ s2 = tcg_constant_tl(a->zimm);
+ dst = dest_gpr(ctx, a->rd);
+
+ /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
+ if (a->rs1 == 0) {
+ /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
+ s1 = tcg_constant_tl(RV_VLEN_MAX);
+ } else {
+ s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ }
+ gen_helper_vsetvl(dst, cpu_env, s1, s2);
+ gen_set_gpr(ctx, a->rd, dst);
+
+ gen_goto_tb(ctx, 0, ctx->pc_succ_insn);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
+
+/* vector register offset from env */
+static uint32_t vreg_ofs(DisasContext *s, int reg)
+{
+ return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8;
+}
+
+/* check functions */
+
+/*
+ * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
+ * So RVV is also be checked in this function.
+ */
+static bool vext_check_isa_ill(DisasContext *s)
+{
+ return !s->vill;
+}
+
+/*
+ * There are two rules check here.
+ *
+ * 1. Vector register numbers are multiples of LMUL. (Section 3.2)
+ *
+ * 2. For all widening instructions, the destination LMUL value must also be
+ * a supported LMUL value. (Section 11.2)
+ */
+static bool vext_check_reg(DisasContext *s, uint32_t reg, bool widen)
+{
+ /*
+ * The destination vector register group results are arranged as if both
+ * SEW and LMUL were at twice their current settings. (Section 11.2).
+ */
+ int legal = widen ? 2 << s->lmul : 1 << s->lmul;
+
+ return !((s->lmul == 0x3 && widen) || (reg % legal));
+}
+
+/*
+ * There are two rules check here.
+ *
+ * 1. The destination vector register group for a masked vector instruction can
+ * only overlap the source mask register (v0) when LMUL=1. (Section 5.3)
+ *
+ * 2. In widen instructions and some other insturctions, like vslideup.vx,
+ * there is no need to check whether LMUL=1.
+ */
+static bool vext_check_overlap_mask(DisasContext *s, uint32_t vd, bool vm,
+ bool force)
+{
+ return (vm != 0 || vd != 0) || (!force && (s->lmul == 0));
+}
+
+/* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */
+static bool vext_check_nf(DisasContext *s, uint32_t nf)
+{
+ return (1 << s->lmul) * nf <= 8;
+}
+
+/*
+ * The destination vector register group cannot overlap a source vector register
+ * group of a different element width. (Section 11.2)
+ */
+static inline bool vext_check_overlap_group(int rd, int dlen, int rs, int slen)
+{
+ return ((rd >= rs + slen) || (rs >= rd + dlen));
+}
+/* common translation macro */
+#define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\
+{ \
+ if (CHECK(s, a)) { \
+ return OP(s, a, SEQ); \
+ } \
+ return false; \
+}
+
+/*
+ *** unit stride load and store
+ */
+typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv,
+ TCGv_env, TCGv_i32);
+
+static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
+ gen_helper_ldst_us *fn, DisasContext *s)
+{
+ TCGv_ptr dest, mask;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+
+ /*
+ * As simd_desc supports at most 256 bytes, and in this implementation,
+ * the max vector group length is 2048 bytes. So split it into two parts.
+ *
+ * The first part is vlen in bytes, encoded in maxsz of simd_desc.
+ * The second part is lmul, encoded in data of simd_desc.
+ */
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_us *fn;
+ static gen_helper_ldst_us * const fns[2][7][4] = {
+ /* masked unit stride load */
+ { { gen_helper_vlb_v_b_mask, gen_helper_vlb_v_h_mask,
+ gen_helper_vlb_v_w_mask, gen_helper_vlb_v_d_mask },
+ { NULL, gen_helper_vlh_v_h_mask,
+ gen_helper_vlh_v_w_mask, gen_helper_vlh_v_d_mask },
+ { NULL, NULL,
+ gen_helper_vlw_v_w_mask, gen_helper_vlw_v_d_mask },
+ { gen_helper_vle_v_b_mask, gen_helper_vle_v_h_mask,
+ gen_helper_vle_v_w_mask, gen_helper_vle_v_d_mask },
+ { gen_helper_vlbu_v_b_mask, gen_helper_vlbu_v_h_mask,
+ gen_helper_vlbu_v_w_mask, gen_helper_vlbu_v_d_mask },
+ { NULL, gen_helper_vlhu_v_h_mask,
+ gen_helper_vlhu_v_w_mask, gen_helper_vlhu_v_d_mask },
+ { NULL, NULL,
+ gen_helper_vlwu_v_w_mask, gen_helper_vlwu_v_d_mask } },
+ /* unmasked unit stride load */
+ { { gen_helper_vlb_v_b, gen_helper_vlb_v_h,
+ gen_helper_vlb_v_w, gen_helper_vlb_v_d },
+ { NULL, gen_helper_vlh_v_h,
+ gen_helper_vlh_v_w, gen_helper_vlh_v_d },
+ { NULL, NULL,
+ gen_helper_vlw_v_w, gen_helper_vlw_v_d },
+ { gen_helper_vle_v_b, gen_helper_vle_v_h,
+ gen_helper_vle_v_w, gen_helper_vle_v_d },
+ { gen_helper_vlbu_v_b, gen_helper_vlbu_v_h,
+ gen_helper_vlbu_v_w, gen_helper_vlbu_v_d },
+ { NULL, gen_helper_vlhu_v_h,
+ gen_helper_vlhu_v_w, gen_helper_vlhu_v_d },
+ { NULL, NULL,
+ gen_helper_vlwu_v_w, gen_helper_vlwu_v_d } }
+ };
+
+ fn = fns[a->vm][seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_us_trans(a->rd, a->rs1, data, fn, s);
+}
+
+static bool ld_us_check(DisasContext *s, arg_r2nfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vlb_v, 0, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlh_v, 1, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlw_v, 2, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vle_v, 3, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlbu_v, 4, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlhu_v, 5, r2nfvm, ld_us_op, ld_us_check)
+GEN_VEXT_TRANS(vlwu_v, 6, r2nfvm, ld_us_op, ld_us_check)
+
+static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_us *fn;
+ static gen_helper_ldst_us * const fns[2][4][4] = {
+ /* masked unit stride load and store */
+ { { gen_helper_vsb_v_b_mask, gen_helper_vsb_v_h_mask,
+ gen_helper_vsb_v_w_mask, gen_helper_vsb_v_d_mask },
+ { NULL, gen_helper_vsh_v_h_mask,
+ gen_helper_vsh_v_w_mask, gen_helper_vsh_v_d_mask },
+ { NULL, NULL,
+ gen_helper_vsw_v_w_mask, gen_helper_vsw_v_d_mask },
+ { gen_helper_vse_v_b_mask, gen_helper_vse_v_h_mask,
+ gen_helper_vse_v_w_mask, gen_helper_vse_v_d_mask } },
+ /* unmasked unit stride store */
+ { { gen_helper_vsb_v_b, gen_helper_vsb_v_h,
+ gen_helper_vsb_v_w, gen_helper_vsb_v_d },
+ { NULL, gen_helper_vsh_v_h,
+ gen_helper_vsh_v_w, gen_helper_vsh_v_d },
+ { NULL, NULL,
+ gen_helper_vsw_v_w, gen_helper_vsw_v_d },
+ { gen_helper_vse_v_b, gen_helper_vse_v_h,
+ gen_helper_vse_v_w, gen_helper_vse_v_d } }
+ };
+
+ fn = fns[a->vm][seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_us_trans(a->rd, a->rs1, data, fn, s);
+}
+
+static bool st_us_check(DisasContext *s, arg_r2nfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vsb_v, 0, r2nfvm, st_us_op, st_us_check)
+GEN_VEXT_TRANS(vsh_v, 1, r2nfvm, st_us_op, st_us_check)
+GEN_VEXT_TRANS(vsw_v, 2, r2nfvm, st_us_op, st_us_check)
+GEN_VEXT_TRANS(vse_v, 3, r2nfvm, st_us_op, st_us_check)
+
+/*
+ *** stride load and store
+ */
+typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv,
+ TCGv, TCGv_env, TCGv_i32);
+
+static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
+ uint32_t data, gen_helper_ldst_stride *fn,
+ DisasContext *s)
+{
+ TCGv_ptr dest, mask;
+ TCGv base, stride;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ stride = get_gpr(s, rs2, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, stride, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_stride *fn;
+ static gen_helper_ldst_stride * const fns[7][4] = {
+ { gen_helper_vlsb_v_b, gen_helper_vlsb_v_h,
+ gen_helper_vlsb_v_w, gen_helper_vlsb_v_d },
+ { NULL, gen_helper_vlsh_v_h,
+ gen_helper_vlsh_v_w, gen_helper_vlsh_v_d },
+ { NULL, NULL,
+ gen_helper_vlsw_v_w, gen_helper_vlsw_v_d },
+ { gen_helper_vlse_v_b, gen_helper_vlse_v_h,
+ gen_helper_vlse_v_w, gen_helper_vlse_v_d },
+ { gen_helper_vlsbu_v_b, gen_helper_vlsbu_v_h,
+ gen_helper_vlsbu_v_w, gen_helper_vlsbu_v_d },
+ { NULL, gen_helper_vlshu_v_h,
+ gen_helper_vlshu_v_w, gen_helper_vlshu_v_d },
+ { NULL, NULL,
+ gen_helper_vlswu_v_w, gen_helper_vlswu_v_d },
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+static bool ld_stride_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vlsb_v, 0, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlsh_v, 1, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlsw_v, 2, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlse_v, 3, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlsbu_v, 4, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlshu_v, 5, rnfvm, ld_stride_op, ld_stride_check)
+GEN_VEXT_TRANS(vlswu_v, 6, rnfvm, ld_stride_op, ld_stride_check)
+
+static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_stride *fn;
+ static gen_helper_ldst_stride * const fns[4][4] = {
+ /* masked stride store */
+ { gen_helper_vssb_v_b, gen_helper_vssb_v_h,
+ gen_helper_vssb_v_w, gen_helper_vssb_v_d },
+ { NULL, gen_helper_vssh_v_h,
+ gen_helper_vssh_v_w, gen_helper_vssh_v_d },
+ { NULL, NULL,
+ gen_helper_vssw_v_w, gen_helper_vssw_v_d },
+ { gen_helper_vsse_v_b, gen_helper_vsse_v_h,
+ gen_helper_vsse_v_w, gen_helper_vsse_v_d }
+ };
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+static bool st_stride_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check)
+GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check)
+GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check)
+GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check)
+
+/*
+ *** index load and store
+ */
+typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv,
+ TCGv_ptr, TCGv_env, TCGv_i32);
+
+static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
+ uint32_t data, gen_helper_ldst_index *fn,
+ DisasContext *s)
+{
+ TCGv_ptr dest, mask, index;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ index = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, index, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(index);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_index *fn;
+ static gen_helper_ldst_index * const fns[7][4] = {
+ { gen_helper_vlxb_v_b, gen_helper_vlxb_v_h,
+ gen_helper_vlxb_v_w, gen_helper_vlxb_v_d },
+ { NULL, gen_helper_vlxh_v_h,
+ gen_helper_vlxh_v_w, gen_helper_vlxh_v_d },
+ { NULL, NULL,
+ gen_helper_vlxw_v_w, gen_helper_vlxw_v_d },
+ { gen_helper_vlxe_v_b, gen_helper_vlxe_v_h,
+ gen_helper_vlxe_v_w, gen_helper_vlxe_v_d },
+ { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h,
+ gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d },
+ { NULL, gen_helper_vlxhu_v_h,
+ gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d },
+ { NULL, NULL,
+ gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d },
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+/*
+ * For vector indexed segment loads, the destination vector register
+ * groups cannot overlap the source vector register group (specified by
+ * `vs2`), else an illegal instruction exception is raised.
+ */
+static bool ld_index_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_nf(s, a->nf) &&
+ ((a->nf == 1) ||
+ vext_check_overlap_group(a->rd, a->nf << s->lmul,
+ a->rs2, 1 << s->lmul)));
+}
+
+GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check)
+GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check)
+
+static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_index *fn;
+ static gen_helper_ldst_index * const fns[4][4] = {
+ { gen_helper_vsxb_v_b, gen_helper_vsxb_v_h,
+ gen_helper_vsxb_v_w, gen_helper_vsxb_v_d },
+ { NULL, gen_helper_vsxh_v_h,
+ gen_helper_vsxh_v_w, gen_helper_vsxh_v_d },
+ { NULL, NULL,
+ gen_helper_vsxw_v_w, gen_helper_vsxw_v_d },
+ { gen_helper_vsxe_v_b, gen_helper_vsxe_v_h,
+ gen_helper_vsxe_v_w, gen_helper_vsxe_v_d }
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+
+static bool st_index_check(DisasContext *s, arg_rnfvm* a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_nf(s, a->nf));
+}
+
+GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check)
+GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check)
+GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check)
+GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check)
+
+/*
+ *** unit stride fault-only-first load
+ */
+static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
+ gen_helper_ldst_us *fn, DisasContext *s)
+{
+ TCGv_ptr dest, mask;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ gen_set_label(over);
+ return true;
+}
+
+static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_ldst_us *fn;
+ static gen_helper_ldst_us * const fns[7][4] = {
+ { gen_helper_vlbff_v_b, gen_helper_vlbff_v_h,
+ gen_helper_vlbff_v_w, gen_helper_vlbff_v_d },
+ { NULL, gen_helper_vlhff_v_h,
+ gen_helper_vlhff_v_w, gen_helper_vlhff_v_d },
+ { NULL, NULL,
+ gen_helper_vlwff_v_w, gen_helper_vlwff_v_d },
+ { gen_helper_vleff_v_b, gen_helper_vleff_v_h,
+ gen_helper_vleff_v_w, gen_helper_vleff_v_d },
+ { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h,
+ gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d },
+ { NULL, gen_helper_vlhuff_v_h,
+ gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d },
+ { NULL, NULL,
+ gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d }
+ };
+
+ fn = fns[seq][s->sew];
+ if (fn == NULL) {
+ return false;
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, NF, a->nf);
+ return ldff_trans(a->rd, a->rs1, data, fn, s);
+}
+
+GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check)
+GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check)
+
+/*
+ *** vector atomic operation
+ */
+typedef void gen_helper_amo(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
+ TCGv_env, TCGv_i32);
+
+static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
+ uint32_t data, gen_helper_amo *fn, DisasContext *s)
+{
+ TCGv_ptr dest, mask, index;
+ TCGv base;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ index = tcg_temp_new_ptr();
+ base = get_gpr(s, rs1, EXT_NONE);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, base, index, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(index);
+ gen_set_label(over);
+ return true;
+}
+
+static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq)
+{
+ uint32_t data = 0;
+ gen_helper_amo *fn;
+ static gen_helper_amo *const fnsw[9] = {
+ /* no atomic operation */
+ gen_helper_vamoswapw_v_w,
+ gen_helper_vamoaddw_v_w,
+ gen_helper_vamoxorw_v_w,
+ gen_helper_vamoandw_v_w,
+ gen_helper_vamoorw_v_w,
+ gen_helper_vamominw_v_w,
+ gen_helper_vamomaxw_v_w,
+ gen_helper_vamominuw_v_w,
+ gen_helper_vamomaxuw_v_w
+ };
+ static gen_helper_amo *const fnsd[18] = {
+ gen_helper_vamoswapw_v_d,
+ gen_helper_vamoaddw_v_d,
+ gen_helper_vamoxorw_v_d,
+ gen_helper_vamoandw_v_d,
+ gen_helper_vamoorw_v_d,
+ gen_helper_vamominw_v_d,
+ gen_helper_vamomaxw_v_d,
+ gen_helper_vamominuw_v_d,
+ gen_helper_vamomaxuw_v_d,
+ gen_helper_vamoswapd_v_d,
+ gen_helper_vamoaddd_v_d,
+ gen_helper_vamoxord_v_d,
+ gen_helper_vamoandd_v_d,
+ gen_helper_vamoord_v_d,
+ gen_helper_vamomind_v_d,
+ gen_helper_vamomaxd_v_d,
+ gen_helper_vamominud_v_d,
+ gen_helper_vamomaxud_v_d
+ };
+
+ if (tb_cflags(s->base.tb) & CF_PARALLEL) {
+ gen_helper_exit_atomic(cpu_env);
+ s->base.is_jmp = DISAS_NORETURN;
+ return true;
+ }
+
+ switch (s->sew) {
+ case 0 ... 2:
+ assert(seq < ARRAY_SIZE(fnsw));
+ fn = fnsw[seq];
+ break;
+ case 3:
+ /* XLEN check done in amo_check(). */
+ assert(seq < ARRAY_SIZE(fnsd));
+ fn = fnsd[seq];
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ data = FIELD_DP32(data, VDATA, WD, a->wd);
+ return amo_trans(a->rd, a->rs1, a->rs2, data, fn, s);
+}
+/*
+ * There are two rules check here.
+ *
+ * 1. SEW must be at least as wide as the AMO memory element size.
+ *
+ * 2. If SEW is greater than XLEN, an illegal instruction exception is raised.
+ */
+static bool amo_check(DisasContext *s, arg_rwdvm* a)
+{
+ return (!s->vill && has_ext(s, RVA) &&
+ (!a->wd || vext_check_overlap_mask(s, a->rd, a->vm, false)) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ ((1 << s->sew) <= sizeof(target_ulong)) &&
+ ((1 << s->sew) >= 4));
+}
+
+static bool amo_check64(DisasContext *s, arg_rwdvm* a)
+{
+ REQUIRE_64BIT(s);
+ return amo_check(s, a);
+}
+
+GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64)
+
+/*
+ *** Vector Integer Arithmetic Instructions
+ */
+#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
+
+static bool opivv_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false));
+}
+
+typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
+ uint32_t, uint32_t, uint32_t);
+
+static inline bool
+do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
+ gen_helper_gvec_4_ptr *fn)
+{
+ TCGLabel *over = gen_new_label();
+ if (!opivv_check(s, a)) {
+ return false;
+ }
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ if (a->vm && s->vl_eq_vlmax) {
+ gvec_fn(s->sew, vreg_ofs(s, a->rd),
+ vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
+ MAXSZ(s), MAXSZ(s));
+ } else {
+ uint32_t data = 0;
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
+ }
+ gen_set_label(over);
+ return true;
+}
+
+/* OPIVV with GVEC IR */
+#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_gvec_4_ptr * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
+}
+
+GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
+GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
+
+typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
+ TCGv_env, TCGv_i32);
+
+static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
+ gen_helper_opivx *fn, DisasContext *s)
+{
+ TCGv_ptr dest, src2, mask;
+ TCGv src1;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ src1 = get_gpr(s, rs1, EXT_NONE);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, src1, src2, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ gen_set_label(over);
+ return true;
+}
+
+static bool opivx_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false));
+}
+
+typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
+ uint32_t, uint32_t);
+
+static inline bool
+do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
+ gen_helper_opivx *fn)
+{
+ if (!opivx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ TCGv_i64 src1 = tcg_temp_new_i64();
+
+ tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ src1, MAXSZ(s), MAXSZ(s));
+
+ tcg_temp_free_i64(src1);
+ return true;
+ }
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+}
+
+/* OPIVX with GVEC IR */
+#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
+}
+
+GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
+GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
+
+static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+ tcg_gen_vec_sub8_i64(d, b, a);
+}
+
+static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+ tcg_gen_vec_sub16_i64(d, b, a);
+}
+
+static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+ tcg_gen_sub_i32(ret, arg2, arg1);
+}
+
+static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+ tcg_gen_sub_i64(ret, arg2, arg1);
+}
+
+static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
+{
+ tcg_gen_sub_vec(vece, r, b, a);
+}
+
+static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
+ TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
+{
+ static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
+ static const GVecGen2s rsub_op[4] = {
+ { .fni8 = gen_vec_rsub8_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs8,
+ .opt_opc = vecop_list,
+ .vece = MO_8 },
+ { .fni8 = gen_vec_rsub16_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs16,
+ .opt_opc = vecop_list,
+ .vece = MO_16 },
+ { .fni4 = gen_rsub_i32,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs32,
+ .opt_opc = vecop_list,
+ .vece = MO_32 },
+ { .fni8 = gen_rsub_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs64,
+ .opt_opc = vecop_list,
+ .prefer_i64 = TCG_TARGET_REG_BITS == 64,
+ .vece = MO_64 },
+ };
+
+ tcg_debug_assert(vece <= MO_64);
+ tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
+}
+
+GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
+
+static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
+ gen_helper_opivx *fn, DisasContext *s, int zx)
+{
+ TCGv_ptr dest, src2, mask;
+ TCGv src1;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ if (zx) {
+ src1 = tcg_constant_tl(imm);
+ } else {
+ src1 = tcg_constant_tl(sextract64(imm, 0, 5));
+ }
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, src1, src2, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ gen_set_label(over);
+ return true;
+}
+
+typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
+ uint32_t, uint32_t);
+
+static inline bool
+do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
+ gen_helper_opivx *fn, int zx)
+{
+ if (!opivx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ if (zx) {
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
+ } else {
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
+ }
+ } else {
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx);
+ }
+ return true;
+}
+
+/* OPIVI with GVEC IR */
+#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
+ gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
+ }; \
+ return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \
+ fns[s->sew], ZX); \
+}
+
+GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi)
+
+static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t c, uint32_t oprsz, uint32_t maxsz)
+{
+ TCGv_i64 tmp = tcg_constant_i64(c);
+ tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
+}
+
+GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi)
+
+/* Vector Widening Integer Add/Subtract */
+
+/* OPIVV with WIDEN */
+static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_gvec_4_ptr *fn,
+ bool (*checkfn)(DisasContext *, arg_rmrr *))
+{
+ if (checkfn(s, a)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1),
+ vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8,
+ data, fn);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opivv_widen(s, a, fns[s->sew], CHECK); \
+}
+
+GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
+
+/* OPIVX with WIDEN */
+static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_opivx *fn)
+{
+ if (opivx_widen_check(s, a)) {
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+ }
+ return false;
+}
+
+#define GEN_OPIVX_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opivx_widen(s, a, fns[s->sew]); \
+}
+
+GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
+
+/* WIDEN OPIVV with WIDEN */
+static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_gvec_4_ptr *fn)
+{
+ if (opiwv_widen_check(s, a)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1),
+ vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+#define GEN_OPIWV_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opiwv_widen(s, a, fns[s->sew]); \
+}
+
+GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
+GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
+GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
+GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
+
+/* WIDEN OPIVX with WIDEN */
+static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
+ gen_helper_opivx *fn)
+{
+ if (opiwx_widen_check(s, a)) {
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+ }
+ return false;
+}
+
+#define GEN_OPIWX_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w \
+ }; \
+ return do_opiwx_widen(s, a, fns[s->sew]); \
+}
+
+GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
+GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
+GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
+GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
+
+/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
+/* OPIVV without GVEC IR */
+#define GEN_OPIVV_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+/*
+ * For vadc and vsbc, an illegal instruction exception is raised if the
+ * destination vector register is v0 and LMUL > 1. (Section 12.3)
+ */
+static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ ((a->rd != 0) || (s->lmul == 0)));
+}
+
+GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
+GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
+
+/*
+ * For vmadc and vmsbc, an illegal instruction exception is raised if the
+ * destination vector register overlaps a source vector register group.
+ */
+static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
+}
+
+GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
+GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
+
+static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ ((a->rd != 0) || (s->lmul == 0)));
+}
+
+/* OPIVX without GVEC IR */
+#define GEN_OPIVX_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ \
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
+ } \
+ return false; \
+}
+
+GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
+GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
+
+static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
+}
+
+GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
+GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
+
+/* OPIVI without GVEC IR */
+#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
+ gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
+ }; \
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
+ fns[s->sew], s, ZX); \
+ } \
+ return false; \
+}
+
+GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check)
+GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check)
+
+/* Vector Bitwise Logical Instructions */
+GEN_OPIVV_GVEC_TRANS(vand_vv, and)
+GEN_OPIVV_GVEC_TRANS(vor_vv, or)
+GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
+GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
+GEN_OPIVX_GVEC_TRANS(vor_vx, ors)
+GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
+GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi)
+GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori)
+GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori)
+
+/* Vector Single-Width Bit Shift Instructions */
+GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv)
+GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv)
+GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv)
+
+typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
+ uint32_t, uint32_t);
+
+static inline bool
+do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
+ gen_helper_opivx *fn)
+{
+ if (!opivx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ TCGv_i32 src1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
+ tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ src1, MAXSZ(s), MAXSZ(s));
+
+ tcg_temp_free_i32(src1);
+ return true;
+ }
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
+}
+
+#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ static gen_helper_opivx * const fns[4] = { \
+ gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
+ }; \
+ \
+ return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
+}
+
+GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls)
+GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs)
+GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars)
+
+GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli)
+GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri)
+GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari)
+
+/* Vector Narrowing Integer Right Shift Instructions */
+static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
+ 2 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+/* OPIVV with NARROW */
+#define GEN_OPIVV_NARROW_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opivv_narrow_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+GEN_OPIVV_NARROW_TRANS(vnsra_vv)
+GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
+
+static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
+ 2 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3));
+}
+
+/* OPIVX with NARROW */
+#define GEN_OPIVX_NARROW_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opivx_narrow_check(s, a)) { \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##NAME##_b, \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
+ } \
+ return false; \
+}
+
+GEN_OPIVX_NARROW_TRANS(vnsra_vx)
+GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
+
+/* OPIVI with NARROW */
+#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opivx_narrow_check(s, a)) { \
+ static gen_helper_opivx * const fns[3] = { \
+ gen_helper_##OPIVX##_b, \
+ gen_helper_##OPIVX##_h, \
+ gen_helper_##OPIVX##_w, \
+ }; \
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
+ fns[s->sew], s, ZX); \
+ } \
+ return false; \
+}
+
+GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx)
+GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx)
+
+/* Vector Integer Comparison Instructions */
+/*
+ * For all comparison instructions, an illegal instruction exception is raised
+ * if the destination vector register overlaps a source vector register group
+ * and LMUL > 1.
+ */
+static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
+ (s->lmul == 0)));
+}
+GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
+GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
+
+static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
+ (s->lmul == 0)));
+}
+
+GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
+GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
+
+GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check)
+GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check)
+
+/* Vector Integer Min/Max Instructions */
+GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
+GEN_OPIVV_GVEC_TRANS(vmin_vv, smin)
+GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
+GEN_OPIVV_GVEC_TRANS(vmax_vv, smax)
+GEN_OPIVX_TRANS(vminu_vx, opivx_check)
+GEN_OPIVX_TRANS(vmin_vx, opivx_check)
+GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
+GEN_OPIVX_TRANS(vmax_vx, opivx_check)
+
+/* Vector Single-Width Integer Multiply Instructions */
+GEN_OPIVV_GVEC_TRANS(vmul_vv, mul)
+GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
+GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
+GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
+GEN_OPIVX_GVEC_TRANS(vmul_vx, muls)
+GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
+GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
+GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
+
+/* Vector Integer Divide Instructions */
+GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
+GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
+GEN_OPIVV_TRANS(vremu_vv, opivv_check)
+GEN_OPIVV_TRANS(vrem_vv, opivv_check)
+GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
+GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
+GEN_OPIVX_TRANS(vremu_vx, opivx_check)
+GEN_OPIVX_TRANS(vrem_vx, opivx_check)
+
+/* Vector Widening Integer Multiply Instructions */
+GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
+GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
+
+/* Vector Single-Width Integer Multiply-Add Instructions */
+GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
+GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
+GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
+GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
+GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
+GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
+GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
+GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
+
+/* Vector Widening Integer Multiply-Add Instructions */
+GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
+GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
+
+/* Vector Integer Merge and Move Instructions */
+static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs1, false)) {
+
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
+ vreg_ofs(s, a->rs1),
+ MAXSZ(s), MAXSZ(s));
+ } else {
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_gvec_2_ptr * const fns[4] = {
+ gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
+ gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
+ cpu_env, s->vlen / 8, s->vlen / 8, data,
+ fns[s->sew]);
+ gen_set_label(over);
+ }
+ return true;
+ }
+ return false;
+}
+
+typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
+static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false)) {
+
+ TCGv s1;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ s1 = get_gpr(s, a->rs1, EXT_SIGN);
+
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), s1);
+ } else {
+ TCGv_i32 desc;
+ TCGv_i64 s1_i64 = tcg_temp_new_i64();
+ TCGv_ptr dest = tcg_temp_new_ptr();
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_vmv_vx * const fns[4] = {
+ gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
+ gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
+ };
+
+ tcg_gen_ext_tl_i64(s1_i64, s1);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
+ fns[s->sew](dest, s1_i64, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_i64(s1_i64);
+ }
+
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false)) {
+
+ int64_t simm = sextract64(a->rs1, 0, 5);
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), simm);
+ } else {
+ TCGv_i32 desc;
+ TCGv_i64 s1;
+ TCGv_ptr dest;
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_vmv_vx * const fns[4] = {
+ gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
+ gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ s1 = tcg_constant_i64(simm);
+ dest = tcg_temp_new_ptr();
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
+ fns[s->sew](dest, s1, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ gen_set_label(over);
+ }
+ return true;
+ }
+ return false;
+}
+
+GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
+GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
+GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check)
+
+/*
+ *** Vector Fixed-Point Arithmetic Instructions
+ */
+
+/* Vector Single-Width Saturating Add and Subtract */
+GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
+GEN_OPIVV_TRANS(vsadd_vv, opivv_check)
+GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
+GEN_OPIVV_TRANS(vssub_vv, opivv_check)
+GEN_OPIVX_TRANS(vsaddu_vx, opivx_check)
+GEN_OPIVX_TRANS(vsadd_vx, opivx_check)
+GEN_OPIVX_TRANS(vssubu_vx, opivx_check)
+GEN_OPIVX_TRANS(vssub_vx, opivx_check)
+GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check)
+GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check)
+
+/* Vector Single-Width Averaging Add and Subtract */
+GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
+GEN_OPIVV_TRANS(vasub_vv, opivv_check)
+GEN_OPIVX_TRANS(vaadd_vx, opivx_check)
+GEN_OPIVX_TRANS(vasub_vx, opivx_check)
+GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
+
+/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
+GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
+GEN_OPIVX_TRANS(vsmul_vx, opivx_check)
+
+/* Vector Widening Saturating Scaled Multiply-Add */
+GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
+GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
+GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
+GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
+
+/* Vector Single-Width Scaling Shift Instructions */
+GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
+GEN_OPIVV_TRANS(vssra_vv, opivv_check)
+GEN_OPIVX_TRANS(vssrl_vx, opivx_check)
+GEN_OPIVX_TRANS(vssra_vx, opivx_check)
+GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check)
+GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check)
+
+/* Vector Narrowing Fixed-Point Clip Instructions */
+GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
+GEN_OPIVV_NARROW_TRANS(vnclip_vv)
+GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
+GEN_OPIVX_NARROW_TRANS(vnclip_vx)
+GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx)
+GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx)
+
+/*
+ *** Vector Float Point Arithmetic Instructions
+ */
+/* Vector Single-Width Floating-Point Add/Subtract Instructions */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised.
+ */
+static bool opfvv_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ (s->sew != 0));
+}
+
+/* OPFVV without GVEC IR */
+#define GEN_OPFVV_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[3] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ gen_helper_##NAME##_d, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
+
+typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
+ TCGv_env, TCGv_i32);
+
+static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
+ uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
+{
+ TCGv_ptr dest, src2, mask;
+ TCGv_i32 desc;
+
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ gen_set_label(over);
+ return true;
+}
+
+static bool opfvf_check(DisasContext *s, arg_rmrr *a)
+{
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (s->sew != 0));
+}
+
+/* OPFVF without GVEC IR */
+#define GEN_OPFVF_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_opfvf *const fns[3] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ gen_helper_##NAME##_d, \
+ }; \
+ gen_set_rm(s, 7); \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
+ fns[s->sew - 1], s); \
+ } \
+ return false; \
+}
+
+GEN_OPFVF_TRANS(vfadd_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfsub_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check)
+
+/* Vector Widening Floating-Point Add/Subtract Instructions */
+static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* OPFVV with WIDEN */
+#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
+
+static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* OPFVF with WIDEN */
+#define GEN_OPFVF_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opfvf_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_opfvf *const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ gen_set_rm(s, 7); \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
+ fns[s->sew - 1], s); \
+ } \
+ return false; \
+}
+
+GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
+
+static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* WIDEN OPFVV with WIDEN */
+#define GEN_OPFWV_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opfwv_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_4_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
+GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
+
+static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, true) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+/* WIDEN OPFVF with WIDEN */
+#define GEN_OPFWF_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
+{ \
+ if (opfwf_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_opfvf *const fns[2] = { \
+ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
+ }; \
+ gen_set_rm(s, 7); \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
+ fns[s->sew - 1], s); \
+ } \
+ return false; \
+}
+
+GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
+GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
+
+/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
+GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfmul_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check)
+
+/* Vector Widening Floating-Point Multiply */
+GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
+GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
+
+/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
+GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
+
+/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
+GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
+GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
+GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
+GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
+
+/* Vector Floating-Point Square-Root Instruction */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+static bool opfv_check(DisasContext *s, arg_rmr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (s->sew != 0));
+}
+
+#define GEN_OPFV_TRANS(NAME, CHECK) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (CHECK(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_3_ptr * const fns[3] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ gen_helper_##NAME##_d, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
+
+/* Vector Floating-Point MIN/MAX Instructions */
+GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
+
+/* Vector Floating-Point Sign-Injection Instructions */
+GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
+GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
+GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
+GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
+
+/* Vector Floating-Point Compare Instructions */
+static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ (s->sew != 0) &&
+ ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
+ vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
+ (s->lmul == 0)));
+}
+
+GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
+GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
+
+static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (s->sew != 0) &&
+ (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
+ (s->lmul == 0)));
+}
+
+GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
+GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
+
+/* Vector Floating-Point Classify Instruction */
+GEN_OPFV_TRANS(vfclass_v, opfv_check)
+
+/* Vector Floating-Point Merge Instruction */
+GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check)
+
+static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ (s->sew != 0)) {
+
+ if (s->vl_eq_vlmax) {
+ tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
+ } else {
+ TCGv_ptr dest;
+ TCGv_i32 desc;
+ uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
+ static gen_helper_vmv_vx * const fns[3] = {
+ gen_helper_vmv_v_x_h,
+ gen_helper_vmv_v_x_w,
+ gen_helper_vmv_v_x_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ dest = tcg_temp_new_ptr();
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+ tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
+ fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
+
+ tcg_temp_free_ptr(dest);
+ gen_set_label(over);
+ }
+ return true;
+ }
+ return false;
+}
+
+/* Single-Width Floating-Point/Integer Type-Convert Instructions */
+GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
+GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
+GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
+GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
+
+/* Widening Floating-Point/Integer Type-Convert Instructions */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, true) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
+ 1 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+#define GEN_OPFV_WIDEN_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (opfv_widen_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_3_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
+GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
+
+/* Narrowing Floating-Point/Integer Type-Convert Instructions */
+
+/*
+ * If the current SEW does not correspond to a supported IEEE floating-point
+ * type, an illegal instruction exception is raised
+ */
+static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, true) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
+ 2 << s->lmul) &&
+ (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
+}
+
+#define GEN_OPFV_NARROW_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (opfv_narrow_check(s, a)) { \
+ uint32_t data = 0; \
+ static gen_helper_gvec_3_ptr * const fns[2] = { \
+ gen_helper_##NAME##_h, \
+ gen_helper_##NAME##_w, \
+ }; \
+ TCGLabel *over = gen_new_label(); \
+ gen_set_rm(s, 7); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, \
+ fns[s->sew - 1]); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
+GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
+
+/*
+ *** Vector Reduction Operations
+ */
+/* Vector Single-Width Integer Reduction Instructions */
+static bool reduction_check(DisasContext *s, arg_rmrr *a)
+{
+ return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false);
+}
+
+GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
+GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
+GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
+GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
+GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
+GEN_OPIVV_TRANS(vredand_vs, reduction_check)
+GEN_OPIVV_TRANS(vredor_vs, reduction_check)
+GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
+
+/* Vector Widening Integer Reduction Instructions */
+GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check)
+GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check)
+
+/* Vector Single-Width Floating-Point Reduction Instructions */
+GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
+GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
+GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
+
+/* Vector Widening Floating-Point Reduction Instructions */
+GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
+
+/*
+ *** Vector Mask Operations
+ */
+
+/* Vector Mask-Register Logical Instructions */
+#define GEN_MM_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_r *a) \
+{ \
+ if (vext_check_isa_ill(s)) { \
+ uint32_t data = 0; \
+ gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
+ vreg_ofs(s, a->rs1), \
+ vreg_ofs(s, a->rs2), cpu_env, \
+ s->vlen / 8, s->vlen / 8, data, fn); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_MM_TRANS(vmand_mm)
+GEN_MM_TRANS(vmnand_mm)
+GEN_MM_TRANS(vmandnot_mm)
+GEN_MM_TRANS(vmxor_mm)
+GEN_MM_TRANS(vmor_mm)
+GEN_MM_TRANS(vmnor_mm)
+GEN_MM_TRANS(vmornot_mm)
+GEN_MM_TRANS(vmxnor_mm)
+
+/* Vector mask population count vmpopc */
+static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
+{
+ if (vext_check_isa_ill(s)) {
+ TCGv_ptr src2, mask;
+ TCGv dst;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ dst = dest_gpr(s, a->rd);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
+ gen_set_gpr(s, a->rd, dst);
+
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ return true;
+ }
+ return false;
+}
+
+/* vmfirst find-first-set mask bit */
+static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
+{
+ if (vext_check_isa_ill(s)) {
+ TCGv_ptr src2, mask;
+ TCGv dst;
+ TCGv_i32 desc;
+ uint32_t data = 0;
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+
+ mask = tcg_temp_new_ptr();
+ src2 = tcg_temp_new_ptr();
+ dst = dest_gpr(s, a->rd);
+ desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
+
+ tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
+ tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
+
+ gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
+ gen_set_gpr(s, a->rd, dst);
+
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ return true;
+ }
+ return false;
+}
+
+/* vmsbf.m set-before-first mask bit */
+/* vmsif.m set-includ-first mask bit */
+/* vmsof.m set-only-first mask bit */
+#define GEN_M_TRANS(NAME) \
+static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
+{ \
+ if (vext_check_isa_ill(s)) { \
+ uint32_t data = 0; \
+ gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \
+ TCGLabel *over = gen_new_label(); \
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
+ \
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
+ data = FIELD_DP32(data, VDATA, VM, a->vm); \
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \
+ vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \
+ cpu_env, s->vlen / 8, s->vlen / 8, \
+ data, fn); \
+ gen_set_label(over); \
+ return true; \
+ } \
+ return false; \
+}
+
+GEN_M_TRANS(vmsbf_m)
+GEN_M_TRANS(vmsif_m)
+GEN_M_TRANS(vmsof_m)
+
+/* Vector Iota Instruction */
+static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) &&
+ (a->vm != 0 || a->rd != 0)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ static gen_helper_gvec_3_ptr * const fns[4] = {
+ gen_helper_viota_m_b, gen_helper_viota_m_h,
+ gen_helper_viota_m_w, gen_helper_viota_m_d,
+ };
+ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs2), cpu_env,
+ s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/* Vector Element Index Instruction */
+static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
+{
+ if (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, false)) {
+ uint32_t data = 0;
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, VM, a->vm);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ static gen_helper_gvec_2_ptr * const fns[4] = {
+ gen_helper_vid_v_b, gen_helper_vid_v_h,
+ gen_helper_vid_v_w, gen_helper_vid_v_d,
+ };
+ tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ cpu_env, s->vlen / 8, s->vlen / 8,
+ data, fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/*
+ *** Vector Permutation Instructions
+ */
+
+/* Integer Extract Instruction */
+
+static void load_element(TCGv_i64 dest, TCGv_ptr base,
+ int ofs, int sew)
+{
+ switch (sew) {
+ case MO_8:
+ tcg_gen_ld8u_i64(dest, base, ofs);
+ break;
+ case MO_16:
+ tcg_gen_ld16u_i64(dest, base, ofs);
+ break;
+ case MO_32:
+ tcg_gen_ld32u_i64(dest, base, ofs);
+ break;
+ case MO_64:
+ tcg_gen_ld_i64(dest, base, ofs);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+/* offset of the idx element with base regsiter r */
+static uint32_t endian_ofs(DisasContext *s, int r, int idx)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
+#else
+ return vreg_ofs(s, r) + (idx << s->sew);
+#endif
+}
+
+/* adjust the index according to the endian */
+static void endian_adjust(TCGv_i32 ofs, int sew)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
+#endif
+}
+
+/* Load idx >= VLMAX ? 0 : vreg[idx] */
+static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
+ int vreg, TCGv idx, int vlmax)
+{
+ TCGv_i32 ofs = tcg_temp_new_i32();
+ TCGv_ptr base = tcg_temp_new_ptr();
+ TCGv_i64 t_idx = tcg_temp_new_i64();
+ TCGv_i64 t_vlmax, t_zero;
+
+ /*
+ * Mask the index to the length so that we do
+ * not produce an out-of-range load.
+ */
+ tcg_gen_trunc_tl_i32(ofs, idx);
+ tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
+
+ /* Convert the index to an offset. */
+ endian_adjust(ofs, s->sew);
+ tcg_gen_shli_i32(ofs, ofs, s->sew);
+
+ /* Convert the index to a pointer. */
+ tcg_gen_ext_i32_ptr(base, ofs);
+ tcg_gen_add_ptr(base, base, cpu_env);
+
+ /* Perform the load. */
+ load_element(dest, base,
+ vreg_ofs(s, vreg), s->sew);
+ tcg_temp_free_ptr(base);
+ tcg_temp_free_i32(ofs);
+
+ /* Flush out-of-range indexing to zero. */
+ t_vlmax = tcg_constant_i64(vlmax);
+ t_zero = tcg_constant_i64(0);
+ tcg_gen_extu_tl_i64(t_idx, idx);
+
+ tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
+ t_vlmax, dest, t_zero);
+
+ tcg_temp_free_i64(t_idx);
+}
+
+static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
+ int vreg, int idx)
+{
+ load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
+}
+
+static bool trans_vext_x_v(DisasContext *s, arg_r *a)
+{
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ TCGv dest = dest_gpr(s, a->rd);
+
+ if (a->rs1 == 0) {
+ /* Special case vmv.x.s rd, vs2. */
+ vec_element_loadi(s, tmp, a->rs2, 0);
+ } else {
+ /* This instruction ignores LMUL and vector register groups */
+ int vlmax = s->vlen >> (3 + s->sew);
+ vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
+ }
+
+ tcg_gen_trunc_i64_tl(dest, tmp);
+ gen_set_gpr(s, a->rd, dest);
+
+ tcg_temp_free_i64(tmp);
+ return true;
+}
+
+/* Integer Scalar Move Instruction */
+
+static void store_element(TCGv_i64 val, TCGv_ptr base,
+ int ofs, int sew)
+{
+ switch (sew) {
+ case MO_8:
+ tcg_gen_st8_i64(val, base, ofs);
+ break;
+ case MO_16:
+ tcg_gen_st16_i64(val, base, ofs);
+ break;
+ case MO_32:
+ tcg_gen_st32_i64(val, base, ofs);
+ break;
+ case MO_64:
+ tcg_gen_st_i64(val, base, ofs);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+/*
+ * Store vreg[idx] = val.
+ * The index must be in range of VLMAX.
+ */
+static void vec_element_storei(DisasContext *s, int vreg,
+ int idx, TCGv_i64 val)
+{
+ store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
+}
+
+/* vmv.s.x vd, rs1 # vd[0] = rs1 */
+static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
+{
+ if (vext_check_isa_ill(s)) {
+ /* This instruction ignores LMUL and vector register groups */
+ int maxsz = s->vlen >> 3;
+ TCGv_i64 t1;
+ TCGLabel *over = gen_new_label();
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+ tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
+ if (a->rs1 == 0) {
+ goto done;
+ }
+
+ t1 = tcg_temp_new_i64();
+ tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
+ vec_element_storei(s, a->rd, 0, t1);
+ tcg_temp_free_i64(t1);
+ done:
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/* Floating-Point Scalar Move Instructions */
+static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
+{
+ if (!s->vill && has_ext(s, RVF) &&
+ (s->mstatus_fs != 0) && (s->sew != 0)) {
+ unsigned int len = 8 << s->sew;
+
+ vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
+ if (len < 64) {
+ tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
+ MAKE_64BIT_MASK(len, 64 - len));
+ }
+
+ mark_fs_dirty(s);
+ return true;
+ }
+ return false;
+}
+
+/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
+static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
+{
+ if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
+ TCGv_i64 t1;
+ /* The instructions ignore LMUL and vector register group. */
+ uint32_t vlmax = s->vlen >> 3;
+
+ /* if vl == 0, skip vector register write back */
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ /* zeroed all elements */
+ tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
+
+ /* NaN-box f[rs1] as necessary for SEW */
+ t1 = tcg_temp_new_i64();
+ if (s->sew == MO_64 && !has_ext(s, RVD)) {
+ tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
+ } else {
+ tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
+ }
+ vec_element_storei(s, a->rd, 0, t1);
+ tcg_temp_free_i64(t1);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
+
+/* Vector Slide Instructions */
+static bool slideup_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (a->rd != a->rs2));
+}
+
+GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
+GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
+GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check)
+
+GEN_OPIVX_TRANS(vslidedown_vx, opivx_check)
+GEN_OPIVX_TRANS(vslide1down_vx, opivx_check)
+GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check)
+
+/* Vector Register Gather Instruction */
+static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs1, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (a->rd != a->rs2) && (a->rd != a->rs1));
+}
+
+GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
+
+static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_overlap_mask(s, a->rd, a->vm, true) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ (a->rd != a->rs2));
+}
+
+/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
+static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
+{
+ if (!vrgather_vx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ int vlmax = s->vlen / s->mlen;
+ TCGv_i64 dest = tcg_temp_new_i64();
+
+ if (a->rs1 == 0) {
+ vec_element_loadi(s, dest, a->rs2, 0);
+ } else {
+ vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
+ }
+
+ tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), dest);
+ tcg_temp_free_i64(dest);
+ } else {
+ static gen_helper_opivx * const fns[4] = {
+ gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
+ gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
+ };
+ return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
+ }
+ return true;
+}
+
+/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
+static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
+{
+ if (!vrgather_vx_check(s, a)) {
+ return false;
+ }
+
+ if (a->vm && s->vl_eq_vlmax) {
+ if (a->rs1 >= s->vlen / s->mlen) {
+ tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
+ MAXSZ(s), MAXSZ(s), 0);
+ } else {
+ tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
+ endian_ofs(s, a->rs2, a->rs1),
+ MAXSZ(s), MAXSZ(s));
+ }
+ } else {
+ static gen_helper_opivx * const fns[4] = {
+ gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
+ gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
+ };
+ return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1);
+ }
+ return true;
+}
+
+/* Vector Compress Instruction */
+static bool vcompress_vm_check(DisasContext *s, arg_r *a)
+{
+ return (vext_check_isa_ill(s) &&
+ vext_check_reg(s, a->rd, false) &&
+ vext_check_reg(s, a->rs2, false) &&
+ vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) &&
+ (a->rd != a->rs2));
+}
+
+static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
+{
+ if (vcompress_vm_check(s, a)) {
+ uint32_t data = 0;
+ static gen_helper_gvec_4_ptr * const fns[4] = {
+ gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
+ gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
+ };
+ TCGLabel *over = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
+
+ data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
+ data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
+ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
+ vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
+ cpu_env, s->vlen / 8, s->vlen / 8, data,
+ fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
diff --git a/target/riscv/instmap.h b/target/riscv/instmap.h
new file mode 100644
index 000000000..40b6d2b64
--- /dev/null
+++ b/target/riscv/instmap.h
@@ -0,0 +1,369 @@
+/*
+ * RISC-V emulation for qemu: Instruction decode helpers
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TARGET_RISCV_INSTMAP_H
+#define TARGET_RISCV_INSTMAP_H
+
+#define MASK_OP_MAJOR(op) (op & 0x7F)
+enum {
+ /* rv32i, rv64i, rv32m */
+ OPC_RISC_LUI = (0x37),
+ OPC_RISC_AUIPC = (0x17),
+ OPC_RISC_JAL = (0x6F),
+ OPC_RISC_JALR = (0x67),
+ OPC_RISC_BRANCH = (0x63),
+ OPC_RISC_LOAD = (0x03),
+ OPC_RISC_STORE = (0x23),
+ OPC_RISC_ARITH_IMM = (0x13),
+ OPC_RISC_ARITH = (0x33),
+ OPC_RISC_FENCE = (0x0F),
+ OPC_RISC_SYSTEM = (0x73),
+
+ /* rv64i, rv64m */
+ OPC_RISC_ARITH_IMM_W = (0x1B),
+ OPC_RISC_ARITH_W = (0x3B),
+
+ /* rv32a, rv64a */
+ OPC_RISC_ATOMIC = (0x2F),
+
+ /* floating point */
+ OPC_RISC_FP_LOAD = (0x7),
+ OPC_RISC_FP_STORE = (0x27),
+
+ OPC_RISC_FMADD = (0x43),
+ OPC_RISC_FMSUB = (0x47),
+ OPC_RISC_FNMSUB = (0x4B),
+ OPC_RISC_FNMADD = (0x4F),
+
+ OPC_RISC_FP_ARITH = (0x53),
+};
+
+#define MASK_OP_ARITH(op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | \
+ (0x7F << 25))))
+enum {
+ OPC_RISC_ADD = OPC_RISC_ARITH | (0x0 << 12) | (0x00 << 25),
+ OPC_RISC_SUB = OPC_RISC_ARITH | (0x0 << 12) | (0x20 << 25),
+ OPC_RISC_SLL = OPC_RISC_ARITH | (0x1 << 12) | (0x00 << 25),
+ OPC_RISC_SLT = OPC_RISC_ARITH | (0x2 << 12) | (0x00 << 25),
+ OPC_RISC_SLTU = OPC_RISC_ARITH | (0x3 << 12) | (0x00 << 25),
+ OPC_RISC_XOR = OPC_RISC_ARITH | (0x4 << 12) | (0x00 << 25),
+ OPC_RISC_SRL = OPC_RISC_ARITH | (0x5 << 12) | (0x00 << 25),
+ OPC_RISC_SRA = OPC_RISC_ARITH | (0x5 << 12) | (0x20 << 25),
+ OPC_RISC_OR = OPC_RISC_ARITH | (0x6 << 12) | (0x00 << 25),
+ OPC_RISC_AND = OPC_RISC_ARITH | (0x7 << 12) | (0x00 << 25),
+
+ /* RV64M */
+ OPC_RISC_MUL = OPC_RISC_ARITH | (0x0 << 12) | (0x01 << 25),
+ OPC_RISC_MULH = OPC_RISC_ARITH | (0x1 << 12) | (0x01 << 25),
+ OPC_RISC_MULHSU = OPC_RISC_ARITH | (0x2 << 12) | (0x01 << 25),
+ OPC_RISC_MULHU = OPC_RISC_ARITH | (0x3 << 12) | (0x01 << 25),
+
+ OPC_RISC_DIV = OPC_RISC_ARITH | (0x4 << 12) | (0x01 << 25),
+ OPC_RISC_DIVU = OPC_RISC_ARITH | (0x5 << 12) | (0x01 << 25),
+ OPC_RISC_REM = OPC_RISC_ARITH | (0x6 << 12) | (0x01 << 25),
+ OPC_RISC_REMU = OPC_RISC_ARITH | (0x7 << 12) | (0x01 << 25),
+};
+
+
+#define MASK_OP_ARITH_IMM(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_ADDI = OPC_RISC_ARITH_IMM | (0x0 << 12),
+ OPC_RISC_SLTI = OPC_RISC_ARITH_IMM | (0x2 << 12),
+ OPC_RISC_SLTIU = OPC_RISC_ARITH_IMM | (0x3 << 12),
+ OPC_RISC_XORI = OPC_RISC_ARITH_IMM | (0x4 << 12),
+ OPC_RISC_ORI = OPC_RISC_ARITH_IMM | (0x6 << 12),
+ OPC_RISC_ANDI = OPC_RISC_ARITH_IMM | (0x7 << 12),
+ OPC_RISC_SLLI = OPC_RISC_ARITH_IMM | (0x1 << 12), /* additional part of
+ IMM */
+ OPC_RISC_SHIFT_RIGHT_I = OPC_RISC_ARITH_IMM | (0x5 << 12) /* SRAI, SRLI */
+};
+
+#define MASK_OP_BRANCH(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_BEQ = OPC_RISC_BRANCH | (0x0 << 12),
+ OPC_RISC_BNE = OPC_RISC_BRANCH | (0x1 << 12),
+ OPC_RISC_BLT = OPC_RISC_BRANCH | (0x4 << 12),
+ OPC_RISC_BGE = OPC_RISC_BRANCH | (0x5 << 12),
+ OPC_RISC_BLTU = OPC_RISC_BRANCH | (0x6 << 12),
+ OPC_RISC_BGEU = OPC_RISC_BRANCH | (0x7 << 12)
+};
+
+enum {
+ OPC_RISC_ADDIW = OPC_RISC_ARITH_IMM_W | (0x0 << 12),
+ OPC_RISC_SLLIW = OPC_RISC_ARITH_IMM_W | (0x1 << 12), /* additional part of
+ IMM */
+ OPC_RISC_SHIFT_RIGHT_IW = OPC_RISC_ARITH_IMM_W | (0x5 << 12) /* SRAI, SRLI
+ */
+};
+
+enum {
+ OPC_RISC_ADDW = OPC_RISC_ARITH_W | (0x0 << 12) | (0x00 << 25),
+ OPC_RISC_SUBW = OPC_RISC_ARITH_W | (0x0 << 12) | (0x20 << 25),
+ OPC_RISC_SLLW = OPC_RISC_ARITH_W | (0x1 << 12) | (0x00 << 25),
+ OPC_RISC_SRLW = OPC_RISC_ARITH_W | (0x5 << 12) | (0x00 << 25),
+ OPC_RISC_SRAW = OPC_RISC_ARITH_W | (0x5 << 12) | (0x20 << 25),
+
+ /* RV64M */
+ OPC_RISC_MULW = OPC_RISC_ARITH_W | (0x0 << 12) | (0x01 << 25),
+ OPC_RISC_DIVW = OPC_RISC_ARITH_W | (0x4 << 12) | (0x01 << 25),
+ OPC_RISC_DIVUW = OPC_RISC_ARITH_W | (0x5 << 12) | (0x01 << 25),
+ OPC_RISC_REMW = OPC_RISC_ARITH_W | (0x6 << 12) | (0x01 << 25),
+ OPC_RISC_REMUW = OPC_RISC_ARITH_W | (0x7 << 12) | (0x01 << 25),
+};
+
+#define MASK_OP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_LB = OPC_RISC_LOAD | (0x0 << 12),
+ OPC_RISC_LH = OPC_RISC_LOAD | (0x1 << 12),
+ OPC_RISC_LW = OPC_RISC_LOAD | (0x2 << 12),
+ OPC_RISC_LD = OPC_RISC_LOAD | (0x3 << 12),
+ OPC_RISC_LBU = OPC_RISC_LOAD | (0x4 << 12),
+ OPC_RISC_LHU = OPC_RISC_LOAD | (0x5 << 12),
+ OPC_RISC_LWU = OPC_RISC_LOAD | (0x6 << 12),
+};
+
+#define MASK_OP_STORE(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_SB = OPC_RISC_STORE | (0x0 << 12),
+ OPC_RISC_SH = OPC_RISC_STORE | (0x1 << 12),
+ OPC_RISC_SW = OPC_RISC_STORE | (0x2 << 12),
+ OPC_RISC_SD = OPC_RISC_STORE | (0x3 << 12),
+};
+
+#define MASK_OP_JALR(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+/* no enum since OPC_RISC_JALR is the actual value */
+
+#define MASK_OP_ATOMIC(op) \
+ (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | (0x7F << 25))))
+#define MASK_OP_ATOMIC_NO_AQ_RL_SZ(op) \
+ (MASK_OP_MAJOR(op) | (op & (0x1F << 27)))
+
+enum {
+ OPC_RISC_LR = OPC_RISC_ATOMIC | (0x02 << 27),
+ OPC_RISC_SC = OPC_RISC_ATOMIC | (0x03 << 27),
+ OPC_RISC_AMOSWAP = OPC_RISC_ATOMIC | (0x01 << 27),
+ OPC_RISC_AMOADD = OPC_RISC_ATOMIC | (0x00 << 27),
+ OPC_RISC_AMOXOR = OPC_RISC_ATOMIC | (0x04 << 27),
+ OPC_RISC_AMOAND = OPC_RISC_ATOMIC | (0x0C << 27),
+ OPC_RISC_AMOOR = OPC_RISC_ATOMIC | (0x08 << 27),
+ OPC_RISC_AMOMIN = OPC_RISC_ATOMIC | (0x10 << 27),
+ OPC_RISC_AMOMAX = OPC_RISC_ATOMIC | (0x14 << 27),
+ OPC_RISC_AMOMINU = OPC_RISC_ATOMIC | (0x18 << 27),
+ OPC_RISC_AMOMAXU = OPC_RISC_ATOMIC | (0x1C << 27),
+};
+
+#define MASK_OP_SYSTEM(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_ECALL = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_EBREAK = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_ERET = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_MRTS = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_MRTH = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_HRTS = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_WFI = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_SFENCEVM = OPC_RISC_SYSTEM | (0x0 << 12),
+
+ OPC_RISC_CSRRW = OPC_RISC_SYSTEM | (0x1 << 12),
+ OPC_RISC_CSRRS = OPC_RISC_SYSTEM | (0x2 << 12),
+ OPC_RISC_CSRRC = OPC_RISC_SYSTEM | (0x3 << 12),
+ OPC_RISC_CSRRWI = OPC_RISC_SYSTEM | (0x5 << 12),
+ OPC_RISC_CSRRSI = OPC_RISC_SYSTEM | (0x6 << 12),
+ OPC_RISC_CSRRCI = OPC_RISC_SYSTEM | (0x7 << 12),
+};
+
+#define MASK_OP_FP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_FLW = OPC_RISC_FP_LOAD | (0x2 << 12),
+ OPC_RISC_FLD = OPC_RISC_FP_LOAD | (0x3 << 12),
+};
+
+#define MASK_OP_FP_STORE(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_FSW = OPC_RISC_FP_STORE | (0x2 << 12),
+ OPC_RISC_FSD = OPC_RISC_FP_STORE | (0x3 << 12),
+};
+
+#define MASK_OP_FP_FMADD(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FMADD_S = OPC_RISC_FMADD | (0x0 << 25),
+ OPC_RISC_FMADD_D = OPC_RISC_FMADD | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FMSUB(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FMSUB_S = OPC_RISC_FMSUB | (0x0 << 25),
+ OPC_RISC_FMSUB_D = OPC_RISC_FMSUB | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FNMADD(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FNMADD_S = OPC_RISC_FNMADD | (0x0 << 25),
+ OPC_RISC_FNMADD_D = OPC_RISC_FNMADD | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FNMSUB(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FNMSUB_S = OPC_RISC_FNMSUB | (0x0 << 25),
+ OPC_RISC_FNMSUB_D = OPC_RISC_FNMSUB | (0x1 << 25),
+};
+
+#define MASK_OP_FP_ARITH(op) (MASK_OP_MAJOR(op) | (op & (0x7F << 25)))
+enum {
+ /* float */
+ OPC_RISC_FADD_S = OPC_RISC_FP_ARITH | (0x0 << 25),
+ OPC_RISC_FSUB_S = OPC_RISC_FP_ARITH | (0x4 << 25),
+ OPC_RISC_FMUL_S = OPC_RISC_FP_ARITH | (0x8 << 25),
+ OPC_RISC_FDIV_S = OPC_RISC_FP_ARITH | (0xC << 25),
+
+ OPC_RISC_FSGNJ_S = OPC_RISC_FP_ARITH | (0x10 << 25),
+ OPC_RISC_FSGNJN_S = OPC_RISC_FP_ARITH | (0x10 << 25),
+ OPC_RISC_FSGNJX_S = OPC_RISC_FP_ARITH | (0x10 << 25),
+
+ OPC_RISC_FMIN_S = OPC_RISC_FP_ARITH | (0x14 << 25),
+ OPC_RISC_FMAX_S = OPC_RISC_FP_ARITH | (0x14 << 25),
+
+ OPC_RISC_FSQRT_S = OPC_RISC_FP_ARITH | (0x2C << 25),
+
+ OPC_RISC_FEQ_S = OPC_RISC_FP_ARITH | (0x50 << 25),
+ OPC_RISC_FLT_S = OPC_RISC_FP_ARITH | (0x50 << 25),
+ OPC_RISC_FLE_S = OPC_RISC_FP_ARITH | (0x50 << 25),
+
+ OPC_RISC_FCVT_W_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+ OPC_RISC_FCVT_WU_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+ OPC_RISC_FCVT_L_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+ OPC_RISC_FCVT_LU_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+
+ OPC_RISC_FCVT_S_W = OPC_RISC_FP_ARITH | (0x68 << 25),
+ OPC_RISC_FCVT_S_WU = OPC_RISC_FP_ARITH | (0x68 << 25),
+ OPC_RISC_FCVT_S_L = OPC_RISC_FP_ARITH | (0x68 << 25),
+ OPC_RISC_FCVT_S_LU = OPC_RISC_FP_ARITH | (0x68 << 25),
+
+ OPC_RISC_FMV_X_S = OPC_RISC_FP_ARITH | (0x70 << 25),
+ OPC_RISC_FCLASS_S = OPC_RISC_FP_ARITH | (0x70 << 25),
+
+ OPC_RISC_FMV_S_X = OPC_RISC_FP_ARITH | (0x78 << 25),
+
+ /* double */
+ OPC_RISC_FADD_D = OPC_RISC_FP_ARITH | (0x1 << 25),
+ OPC_RISC_FSUB_D = OPC_RISC_FP_ARITH | (0x5 << 25),
+ OPC_RISC_FMUL_D = OPC_RISC_FP_ARITH | (0x9 << 25),
+ OPC_RISC_FDIV_D = OPC_RISC_FP_ARITH | (0xD << 25),
+
+ OPC_RISC_FSGNJ_D = OPC_RISC_FP_ARITH | (0x11 << 25),
+ OPC_RISC_FSGNJN_D = OPC_RISC_FP_ARITH | (0x11 << 25),
+ OPC_RISC_FSGNJX_D = OPC_RISC_FP_ARITH | (0x11 << 25),
+
+ OPC_RISC_FMIN_D = OPC_RISC_FP_ARITH | (0x15 << 25),
+ OPC_RISC_FMAX_D = OPC_RISC_FP_ARITH | (0x15 << 25),
+
+ OPC_RISC_FCVT_S_D = OPC_RISC_FP_ARITH | (0x20 << 25),
+
+ OPC_RISC_FCVT_D_S = OPC_RISC_FP_ARITH | (0x21 << 25),
+
+ OPC_RISC_FSQRT_D = OPC_RISC_FP_ARITH | (0x2D << 25),
+
+ OPC_RISC_FEQ_D = OPC_RISC_FP_ARITH | (0x51 << 25),
+ OPC_RISC_FLT_D = OPC_RISC_FP_ARITH | (0x51 << 25),
+ OPC_RISC_FLE_D = OPC_RISC_FP_ARITH | (0x51 << 25),
+
+ OPC_RISC_FCVT_W_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+ OPC_RISC_FCVT_WU_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+ OPC_RISC_FCVT_L_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+ OPC_RISC_FCVT_LU_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+
+ OPC_RISC_FCVT_D_W = OPC_RISC_FP_ARITH | (0x69 << 25),
+ OPC_RISC_FCVT_D_WU = OPC_RISC_FP_ARITH | (0x69 << 25),
+ OPC_RISC_FCVT_D_L = OPC_RISC_FP_ARITH | (0x69 << 25),
+ OPC_RISC_FCVT_D_LU = OPC_RISC_FP_ARITH | (0x69 << 25),
+
+ OPC_RISC_FMV_X_D = OPC_RISC_FP_ARITH | (0x71 << 25),
+ OPC_RISC_FCLASS_D = OPC_RISC_FP_ARITH | (0x71 << 25),
+
+ OPC_RISC_FMV_D_X = OPC_RISC_FP_ARITH | (0x79 << 25),
+};
+
+#define GET_B_IMM(inst) ((extract32(inst, 8, 4) << 1) \
+ | (extract32(inst, 25, 6) << 5) \
+ | (extract32(inst, 7, 1) << 11) \
+ | (sextract64(inst, 31, 1) << 12))
+
+#define GET_STORE_IMM(inst) ((extract32(inst, 7, 5)) \
+ | (sextract64(inst, 25, 7) << 5))
+
+#define GET_JAL_IMM(inst) ((extract32(inst, 21, 10) << 1) \
+ | (extract32(inst, 20, 1) << 11) \
+ | (extract32(inst, 12, 8) << 12) \
+ | (sextract64(inst, 31, 1) << 20))
+
+#define GET_RM(inst) extract32(inst, 12, 3)
+#define GET_RS3(inst) extract32(inst, 27, 5)
+#define GET_RS1(inst) extract32(inst, 15, 5)
+#define GET_RS2(inst) extract32(inst, 20, 5)
+#define GET_RD(inst) extract32(inst, 7, 5)
+#define GET_IMM(inst) sextract64(inst, 20, 12)
+
+/* RVC decoding macros */
+#define GET_C_IMM(inst) (extract32(inst, 2, 5) \
+ | (sextract64(inst, 12, 1) << 5))
+#define GET_C_ZIMM(inst) (extract32(inst, 2, 5) \
+ | (extract32(inst, 12, 1) << 5))
+#define GET_C_ADDI4SPN_IMM(inst) ((extract32(inst, 6, 1) << 2) \
+ | (extract32(inst, 5, 1) << 3) \
+ | (extract32(inst, 11, 2) << 4) \
+ | (extract32(inst, 7, 4) << 6))
+#define GET_C_ADDI16SP_IMM(inst) ((extract32(inst, 6, 1) << 4) \
+ | (extract32(inst, 2, 1) << 5) \
+ | (extract32(inst, 5, 1) << 6) \
+ | (extract32(inst, 3, 2) << 7) \
+ | (sextract64(inst, 12, 1) << 9))
+#define GET_C_LWSP_IMM(inst) ((extract32(inst, 4, 3) << 2) \
+ | (extract32(inst, 12, 1) << 5) \
+ | (extract32(inst, 2, 2) << 6))
+#define GET_C_LDSP_IMM(inst) ((extract32(inst, 5, 2) << 3) \
+ | (extract32(inst, 12, 1) << 5) \
+ | (extract32(inst, 2, 3) << 6))
+#define GET_C_SWSP_IMM(inst) ((extract32(inst, 9, 4) << 2) \
+ | (extract32(inst, 7, 2) << 6))
+#define GET_C_SDSP_IMM(inst) ((extract32(inst, 10, 3) << 3) \
+ | (extract32(inst, 7, 3) << 6))
+#define GET_C_LW_IMM(inst) ((extract32(inst, 6, 1) << 2) \
+ | (extract32(inst, 10, 3) << 3) \
+ | (extract32(inst, 5, 1) << 6))
+#define GET_C_LD_IMM(inst) ((extract16(inst, 10, 3) << 3) \
+ | (extract16(inst, 5, 2) << 6))
+#define GET_C_J_IMM(inst) ((extract32(inst, 3, 3) << 1) \
+ | (extract32(inst, 11, 1) << 4) \
+ | (extract32(inst, 2, 1) << 5) \
+ | (extract32(inst, 7, 1) << 6) \
+ | (extract32(inst, 6, 1) << 7) \
+ | (extract32(inst, 9, 2) << 8) \
+ | (extract32(inst, 8, 1) << 10) \
+ | (sextract64(inst, 12, 1) << 11))
+#define GET_C_B_IMM(inst) ((extract32(inst, 3, 2) << 1) \
+ | (extract32(inst, 10, 2) << 3) \
+ | (extract32(inst, 2, 1) << 5) \
+ | (extract32(inst, 5, 2) << 6) \
+ | (sextract64(inst, 12, 1) << 8))
+#define GET_C_SIMM3(inst) extract32(inst, 10, 3)
+#define GET_C_RD(inst) GET_RD(inst)
+#define GET_C_RS1(inst) GET_RD(inst)
+#define GET_C_RS2(inst) extract32(inst, 2, 5)
+#define GET_C_RS1S(inst) (8 + extract16(inst, 7, 3))
+#define GET_C_RS2S(inst) (8 + extract16(inst, 2, 3))
+
+#endif
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
new file mode 100644
index 000000000..b15ad394b
--- /dev/null
+++ b/target/riscv/internals.h
@@ -0,0 +1,61 @@
+/*
+ * QEMU RISC-V CPU -- internal functions and types
+ *
+ * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RISCV_CPU_INTERNALS_H
+#define RISCV_CPU_INTERNALS_H
+
+#include "hw/registerfields.h"
+
+/* share data between vector helpers and decode code */
+FIELD(VDATA, MLEN, 0, 8)
+FIELD(VDATA, VM, 8, 1)
+FIELD(VDATA, LMUL, 9, 2)
+FIELD(VDATA, NF, 11, 4)
+FIELD(VDATA, WD, 11, 1)
+
+/* float point classify helpers */
+target_ulong fclass_h(uint64_t frs1);
+target_ulong fclass_s(uint64_t frs1);
+target_ulong fclass_d(uint64_t frs1);
+
+#define SEW8 0
+#define SEW16 1
+#define SEW32 2
+#define SEW64 3
+
+#ifndef CONFIG_USER_ONLY
+extern const VMStateDescription vmstate_riscv_cpu;
+#endif
+
+static inline uint64_t nanbox_s(float32 f)
+{
+ return f | MAKE_64BIT_MASK(32, 32);
+}
+
+static inline float32 check_nanbox_s(uint64_t f)
+{
+ uint64_t mask = MAKE_64BIT_MASK(32, 32);
+
+ if (likely((f & mask) == mask)) {
+ return (uint32_t)f;
+ } else {
+ return 0x7fc00000u; /* default qnan */
+ }
+}
+
+#endif
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
new file mode 100644
index 000000000..ad8248ebf
--- /dev/null
+++ b/target/riscv/machine.c
@@ -0,0 +1,223 @@
+/*
+ * RISC-V VMState Description
+ *
+ * Copyright (c) 2020 Huawei Technologies Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "qemu/error-report.h"
+#include "sysemu/kvm.h"
+#include "migration/cpu.h"
+
+static bool pmp_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ return riscv_feature(env, RISCV_FEATURE_PMP);
+}
+
+static int pmp_post_load(void *opaque, int version_id)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+ int i;
+
+ for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ pmp_update_rule_addr(env, i);
+ }
+ pmp_update_rule_nums(env);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_pmp_entry = {
+ .name = "cpu/pmp/entry",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL(addr_reg, pmp_entry_t),
+ VMSTATE_UINT8(cfg_reg, pmp_entry_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_pmp = {
+ .name = "cpu/pmp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pmp_needed,
+ .post_load = pmp_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(env.pmp_state.pmp, RISCVCPU, MAX_RISCV_PMPS,
+ 0, vmstate_pmp_entry, pmp_entry_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool hyper_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ return riscv_has_ext(env, RVH);
+}
+
+static const VMStateDescription vmstate_hyper = {
+ .name = "cpu/hyper",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = hyper_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL(env.hstatus, RISCVCPU),
+ VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
+ VMSTATE_UINTTL(env.hideleg, RISCVCPU),
+ VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
+ VMSTATE_UINTTL(env.htval, RISCVCPU),
+ VMSTATE_UINTTL(env.htinst, RISCVCPU),
+ VMSTATE_UINTTL(env.hgatp, RISCVCPU),
+ VMSTATE_UINT64(env.htimedelta, RISCVCPU),
+
+ VMSTATE_UINT64(env.vsstatus, RISCVCPU),
+ VMSTATE_UINTTL(env.vstvec, RISCVCPU),
+ VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
+ VMSTATE_UINTTL(env.vsepc, RISCVCPU),
+ VMSTATE_UINTTL(env.vscause, RISCVCPU),
+ VMSTATE_UINTTL(env.vstval, RISCVCPU),
+ VMSTATE_UINTTL(env.vsatp, RISCVCPU),
+
+ VMSTATE_UINTTL(env.mtval2, RISCVCPU),
+ VMSTATE_UINTTL(env.mtinst, RISCVCPU),
+
+ VMSTATE_UINTTL(env.stvec_hs, RISCVCPU),
+ VMSTATE_UINTTL(env.sscratch_hs, RISCVCPU),
+ VMSTATE_UINTTL(env.sepc_hs, RISCVCPU),
+ VMSTATE_UINTTL(env.scause_hs, RISCVCPU),
+ VMSTATE_UINTTL(env.stval_hs, RISCVCPU),
+ VMSTATE_UINTTL(env.satp_hs, RISCVCPU),
+ VMSTATE_UINT64(env.mstatus_hs, RISCVCPU),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool vector_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ return riscv_has_ext(env, RVV);
+}
+
+static const VMStateDescription vmstate_vector = {
+ .name = "cpu/vector",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = vector_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64),
+ VMSTATE_UINTTL(env.vxrm, RISCVCPU),
+ VMSTATE_UINTTL(env.vxsat, RISCVCPU),
+ VMSTATE_UINTTL(env.vl, RISCVCPU),
+ VMSTATE_UINTTL(env.vstart, RISCVCPU),
+ VMSTATE_UINTTL(env.vtype, RISCVCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool pointermasking_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ return riscv_has_ext(env, RVJ);
+}
+
+static const VMStateDescription vmstate_pointermasking = {
+ .name = "cpu/pointer_masking",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pointermasking_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL(env.mmte, RISCVCPU),
+ VMSTATE_UINTTL(env.mpmmask, RISCVCPU),
+ VMSTATE_UINTTL(env.mpmbase, RISCVCPU),
+ VMSTATE_UINTTL(env.spmmask, RISCVCPU),
+ VMSTATE_UINTTL(env.spmbase, RISCVCPU),
+ VMSTATE_UINTTL(env.upmmask, RISCVCPU),
+ VMSTATE_UINTTL(env.upmbase, RISCVCPU),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+const VMStateDescription vmstate_riscv_cpu = {
+ .name = "cpu",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
+ VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
+ VMSTATE_UINTTL(env.pc, RISCVCPU),
+ VMSTATE_UINTTL(env.load_res, RISCVCPU),
+ VMSTATE_UINTTL(env.load_val, RISCVCPU),
+ VMSTATE_UINTTL(env.frm, RISCVCPU),
+ VMSTATE_UINTTL(env.badaddr, RISCVCPU),
+ VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU),
+ VMSTATE_UINTTL(env.priv_ver, RISCVCPU),
+ VMSTATE_UINTTL(env.vext_ver, RISCVCPU),
+ VMSTATE_UINT32(env.misa_mxl, RISCVCPU),
+ VMSTATE_UINT32(env.misa_ext, RISCVCPU),
+ VMSTATE_UINT32(env.misa_mxl_max, RISCVCPU),
+ VMSTATE_UINT32(env.misa_ext_mask, RISCVCPU),
+ VMSTATE_UINT32(env.features, RISCVCPU),
+ VMSTATE_UINTTL(env.priv, RISCVCPU),
+ VMSTATE_UINTTL(env.virt, RISCVCPU),
+ VMSTATE_UINTTL(env.resetvec, RISCVCPU),
+ VMSTATE_UINTTL(env.mhartid, RISCVCPU),
+ VMSTATE_UINT64(env.mstatus, RISCVCPU),
+ VMSTATE_UINTTL(env.mip, RISCVCPU),
+ VMSTATE_UINT32(env.miclaim, RISCVCPU),
+ VMSTATE_UINTTL(env.mie, RISCVCPU),
+ VMSTATE_UINTTL(env.mideleg, RISCVCPU),
+ VMSTATE_UINTTL(env.satp, RISCVCPU),
+ VMSTATE_UINTTL(env.stval, RISCVCPU),
+ VMSTATE_UINTTL(env.medeleg, RISCVCPU),
+ VMSTATE_UINTTL(env.stvec, RISCVCPU),
+ VMSTATE_UINTTL(env.sepc, RISCVCPU),
+ VMSTATE_UINTTL(env.scause, RISCVCPU),
+ VMSTATE_UINTTL(env.mtvec, RISCVCPU),
+ VMSTATE_UINTTL(env.mepc, RISCVCPU),
+ VMSTATE_UINTTL(env.mcause, RISCVCPU),
+ VMSTATE_UINTTL(env.mtval, RISCVCPU),
+ VMSTATE_UINTTL(env.scounteren, RISCVCPU),
+ VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
+ VMSTATE_UINTTL(env.sscratch, RISCVCPU),
+ VMSTATE_UINTTL(env.mscratch, RISCVCPU),
+ VMSTATE_UINT64(env.mfromhost, RISCVCPU),
+ VMSTATE_UINT64(env.mtohost, RISCVCPU),
+ VMSTATE_UINT64(env.timecmp, RISCVCPU),
+
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_pmp,
+ &vmstate_hyper,
+ &vmstate_vector,
+ &vmstate_pointermasking,
+ NULL
+ }
+};
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
new file mode 100644
index 000000000..d5e0bc93e
--- /dev/null
+++ b/target/riscv/meson.build
@@ -0,0 +1,32 @@
+# FIXME extra_args should accept files()
+dir = meson.current_source_dir()
+
+gen = [
+ decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']),
+ decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'),
+]
+
+riscv_ss = ss.source_set()
+riscv_ss.add(gen)
+riscv_ss.add(files(
+ 'cpu.c',
+ 'cpu_helper.c',
+ 'csr.c',
+ 'fpu_helper.c',
+ 'gdbstub.c',
+ 'op_helper.c',
+ 'vector_helper.c',
+ 'bitmanip_helper.c',
+ 'translate.c',
+))
+
+riscv_softmmu_ss = ss.source_set()
+riscv_softmmu_ss.add(files(
+ 'arch_dump.c',
+ 'pmp.c',
+ 'monitor.c',
+ 'machine.c'
+))
+
+target_arch += {'riscv': riscv_ss}
+target_softmmu_arch += {'riscv': riscv_softmmu_ss}
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
new file mode 100644
index 000000000..7efb4b62c
--- /dev/null
+++ b/target/riscv/monitor.c
@@ -0,0 +1,236 @@
+/*
+ * QEMU monitor for RISC-V
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * RISC-V specific monitor commands implementation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "cpu_bits.h"
+#include "monitor/monitor.h"
+#include "monitor/hmp-target.h"
+
+#ifdef TARGET_RISCV64
+#define PTE_HEADER_FIELDS "vaddr paddr "\
+ "size attr\n"
+#define PTE_HEADER_DELIMITER "---------------- ---------------- "\
+ "---------------- -------\n"
+#else
+#define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
+#define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
+#endif
+
+/* Perform linear address sign extension */
+static target_ulong addr_canonical(int va_bits, target_ulong addr)
+{
+#ifdef TARGET_RISCV64
+ if (addr & (1UL << (va_bits - 1))) {
+ addr |= (hwaddr)-(1L << va_bits);
+ }
+#endif
+
+ return addr;
+}
+
+static void print_pte_header(Monitor *mon)
+{
+ monitor_printf(mon, PTE_HEADER_FIELDS);
+ monitor_printf(mon, PTE_HEADER_DELIMITER);
+}
+
+static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr,
+ hwaddr paddr, target_ulong size, int attr)
+{
+ /* santity check on vaddr */
+ if (vaddr >= (1UL << va_bits)) {
+ return;
+ }
+
+ if (!size) {
+ return;
+ }
+
+ monitor_printf(mon, TARGET_FMT_lx " " TARGET_FMT_plx " " TARGET_FMT_lx
+ " %c%c%c%c%c%c%c\n",
+ addr_canonical(va_bits, vaddr),
+ paddr, size,
+ attr & PTE_R ? 'r' : '-',
+ attr & PTE_W ? 'w' : '-',
+ attr & PTE_X ? 'x' : '-',
+ attr & PTE_U ? 'u' : '-',
+ attr & PTE_G ? 'g' : '-',
+ attr & PTE_A ? 'a' : '-',
+ attr & PTE_D ? 'd' : '-');
+}
+
+static void walk_pte(Monitor *mon, hwaddr base, target_ulong start,
+ int level, int ptidxbits, int ptesize, int va_bits,
+ target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr,
+ target_ulong *last_size, int *last_attr)
+{
+ hwaddr pte_addr;
+ hwaddr paddr;
+ target_ulong pgsize;
+ target_ulong pte;
+ int ptshift;
+ int attr;
+ int idx;
+
+ if (level < 0) {
+ return;
+ }
+
+ ptshift = level * ptidxbits;
+ pgsize = 1UL << (PGSHIFT + ptshift);
+
+ for (idx = 0; idx < (1UL << ptidxbits); idx++) {
+ pte_addr = base + idx * ptesize;
+ cpu_physical_memory_read(pte_addr, &pte, ptesize);
+
+ paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT;
+ attr = pte & 0xff;
+
+ /* PTE has to be valid */
+ if (attr & PTE_V) {
+ if (attr & (PTE_R | PTE_W | PTE_X)) {
+ /*
+ * A leaf PTE has been found
+ *
+ * If current PTE's permission bits differ from the last one,
+ * or current PTE's ppn does not make a contiguous physical
+ * address block together with the last one, print out the last
+ * contiguous mapped block details.
+ */
+ if ((*last_attr != attr) ||
+ (*last_paddr + *last_size != paddr)) {
+ print_pte(mon, va_bits, *vbase, *pbase,
+ *last_paddr + *last_size - *pbase, *last_attr);
+
+ *vbase = start;
+ *pbase = paddr;
+ *last_attr = attr;
+ }
+
+ *last_paddr = paddr;
+ *last_size = pgsize;
+ } else {
+ /* pointer to the next level of the page table */
+ walk_pte(mon, paddr, start, level - 1, ptidxbits, ptesize,
+ va_bits, vbase, pbase, last_paddr,
+ last_size, last_attr);
+ }
+ }
+
+ start += pgsize;
+ }
+
+}
+
+static void mem_info_svxx(Monitor *mon, CPUArchState *env)
+{
+ int levels, ptidxbits, ptesize, vm, va_bits;
+ hwaddr base;
+ target_ulong vbase;
+ hwaddr pbase;
+ hwaddr last_paddr;
+ target_ulong last_size;
+ int last_attr;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP64_MODE);
+ }
+
+ switch (vm) {
+ case VM_1_10_SV32:
+ levels = 2;
+ ptidxbits = 10;
+ ptesize = 4;
+ break;
+ case VM_1_10_SV39:
+ levels = 3;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_1_10_SV48:
+ levels = 4;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_1_10_SV57:
+ levels = 5;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ /* calculate virtual address bits */
+ va_bits = PGSHIFT + levels * ptidxbits;
+
+ /* print header */
+ print_pte_header(mon);
+
+ vbase = -1;
+ pbase = -1;
+ last_paddr = -1;
+ last_size = 0;
+ last_attr = 0;
+
+ /* walk page tables, starting from address 0 */
+ walk_pte(mon, base, 0, levels - 1, ptidxbits, ptesize, va_bits,
+ &vbase, &pbase, &last_paddr, &last_size, &last_attr);
+
+ /* don't forget the last one */
+ print_pte(mon, va_bits, vbase, pbase,
+ last_paddr + last_size - pbase, last_attr);
+}
+
+void hmp_info_mem(Monitor *mon, const QDict *qdict)
+{
+ CPUArchState *env;
+
+ env = mon_get_cpu_env(mon);
+ if (!env) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ monitor_printf(mon, "S-mode MMU unavailable\n");
+ return;
+ }
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ if (!(env->satp & SATP32_MODE)) {
+ monitor_printf(mon, "No translation or protection\n");
+ return;
+ }
+ } else {
+ if (!(env->satp & SATP64_MODE)) {
+ monitor_printf(mon, "No translation or protection\n");
+ return;
+ }
+ }
+
+ mem_info_svxx(mon, env);
+}
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
new file mode 100644
index 000000000..ee7c24efe
--- /dev/null
+++ b/target/riscv/op_helper.c
@@ -0,0 +1,249 @@
+/*
+ * RISC-V Emulation Helpers for QEMU.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+
+/* Exceptions processing helpers */
+void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
+ uint32_t exception, uintptr_t pc)
+{
+ CPUState *cs = env_cpu(env);
+ cs->exception_index = exception;
+ cpu_loop_exit_restore(cs, pc);
+}
+
+void helper_raise_exception(CPURISCVState *env, uint32_t exception)
+{
+ riscv_raise_exception(env, exception, 0);
+}
+
+target_ulong helper_csrr(CPURISCVState *env, int csr)
+{
+ target_ulong val = 0;
+ RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0);
+
+ if (ret != RISCV_EXCP_NONE) {
+ riscv_raise_exception(env, ret, GETPC());
+ }
+ return val;
+}
+
+void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
+{
+ RISCVException ret = riscv_csrrw(env, csr, NULL, src, -1);
+
+ if (ret != RISCV_EXCP_NONE) {
+ riscv_raise_exception(env, ret, GETPC());
+ }
+}
+
+target_ulong helper_csrrw(CPURISCVState *env, int csr,
+ target_ulong src, target_ulong write_mask)
+{
+ target_ulong val = 0;
+ RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask);
+
+ if (ret != RISCV_EXCP_NONE) {
+ riscv_raise_exception(env, ret, GETPC());
+ }
+ return val;
+}
+
+#ifndef CONFIG_USER_ONLY
+
+target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
+{
+ uint64_t mstatus;
+ target_ulong prev_priv, prev_virt;
+
+ if (!(env->priv >= PRV_S)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+
+ target_ulong retpc = env->sepc;
+ if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
+ riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
+ }
+
+ if (get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+
+ if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
+ get_field(env->hstatus, HSTATUS_VTSR)) {
+ riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
+ }
+
+ mstatus = env->mstatus;
+
+ if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
+ /* We support Hypervisor extensions and virtulisation is disabled */
+ target_ulong hstatus = env->hstatus;
+
+ prev_priv = get_field(mstatus, MSTATUS_SPP);
+ prev_virt = get_field(hstatus, HSTATUS_SPV);
+
+ hstatus = set_field(hstatus, HSTATUS_SPV, 0);
+ mstatus = set_field(mstatus, MSTATUS_SPP, 0);
+ mstatus = set_field(mstatus, SSTATUS_SIE,
+ get_field(mstatus, SSTATUS_SPIE));
+ mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
+
+ env->mstatus = mstatus;
+ env->hstatus = hstatus;
+
+ if (prev_virt) {
+ riscv_cpu_swap_hypervisor_regs(env);
+ }
+
+ riscv_cpu_set_virt_enabled(env, prev_virt);
+ } else {
+ prev_priv = get_field(mstatus, MSTATUS_SPP);
+
+ mstatus = set_field(mstatus, MSTATUS_SIE,
+ get_field(mstatus, MSTATUS_SPIE));
+ mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
+ mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+ env->mstatus = mstatus;
+ }
+
+ riscv_cpu_set_mode(env, prev_priv);
+
+ return retpc;
+}
+
+target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
+{
+ if (!(env->priv >= PRV_M)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+
+ target_ulong retpc = env->mepc;
+ if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
+ riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
+ }
+
+ uint64_t mstatus = env->mstatus;
+ target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
+
+ if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+
+ target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV);
+ mstatus = set_field(mstatus, MSTATUS_MIE,
+ get_field(mstatus, MSTATUS_MPIE));
+ mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
+ mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
+ mstatus = set_field(mstatus, MSTATUS_MPV, 0);
+ env->mstatus = mstatus;
+ riscv_cpu_set_mode(env, prev_priv);
+
+ if (riscv_has_ext(env, RVH)) {
+ if (prev_virt) {
+ riscv_cpu_swap_hypervisor_regs(env);
+ }
+
+ riscv_cpu_set_virt_enabled(env, prev_virt);
+ }
+
+ return retpc;
+}
+
+void helper_wfi(CPURISCVState *env)
+{
+ CPUState *cs = env_cpu(env);
+ bool rvs = riscv_has_ext(env, RVS);
+ bool prv_u = env->priv == PRV_U;
+ bool prv_s = env->priv == PRV_S;
+
+ if (((prv_s || (!rvs && prv_u)) && get_field(env->mstatus, MSTATUS_TW)) ||
+ (rvs && prv_u && !riscv_cpu_virt_enabled(env))) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ } else if (riscv_cpu_virt_enabled(env) && (prv_u ||
+ (prv_s && get_field(env->hstatus, HSTATUS_VTW)))) {
+ riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
+ } else {
+ cs->halted = 1;
+ cs->exception_index = EXCP_HLT;
+ cpu_loop_exit(cs);
+ }
+}
+
+void helper_tlb_flush(CPURISCVState *env)
+{
+ CPUState *cs = env_cpu(env);
+ if (!(env->priv >= PRV_S) ||
+ (env->priv == PRV_S &&
+ get_field(env->mstatus, MSTATUS_TVM))) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ } else if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
+ get_field(env->hstatus, HSTATUS_VTVM)) {
+ riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
+ } else {
+ tlb_flush(cs);
+ }
+}
+
+void helper_hyp_tlb_flush(CPURISCVState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
+ riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
+ }
+
+ if (env->priv == PRV_M ||
+ (env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
+ tlb_flush(cs);
+ return;
+ }
+
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+}
+
+void helper_hyp_gvma_tlb_flush(CPURISCVState *env)
+{
+ if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env) &&
+ get_field(env->mstatus, MSTATUS_TVM)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+
+ helper_hyp_tlb_flush(env);
+}
+
+target_ulong helper_hyp_hlvx_hu(CPURISCVState *env, target_ulong address)
+{
+ int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+
+ return cpu_lduw_mmuidx_ra(env, address, mmu_idx, GETPC());
+}
+
+target_ulong helper_hyp_hlvx_wu(CPURISCVState *env, target_ulong address)
+{
+ int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
+
+ return cpu_ldl_mmuidx_ra(env, address, mmu_idx, GETPC());
+}
+
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
new file mode 100644
index 000000000..54abf4258
--- /dev/null
+++ b/target/riscv/pmp.c
@@ -0,0 +1,664 @@
+/*
+ * QEMU RISC-V PMP (Physical Memory Protection)
+ *
+ * Author: Daire McNamara, daire.mcnamara@emdalo.com
+ * Ivan Griffin, ivan.griffin@emdalo.com
+ *
+ * This provides a RISC-V Physical Memory Protection implementation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "trace.h"
+#include "exec/exec-all.h"
+
+static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
+ uint8_t val);
+static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index);
+static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index);
+
+/*
+ * Accessor method to extract address matching type 'a field' from cfg reg
+ */
+static inline uint8_t pmp_get_a_field(uint8_t cfg)
+{
+ uint8_t a = cfg >> 3;
+ return a & 0x3;
+}
+
+/*
+ * Check whether a PMP is locked or not.
+ */
+static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
+{
+
+ if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
+ return 1;
+ }
+
+ /* Top PMP has no 'next' to check */
+ if ((pmp_index + 1u) >= MAX_RISCV_PMPS) {
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Count the number of active rules.
+ */
+uint32_t pmp_get_num_rules(CPURISCVState *env)
+{
+ return env->pmp_state.num_rules;
+}
+
+/*
+ * Accessor to get the cfg reg for a specific PMP/HART
+ */
+static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
+{
+ if (pmp_index < MAX_RISCV_PMPS) {
+ return env->pmp_state.pmp[pmp_index].cfg_reg;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Accessor to set the cfg reg for a specific PMP/HART
+ * Bounds checks and relevant lock bit.
+ */
+static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
+{
+ if (pmp_index < MAX_RISCV_PMPS) {
+ bool locked = true;
+
+ if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ /* mseccfg.RLB is set */
+ if (MSECCFG_RLB_ISSET(env)) {
+ locked = false;
+ }
+
+ /* mseccfg.MML is not set */
+ if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
+ locked = false;
+ }
+
+ /* mseccfg.MML is set */
+ if (MSECCFG_MML_ISSET(env)) {
+ /* not adding execute bit */
+ if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
+ locked = false;
+ }
+ /* shared region and not adding X bit */
+ if ((val & PMP_LOCK) != PMP_LOCK &&
+ (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
+ locked = false;
+ }
+ }
+ } else {
+ if (!pmp_is_locked(env, pmp_index)) {
+ locked = false;
+ }
+ }
+
+ if (locked) {
+ qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
+ } else {
+ env->pmp_state.pmp[pmp_index].cfg_reg = val;
+ pmp_update_rule(env, pmp_index);
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpcfg write - out of bounds\n");
+ }
+}
+
+static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea)
+{
+ /*
+ aaaa...aaa0 8-byte NAPOT range
+ aaaa...aa01 16-byte NAPOT range
+ aaaa...a011 32-byte NAPOT range
+ ...
+ aa01...1111 2^XLEN-byte NAPOT range
+ a011...1111 2^(XLEN+1)-byte NAPOT range
+ 0111...1111 2^(XLEN+2)-byte NAPOT range
+ 1111...1111 Reserved
+ */
+ if (a == -1) {
+ *sa = 0u;
+ *ea = -1;
+ return;
+ } else {
+ target_ulong t1 = ctz64(~a);
+ target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 2;
+ target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1;
+ *sa = base;
+ *ea = base + range;
+ }
+}
+
+void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
+{
+ uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg;
+ target_ulong this_addr = env->pmp_state.pmp[pmp_index].addr_reg;
+ target_ulong prev_addr = 0u;
+ target_ulong sa = 0u;
+ target_ulong ea = 0u;
+
+ if (pmp_index >= 1u) {
+ prev_addr = env->pmp_state.pmp[pmp_index - 1].addr_reg;
+ }
+
+ switch (pmp_get_a_field(this_cfg)) {
+ case PMP_AMATCH_OFF:
+ sa = 0u;
+ ea = -1;
+ break;
+
+ case PMP_AMATCH_TOR:
+ sa = prev_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
+ ea = (this_addr << 2) - 1u;
+ break;
+
+ case PMP_AMATCH_NA4:
+ sa = this_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
+ ea = (sa + 4u) - 1u;
+ break;
+
+ case PMP_AMATCH_NAPOT:
+ pmp_decode_napot(this_addr, &sa, &ea);
+ break;
+
+ default:
+ sa = 0u;
+ ea = 0u;
+ break;
+ }
+
+ env->pmp_state.addr[pmp_index].sa = sa;
+ env->pmp_state.addr[pmp_index].ea = ea;
+}
+
+void pmp_update_rule_nums(CPURISCVState *env)
+{
+ int i;
+
+ env->pmp_state.num_rules = 0;
+ for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ const uint8_t a_field =
+ pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
+ if (PMP_AMATCH_OFF != a_field) {
+ env->pmp_state.num_rules++;
+ }
+ }
+}
+
+/* Convert cfg/addr reg values here into simple 'sa' --> start address and 'ea'
+ * end address values.
+ * This function is called relatively infrequently whereas the check that
+ * an address is within a pmp rule is called often, so optimise that one
+ */
+static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
+{
+ pmp_update_rule_addr(env, pmp_index);
+ pmp_update_rule_nums(env);
+}
+
+static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr)
+{
+ int result = 0;
+
+ if ((addr >= env->pmp_state.addr[pmp_index].sa)
+ && (addr <= env->pmp_state.addr[pmp_index].ea)) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+
+ return result;
+}
+
+/*
+ * Check if the address has required RWX privs when no PMP entry is matched.
+ */
+static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
+ target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
+ target_ulong mode)
+{
+ bool ret;
+
+ if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ if (MSECCFG_MMWP_ISSET(env)) {
+ /*
+ * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
+ * so we default to deny all, even for M-mode.
+ */
+ *allowed_privs = 0;
+ return false;
+ } else if (MSECCFG_MML_ISSET(env)) {
+ /*
+ * The Machine Mode Lockdown (mseccfg.MML) bit is set
+ * so we can only execute code in M-mode with an applicable
+ * rule. Other modes are disabled.
+ */
+ if (mode == PRV_M && !(privs & PMP_EXEC)) {
+ ret = true;
+ *allowed_privs = PMP_READ | PMP_WRITE;
+ } else {
+ ret = false;
+ *allowed_privs = 0;
+ }
+
+ return ret;
+ }
+ }
+
+ if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
+ /*
+ * Privileged spec v1.10 states if HW doesn't implement any PMP entry
+ * or no PMP entry matches an M-Mode access, the access succeeds.
+ */
+ ret = true;
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ } else {
+ /*
+ * Other modes are not allowed to succeed if they don't * match a rule,
+ * but there are rules. We've checked for no rule earlier in this
+ * function.
+ */
+ ret = false;
+ *allowed_privs = 0;
+ }
+
+ return ret;
+}
+
+
+/*
+ * Public Interface
+ */
+
+/*
+ * Check if the address has required RWX privs to complete desired operation
+ */
+bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
+ target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
+ target_ulong mode)
+{
+ int i = 0;
+ int ret = -1;
+ int pmp_size = 0;
+ target_ulong s = 0;
+ target_ulong e = 0;
+
+ /* Short cut if no rules */
+ if (0 == pmp_get_num_rules(env)) {
+ return pmp_hart_has_privs_default(env, addr, size, privs,
+ allowed_privs, mode);
+ }
+
+ if (size == 0) {
+ if (riscv_feature(env, RISCV_FEATURE_MMU)) {
+ /*
+ * If size is unknown (0), assume that all bytes
+ * from addr to the end of the page will be accessed.
+ */
+ pmp_size = -(addr | TARGET_PAGE_MASK);
+ } else {
+ pmp_size = sizeof(target_ulong);
+ }
+ } else {
+ pmp_size = size;
+ }
+
+ /* 1.10 draft priv spec states there is an implicit order
+ from low to high */
+ for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ s = pmp_is_in_range(env, i, addr);
+ e = pmp_is_in_range(env, i, addr + pmp_size - 1);
+
+ /* partially inside */
+ if ((s + e) == 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pmp violation - access is partially inside\n");
+ ret = 0;
+ break;
+ }
+
+ /* fully inside */
+ const uint8_t a_field =
+ pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
+
+ /*
+ * Convert the PMP permissions to match the truth table in the
+ * ePMP spec.
+ */
+ const uint8_t epmp_operation =
+ ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
+ ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
+ (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
+ ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
+
+ if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
+ /*
+ * If the PMP entry is not off and the address is in range,
+ * do the priv check
+ */
+ if (!MSECCFG_MML_ISSET(env)) {
+ /*
+ * If mseccfg.MML Bit is not set, do pmp priv check
+ * This will always apply to regular PMP.
+ */
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ if ((mode != PRV_M) || pmp_is_locked(env, i)) {
+ *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
+ }
+ } else {
+ /*
+ * If mseccfg.MML Bit set, do the enhanced pmp priv check
+ */
+ if (mode == PRV_M) {
+ switch (epmp_operation) {
+ case 0:
+ case 1:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ *allowed_privs = 0;
+ break;
+ case 2:
+ case 3:
+ case 14:
+ *allowed_privs = PMP_READ | PMP_WRITE;
+ break;
+ case 9:
+ case 10:
+ *allowed_privs = PMP_EXEC;
+ break;
+ case 11:
+ case 13:
+ *allowed_privs = PMP_READ | PMP_EXEC;
+ break;
+ case 12:
+ case 15:
+ *allowed_privs = PMP_READ;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ } else {
+ switch (epmp_operation) {
+ case 0:
+ case 8:
+ case 9:
+ case 12:
+ case 13:
+ case 14:
+ *allowed_privs = 0;
+ break;
+ case 1:
+ case 10:
+ case 11:
+ *allowed_privs = PMP_EXEC;
+ break;
+ case 2:
+ case 4:
+ case 15:
+ *allowed_privs = PMP_READ;
+ break;
+ case 3:
+ case 6:
+ *allowed_privs = PMP_READ | PMP_WRITE;
+ break;
+ case 5:
+ *allowed_privs = PMP_READ | PMP_EXEC;
+ break;
+ case 7:
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ }
+
+ ret = ((privs & *allowed_privs) == privs);
+ break;
+ }
+ }
+
+ /* No rule matched */
+ if (ret == -1) {
+ return pmp_hart_has_privs_default(env, addr, size, privs,
+ allowed_privs, mode);
+ }
+
+ return ret == 1 ? true : false;
+}
+
+/*
+ * Handle a write to a pmpcfg CSR
+ */
+void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
+ target_ulong val)
+{
+ int i;
+ uint8_t cfg_val;
+
+ trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
+
+ if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpcfg write - incorrect address\n");
+ return;
+ }
+
+ for (i = 0; i < sizeof(target_ulong); i++) {
+ cfg_val = (val >> 8 * i) & 0xff;
+ pmp_write_cfg(env, (reg_index * 4) + i, cfg_val);
+ }
+
+ /* If PMP permission of any addr has been changed, flush TLB pages. */
+ tlb_flush(env_cpu(env));
+}
+
+
+/*
+ * Handle a read from a pmpcfg CSR
+ */
+target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
+{
+ int i;
+ target_ulong cfg_val = 0;
+ target_ulong val = 0;
+
+ for (i = 0; i < sizeof(target_ulong); i++) {
+ val = pmp_read_cfg(env, (reg_index * 4) + i);
+ cfg_val |= (val << (i * 8));
+ }
+ trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val);
+
+ return cfg_val;
+}
+
+
+/*
+ * Handle a write to a pmpaddr CSR
+ */
+void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
+ target_ulong val)
+{
+ trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
+
+ if (addr_index < MAX_RISCV_PMPS) {
+ /*
+ * In TOR mode, need to check the lock bit of the next pmp
+ * (if there is a next).
+ */
+ if (addr_index + 1 < MAX_RISCV_PMPS) {
+ uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
+
+ if (pmp_cfg & PMP_LOCK &&
+ PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr write - pmpcfg + 1 locked\n");
+ return;
+ }
+ }
+
+ if (!pmp_is_locked(env, addr_index)) {
+ env->pmp_state.pmp[addr_index].addr_reg = val;
+ pmp_update_rule(env, addr_index);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr write - locked\n");
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr write - out of bounds\n");
+ }
+}
+
+
+/*
+ * Handle a read from a pmpaddr CSR
+ */
+target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
+{
+ target_ulong val = 0;
+
+ if (addr_index < MAX_RISCV_PMPS) {
+ val = env->pmp_state.pmp[addr_index].addr_reg;
+ trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr read - out of bounds\n");
+ }
+
+ return val;
+}
+
+/*
+ * Handle a write to a mseccfg CSR
+ */
+void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
+{
+ int i;
+
+ trace_mseccfg_csr_write(env->mhartid, val);
+
+ /* RLB cannot be enabled if it's already 0 and if any regions are locked */
+ if (!MSECCFG_RLB_ISSET(env)) {
+ for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ if (pmp_is_locked(env, i)) {
+ val &= ~MSECCFG_RLB;
+ break;
+ }
+ }
+ }
+
+ /* Sticky bits */
+ val |= (env->mseccfg & (MSECCFG_MMWP | MSECCFG_MML));
+
+ env->mseccfg = val;
+}
+
+/*
+ * Handle a read from a mseccfg CSR
+ */
+target_ulong mseccfg_csr_read(CPURISCVState *env)
+{
+ trace_mseccfg_csr_read(env->mhartid, env->mseccfg);
+ return env->mseccfg;
+}
+
+/*
+ * Calculate the TLB size if the start address or the end address of
+ * PMP entry is presented in the TLB page.
+ */
+static target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index,
+ target_ulong tlb_sa, target_ulong tlb_ea)
+{
+ target_ulong pmp_sa = env->pmp_state.addr[pmp_index].sa;
+ target_ulong pmp_ea = env->pmp_state.addr[pmp_index].ea;
+
+ if (pmp_sa >= tlb_sa && pmp_ea <= tlb_ea) {
+ return pmp_ea - pmp_sa + 1;
+ }
+
+ if (pmp_sa >= tlb_sa && pmp_sa <= tlb_ea && pmp_ea >= tlb_ea) {
+ return tlb_ea - pmp_sa + 1;
+ }
+
+ if (pmp_ea <= tlb_ea && pmp_ea >= tlb_sa && pmp_sa <= tlb_sa) {
+ return pmp_ea - tlb_sa + 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Check is there a PMP entry which range covers this page. If so,
+ * try to find the minimum granularity for the TLB size.
+ */
+bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
+ target_ulong *tlb_size)
+{
+ int i;
+ target_ulong val;
+ target_ulong tlb_ea = (tlb_sa + TARGET_PAGE_SIZE - 1);
+
+ for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ val = pmp_get_tlb_size(env, i, tlb_sa, tlb_ea);
+ if (val) {
+ if (*tlb_size == 0 || *tlb_size > val) {
+ *tlb_size = val;
+ }
+ }
+ }
+
+ if (*tlb_size != 0) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Convert PMP privilege to TLB page privilege.
+ */
+int pmp_priv_to_page_prot(pmp_priv_t pmp_priv)
+{
+ int prot = 0;
+
+ if (pmp_priv & PMP_READ) {
+ prot |= PAGE_READ;
+ }
+ if (pmp_priv & PMP_WRITE) {
+ prot |= PAGE_WRITE;
+ }
+ if (pmp_priv & PMP_EXEC) {
+ prot |= PAGE_EXEC;
+ }
+
+ return prot;
+}
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
new file mode 100644
index 000000000..a9a0b363a
--- /dev/null
+++ b/target/riscv/pmp.h
@@ -0,0 +1,85 @@
+/*
+ * QEMU RISC-V PMP (Physical Memory Protection)
+ *
+ * Author: Daire McNamara, daire.mcnamara@emdalo.com
+ * Ivan Griffin, ivan.griffin@emdalo.com
+ *
+ * This provides a RISC-V Physical Memory Protection interface
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RISCV_PMP_H
+#define RISCV_PMP_H
+
+typedef enum {
+ PMP_READ = 1 << 0,
+ PMP_WRITE = 1 << 1,
+ PMP_EXEC = 1 << 2,
+ PMP_LOCK = 1 << 7
+} pmp_priv_t;
+
+typedef enum {
+ PMP_AMATCH_OFF, /* Null (off) */
+ PMP_AMATCH_TOR, /* Top of Range */
+ PMP_AMATCH_NA4, /* Naturally aligned four-byte region */
+ PMP_AMATCH_NAPOT /* Naturally aligned power-of-two region */
+} pmp_am_t;
+
+typedef enum {
+ MSECCFG_MML = 1 << 0,
+ MSECCFG_MMWP = 1 << 1,
+ MSECCFG_RLB = 1 << 2
+} mseccfg_field_t;
+
+typedef struct {
+ target_ulong addr_reg;
+ uint8_t cfg_reg;
+} pmp_entry_t;
+
+typedef struct {
+ target_ulong sa;
+ target_ulong ea;
+} pmp_addr_t;
+
+typedef struct {
+ pmp_entry_t pmp[MAX_RISCV_PMPS];
+ pmp_addr_t addr[MAX_RISCV_PMPS];
+ uint32_t num_rules;
+} pmp_table_t;
+
+void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
+ target_ulong val);
+target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index);
+
+void mseccfg_csr_write(CPURISCVState *env, target_ulong val);
+target_ulong mseccfg_csr_read(CPURISCVState *env);
+
+void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
+ target_ulong val);
+target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
+bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
+ target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
+ target_ulong mode);
+bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
+ target_ulong *tlb_size);
+void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
+void pmp_update_rule_nums(CPURISCVState *env);
+uint32_t pmp_get_num_rules(CPURISCVState *env);
+int pmp_priv_to_page_prot(pmp_priv_t pmp_priv);
+
+#define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML)
+#define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP)
+#define MSECCFG_RLB_ISSET(env) get_field(env->mseccfg, MSECCFG_RLB)
+
+#endif
diff --git a/target/riscv/trace-events b/target/riscv/trace-events
new file mode 100644
index 000000000..49ec4d3b7
--- /dev/null
+++ b/target/riscv/trace-events
@@ -0,0 +1,11 @@
+# cpu_helper.c
+riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s"
+
+# pmp.c
+pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": read reg%" PRIu32", val: 0x%" PRIx64
+pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64
+pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64
+pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64
+
+mseccfg_csr_read(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": read mseccfg, val: 0x%" PRIx64
+mseccfg_csr_write(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": write mseccfg, val: 0x%" PRIx64
diff --git a/target/riscv/trace.h b/target/riscv/trace.h
new file mode 100644
index 000000000..03a89fcd9
--- /dev/null
+++ b/target/riscv/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-target_riscv.h"
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
new file mode 100644
index 000000000..1d57bc97b
--- /dev/null
+++ b/target/riscv/translate.c
@@ -0,0 +1,773 @@
+/*
+ * RISC-V emulation for qemu: main translation routines.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "tcg/tcg-op.h"
+#include "disas/disas.h"
+#include "exec/cpu_ldst.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+#include "exec/translator.h"
+#include "exec/log.h"
+
+#include "instmap.h"
+
+/* global register indices */
+static TCGv cpu_gpr[32], cpu_pc, cpu_vl;
+static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
+static TCGv load_res;
+static TCGv load_val;
+/* globals for PM CSRs */
+static TCGv pm_mask[4];
+static TCGv pm_base[4];
+
+#include "exec/gen-icount.h"
+
+/*
+ * If an operation is being performed on less than TARGET_LONG_BITS,
+ * it may require the inputs to be sign- or zero-extended; which will
+ * depend on the exact operation being performed.
+ */
+typedef enum {
+ EXT_NONE,
+ EXT_SIGN,
+ EXT_ZERO,
+} DisasExtend;
+
+typedef struct DisasContext {
+ DisasContextBase base;
+ /* pc_succ_insn points to the instruction following base.pc_next */
+ target_ulong pc_succ_insn;
+ target_ulong priv_ver;
+ RISCVMXL xl;
+ uint32_t misa_ext;
+ uint32_t opcode;
+ uint32_t mstatus_fs;
+ uint32_t mstatus_hs_fs;
+ uint32_t mem_idx;
+ /* Remember the rounding mode encoded in the previous fp instruction,
+ which we have already installed into env->fp_status. Or -1 for
+ no previous fp instruction. Note that we exit the TB when writing
+ to any system register, which includes CSR_FRM, so we do not have
+ to reset this known value. */
+ int frm;
+ RISCVMXL ol;
+ bool virt_enabled;
+ bool ext_ifencei;
+ bool hlsx;
+ /* vector extension */
+ bool vill;
+ uint8_t lmul;
+ uint8_t sew;
+ uint16_t vlen;
+ uint16_t mlen;
+ bool vl_eq_vlmax;
+ uint8_t ntemp;
+ CPUState *cs;
+ TCGv zero;
+ /* Space for 3 operands plus 1 extra for address computation. */
+ TCGv temp[4];
+ /* PointerMasking extension */
+ bool pm_enabled;
+ TCGv pm_mask;
+ TCGv pm_base;
+} DisasContext;
+
+static inline bool has_ext(DisasContext *ctx, uint32_t ext)
+{
+ return ctx->misa_ext & ext;
+}
+
+#ifdef TARGET_RISCV32
+#define get_xl(ctx) MXL_RV32
+#elif defined(CONFIG_USER_ONLY)
+#define get_xl(ctx) MXL_RV64
+#else
+#define get_xl(ctx) ((ctx)->xl)
+#endif
+
+/* The word size for this machine mode. */
+static inline int __attribute__((unused)) get_xlen(DisasContext *ctx)
+{
+ return 16 << get_xl(ctx);
+}
+
+/* The operation length, as opposed to the xlen. */
+#ifdef TARGET_RISCV32
+#define get_ol(ctx) MXL_RV32
+#else
+#define get_ol(ctx) ((ctx)->ol)
+#endif
+
+static inline int get_olen(DisasContext *ctx)
+{
+ return 16 << get_ol(ctx);
+}
+
+/*
+ * RISC-V requires NaN-boxing of narrower width floating point values.
+ * This applies when a 32-bit value is assigned to a 64-bit FP register.
+ * For consistency and simplicity, we nanbox results even when the RVD
+ * extension is not present.
+ */
+static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in)
+{
+ tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32));
+}
+
+/*
+ * A narrow n-bit operation, where n < FLEN, checks that input operands
+ * are correctly Nan-boxed, i.e., all upper FLEN - n bits are 1.
+ * If so, the least-significant bits of the input are used, otherwise the
+ * input value is treated as an n-bit canonical NaN (v2.2 section 9.2).
+ *
+ * Here, the result is always nan-boxed, even the canonical nan.
+ */
+static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
+{
+ TCGv_i64 t_max = tcg_constant_i64(0xffffffff00000000ull);
+ TCGv_i64 t_nan = tcg_constant_i64(0xffffffff7fc00000ull);
+
+ tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
+}
+
+static void generate_exception(DisasContext *ctx, int excp)
+{
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+static void generate_exception_mtval(DisasContext *ctx, int excp)
+{
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+ tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+static void gen_exception_illegal(DisasContext *ctx)
+{
+ generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
+}
+
+static void gen_exception_inst_addr_mis(DisasContext *ctx)
+{
+ generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS);
+}
+
+static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+ if (translator_use_goto_tb(&ctx->base, dest)) {
+ tcg_gen_goto_tb(n);
+ tcg_gen_movi_tl(cpu_pc, dest);
+ tcg_gen_exit_tb(ctx->base.tb, n);
+ } else {
+ tcg_gen_movi_tl(cpu_pc, dest);
+ tcg_gen_lookup_and_goto_ptr();
+ }
+}
+
+/*
+ * Wrappers for getting reg values.
+ *
+ * The $zero register does not have cpu_gpr[0] allocated -- we supply the
+ * constant zero as a source, and an uninitialized sink as destination.
+ *
+ * Further, we may provide an extension for word operations.
+ */
+static TCGv temp_new(DisasContext *ctx)
+{
+ assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));
+ return ctx->temp[ctx->ntemp++] = tcg_temp_new();
+}
+
+static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
+{
+ TCGv t;
+
+ if (reg_num == 0) {
+ return ctx->zero;
+ }
+
+ switch (get_ol(ctx)) {
+ case MXL_RV32:
+ switch (ext) {
+ case EXT_NONE:
+ break;
+ case EXT_SIGN:
+ t = temp_new(ctx);
+ tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
+ return t;
+ case EXT_ZERO:
+ t = temp_new(ctx);
+ tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
+ return t;
+ default:
+ g_assert_not_reached();
+ }
+ break;
+ case MXL_RV64:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return cpu_gpr[reg_num];
+}
+
+static TCGv dest_gpr(DisasContext *ctx, int reg_num)
+{
+ if (reg_num == 0 || get_olen(ctx) < TARGET_LONG_BITS) {
+ return temp_new(ctx);
+ }
+ return cpu_gpr[reg_num];
+}
+
+static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
+{
+ if (reg_num != 0) {
+ switch (get_ol(ctx)) {
+ case MXL_RV32:
+ tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
+ break;
+ case MXL_RV64:
+ tcg_gen_mov_tl(cpu_gpr[reg_num], t);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+}
+
+static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
+{
+ target_ulong next_pc;
+
+ /* check misaligned: */
+ next_pc = ctx->base.pc_next + imm;
+ if (!has_ext(ctx, RVC)) {
+ if ((next_pc & 0x3) != 0) {
+ gen_exception_inst_addr_mis(ctx);
+ return;
+ }
+ }
+ if (rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc_succ_insn);
+ }
+
+ gen_goto_tb(ctx, 0, ctx->base.pc_next + imm); /* must use this for safety */
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+/*
+ * Generates address adjustment for PointerMasking
+ */
+static TCGv gen_pm_adjust_address(DisasContext *s, TCGv src)
+{
+ TCGv temp;
+ if (!s->pm_enabled) {
+ /* Load unmodified address */
+ return src;
+ } else {
+ temp = temp_new(s);
+ tcg_gen_andc_tl(temp, src, s->pm_mask);
+ tcg_gen_or_tl(temp, temp, s->pm_base);
+ return temp;
+ }
+}
+
+#ifndef CONFIG_USER_ONLY
+/* The states of mstatus_fs are:
+ * 0 = disabled, 1 = initial, 2 = clean, 3 = dirty
+ * We will have already diagnosed disabled state,
+ * and need to turn initial/clean into dirty.
+ */
+static void mark_fs_dirty(DisasContext *ctx)
+{
+ TCGv tmp;
+
+ if (ctx->mstatus_fs != MSTATUS_FS) {
+ /* Remember the state change for the rest of the TB. */
+ ctx->mstatus_fs = MSTATUS_FS;
+
+ tmp = tcg_temp_new();
+ tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
+ tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
+ tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
+ tcg_temp_free(tmp);
+ }
+
+ if (ctx->virt_enabled && ctx->mstatus_hs_fs != MSTATUS_FS) {
+ /* Remember the stage change for the rest of the TB. */
+ ctx->mstatus_hs_fs = MSTATUS_FS;
+
+ tmp = tcg_temp_new();
+ tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
+ tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
+ tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
+ tcg_temp_free(tmp);
+ }
+}
+#else
+static inline void mark_fs_dirty(DisasContext *ctx) { }
+#endif
+
+static void gen_set_rm(DisasContext *ctx, int rm)
+{
+ if (ctx->frm == rm) {
+ return;
+ }
+ ctx->frm = rm;
+ gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm));
+}
+
+static int ex_plus_1(DisasContext *ctx, int nf)
+{
+ return nf + 1;
+}
+
+#define EX_SH(amount) \
+ static int ex_shift_##amount(DisasContext *ctx, int imm) \
+ { \
+ return imm << amount; \
+ }
+EX_SH(1)
+EX_SH(2)
+EX_SH(3)
+EX_SH(4)
+EX_SH(12)
+
+#define REQUIRE_EXT(ctx, ext) do { \
+ if (!has_ext(ctx, ext)) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_32BIT(ctx) do { \
+ if (get_xl(ctx) != MXL_RV32) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_64BIT(ctx) do { \
+ if (get_xl(ctx) < MXL_RV64) { \
+ return false; \
+ } \
+} while (0)
+
+static int ex_rvc_register(DisasContext *ctx, int reg)
+{
+ return 8 + reg;
+}
+
+static int ex_rvc_shifti(DisasContext *ctx, int imm)
+{
+ /* For RV128 a shamt of 0 means a shift by 64. */
+ return imm ? imm : 64;
+}
+
+/* Include the auto-generated decoder for 32 bit insn */
+#include "decode-insn32.c.inc"
+
+static bool gen_arith_imm_fn(DisasContext *ctx, arg_i *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, target_long))
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+
+ func(dest, src1, a->imm);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+ TCGv src2 = tcg_constant_tl(a->imm);
+
+ func(dest, src1, src2);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+ TCGv src2 = get_gpr(ctx, a->rs2, ext);
+
+ func(dest, src1, src2);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_arith_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
+ void (*f_tl)(TCGv, TCGv, TCGv),
+ void (*f_32)(TCGv, TCGv, TCGv))
+{
+ int olen = get_olen(ctx);
+
+ if (olen != TARGET_LONG_BITS) {
+ if (olen == 32) {
+ f_tl = f_32;
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ return gen_arith(ctx, a, ext, f_tl);
+}
+
+static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, target_long))
+{
+ TCGv dest, src1;
+ int max_len = get_olen(ctx);
+
+ if (a->shamt >= max_len) {
+ return false;
+ }
+
+ dest = dest_gpr(ctx, a->rd);
+ src1 = get_gpr(ctx, a->rs1, ext);
+
+ func(dest, src1, a->shamt);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_shift_imm_fn_per_ol(DisasContext *ctx, arg_shift *a,
+ DisasExtend ext,
+ void (*f_tl)(TCGv, TCGv, target_long),
+ void (*f_32)(TCGv, TCGv, target_long))
+{
+ int olen = get_olen(ctx);
+ if (olen != TARGET_LONG_BITS) {
+ if (olen == 32) {
+ f_tl = f_32;
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ return gen_shift_imm_fn(ctx, a, ext, f_tl);
+}
+
+static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest, src1, src2;
+ int max_len = get_olen(ctx);
+
+ if (a->shamt >= max_len) {
+ return false;
+ }
+
+ dest = dest_gpr(ctx, a->rd);
+ src1 = get_gpr(ctx, a->rs1, ext);
+ src2 = tcg_constant_tl(a->shamt);
+
+ func(dest, src1, src2);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv, TCGv))
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+ TCGv ext2 = tcg_temp_new();
+
+ tcg_gen_andi_tl(ext2, src2, get_olen(ctx) - 1);
+ func(dest, src1, ext2);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ tcg_temp_free(ext2);
+ return true;
+}
+
+static bool gen_shift_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext,
+ void (*f_tl)(TCGv, TCGv, TCGv),
+ void (*f_32)(TCGv, TCGv, TCGv))
+{
+ int olen = get_olen(ctx);
+ if (olen != TARGET_LONG_BITS) {
+ if (olen == 32) {
+ f_tl = f_32;
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ return gen_shift(ctx, a, ext, f_tl);
+}
+
+static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
+ void (*func)(TCGv, TCGv))
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1 = get_gpr(ctx, a->rs1, ext);
+
+ func(dest, src1);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
+ void (*f_tl)(TCGv, TCGv),
+ void (*f_32)(TCGv, TCGv))
+{
+ int olen = get_olen(ctx);
+
+ if (olen != TARGET_LONG_BITS) {
+ if (olen == 32) {
+ f_tl = f_32;
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ return gen_unary(ctx, a, ext, f_tl);
+}
+
+static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPUState *cpu = ctx->cs;
+ CPURISCVState *env = cpu->env_ptr;
+
+ return cpu_ldl_code(env, pc);
+}
+
+/* Include insn module translation function */
+#include "insn_trans/trans_rvi.c.inc"
+#include "insn_trans/trans_rvm.c.inc"
+#include "insn_trans/trans_rva.c.inc"
+#include "insn_trans/trans_rvf.c.inc"
+#include "insn_trans/trans_rvd.c.inc"
+#include "insn_trans/trans_rvh.c.inc"
+#include "insn_trans/trans_rvv.c.inc"
+#include "insn_trans/trans_rvb.c.inc"
+#include "insn_trans/trans_privileged.c.inc"
+
+/* Include the auto-generated decoder for 16 bit insn */
+#include "decode-insn16.c.inc"
+
+static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
+{
+ /* check for compressed insn */
+ if (extract16(opcode, 0, 2) != 3) {
+ if (!has_ext(ctx, RVC)) {
+ gen_exception_illegal(ctx);
+ } else {
+ ctx->pc_succ_insn = ctx->base.pc_next + 2;
+ if (!decode_insn16(ctx, opcode)) {
+ gen_exception_illegal(ctx);
+ }
+ }
+ } else {
+ uint32_t opcode32 = opcode;
+ opcode32 = deposit32(opcode32, 16, 16,
+ translator_lduw(env, &ctx->base,
+ ctx->base.pc_next + 2));
+ ctx->pc_succ_insn = ctx->base.pc_next + 4;
+ if (!decode_insn32(ctx, opcode32)) {
+ gen_exception_illegal(ctx);
+ }
+ }
+}
+
+static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPURISCVState *env = cs->env_ptr;
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ uint32_t tb_flags = ctx->base.tb->flags;
+
+ ctx->pc_succ_insn = ctx->base.pc_first;
+ ctx->mem_idx = FIELD_EX32(tb_flags, TB_FLAGS, MEM_IDX);
+ ctx->mstatus_fs = tb_flags & TB_FLAGS_MSTATUS_FS;
+ ctx->priv_ver = env->priv_ver;
+#if !defined(CONFIG_USER_ONLY)
+ if (riscv_has_ext(env, RVH)) {
+ ctx->virt_enabled = riscv_cpu_virt_enabled(env);
+ } else {
+ ctx->virt_enabled = false;
+ }
+#else
+ ctx->virt_enabled = false;
+#endif
+ ctx->misa_ext = env->misa_ext;
+ ctx->frm = -1; /* unknown rounding mode */
+ ctx->ext_ifencei = cpu->cfg.ext_ifencei;
+ ctx->vlen = cpu->cfg.vlen;
+ ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS);
+ ctx->hlsx = FIELD_EX32(tb_flags, TB_FLAGS, HLSX);
+ ctx->vill = FIELD_EX32(tb_flags, TB_FLAGS, VILL);
+ ctx->sew = FIELD_EX32(tb_flags, TB_FLAGS, SEW);
+ ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL);
+ ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul);
+ ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX);
+ ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL);
+ ctx->cs = cs;
+ ctx->ntemp = 0;
+ memset(ctx->temp, 0, sizeof(ctx->temp));
+ ctx->pm_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_ENABLED);
+ int priv = tb_flags & TB_FLAGS_PRIV_MMU_MASK;
+ ctx->pm_mask = pm_mask[priv];
+ ctx->pm_base = pm_base[priv];
+
+ ctx->zero = tcg_constant_tl(0);
+}
+
+static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
+{
+}
+
+static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ tcg_gen_insn_start(ctx->base.pc_next);
+}
+
+static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPURISCVState *env = cpu->env_ptr;
+ uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next);
+
+ ctx->ol = ctx->xl;
+ decode_opc(env, ctx, opcode16);
+ ctx->base.pc_next = ctx->pc_succ_insn;
+
+ for (int i = ctx->ntemp - 1; i >= 0; --i) {
+ tcg_temp_free(ctx->temp[i]);
+ ctx->temp[i] = NULL;
+ }
+ ctx->ntemp = 0;
+
+ if (ctx->base.is_jmp == DISAS_NEXT) {
+ target_ulong page_start;
+
+ page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
+ if (ctx->base.pc_next - page_start >= TARGET_PAGE_SIZE) {
+ ctx->base.is_jmp = DISAS_TOO_MANY;
+ }
+ }
+}
+
+static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+ switch (ctx->base.is_jmp) {
+ case DISAS_TOO_MANY:
+ gen_goto_tb(ctx, 0, ctx->base.pc_next);
+ break;
+ case DISAS_NORETURN:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
+{
+#ifndef CONFIG_USER_ONLY
+ RISCVCPU *rvcpu = RISCV_CPU(cpu);
+ CPURISCVState *env = &rvcpu->env;
+#endif
+
+ qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
+#ifndef CONFIG_USER_ONLY
+ qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt);
+#endif
+ log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
+}
+
+static const TranslatorOps riscv_tr_ops = {
+ .init_disas_context = riscv_tr_init_disas_context,
+ .tb_start = riscv_tr_tb_start,
+ .insn_start = riscv_tr_insn_start,
+ .translate_insn = riscv_tr_translate_insn,
+ .tb_stop = riscv_tr_tb_stop,
+ .disas_log = riscv_tr_disas_log,
+};
+
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
+{
+ DisasContext ctx;
+
+ translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns);
+}
+
+void riscv_translate_init(void)
+{
+ int i;
+
+ /*
+ * cpu_gpr[0] is a placeholder for the zero register. Do not use it.
+ * Use the gen_set_gpr and get_gpr helper functions when accessing regs,
+ * unless you specifically block reads/writes to reg 0.
+ */
+ cpu_gpr[0] = NULL;
+
+ for (i = 1; i < 32; i++) {
+ cpu_gpr[i] = tcg_global_mem_new(cpu_env,
+ offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
+ offsetof(CPURISCVState, fpr[i]), riscv_fpr_regnames[i]);
+ }
+
+ cpu_pc = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, pc), "pc");
+ cpu_vl = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, vl), "vl");
+ load_res = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_res),
+ "load_res");
+ load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val),
+ "load_val");
+#ifndef CONFIG_USER_ONLY
+ /* Assign PM CSRs to tcg globals */
+ pm_mask[PRV_U] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmmask), "upmmask");
+ pm_base[PRV_U] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmbase), "upmbase");
+ pm_mask[PRV_S] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmmask), "spmmask");
+ pm_base[PRV_S] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmbase), "spmbase");
+ pm_mask[PRV_M] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmmask), "mpmmask");
+ pm_base[PRV_M] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmbase), "mpmbase");
+#endif
+}
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
new file mode 100644
index 000000000..12c31aa4b
--- /dev/null
+++ b/target/riscv/vector_helper.c
@@ -0,0 +1,4872 @@
+/*
+ * RISC-V Vector Extension Helpers for QEMU.
+ *
+ * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/memop.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+#include "tcg/tcg-gvec-desc.h"
+#include "internals.h"
+#include <math.h>
+
+target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
+ target_ulong s2)
+{
+ int vlmax, vl;
+ RISCVCPU *cpu = env_archcpu(env);
+ uint16_t sew = 8 << FIELD_EX64(s2, VTYPE, VSEW);
+ uint8_t ediv = FIELD_EX64(s2, VTYPE, VEDIV);
+ bool vill = FIELD_EX64(s2, VTYPE, VILL);
+ target_ulong reserved = FIELD_EX64(s2, VTYPE, RESERVED);
+
+ if ((sew > cpu->cfg.elen) || vill || (ediv != 0) || (reserved != 0)) {
+ /* only set vill bit. */
+ env->vtype = FIELD_DP64(0, VTYPE, VILL, 1);
+ env->vl = 0;
+ env->vstart = 0;
+ return 0;
+ }
+
+ vlmax = vext_get_vlmax(cpu, s2);
+ if (s1 <= vlmax) {
+ vl = s1;
+ } else {
+ vl = vlmax;
+ }
+ env->vl = vl;
+ env->vtype = s2;
+ env->vstart = 0;
+ return vl;
+}
+
+/*
+ * Note that vector data is stored in host-endian 64-bit chunks,
+ * so addressing units smaller than that needs a host-endian fixup.
+ */
+#ifdef HOST_WORDS_BIGENDIAN
+#define H1(x) ((x) ^ 7)
+#define H1_2(x) ((x) ^ 6)
+#define H1_4(x) ((x) ^ 4)
+#define H2(x) ((x) ^ 3)
+#define H4(x) ((x) ^ 1)
+#define H8(x) ((x))
+#else
+#define H1(x) (x)
+#define H1_2(x) (x)
+#define H1_4(x) (x)
+#define H2(x) (x)
+#define H4(x) (x)
+#define H8(x) (x)
+#endif
+
+static inline uint32_t vext_nf(uint32_t desc)
+{
+ return FIELD_EX32(simd_data(desc), VDATA, NF);
+}
+
+static inline uint32_t vext_mlen(uint32_t desc)
+{
+ return FIELD_EX32(simd_data(desc), VDATA, MLEN);
+}
+
+static inline uint32_t vext_vm(uint32_t desc)
+{
+ return FIELD_EX32(simd_data(desc), VDATA, VM);
+}
+
+static inline uint32_t vext_lmul(uint32_t desc)
+{
+ return FIELD_EX32(simd_data(desc), VDATA, LMUL);
+}
+
+static uint32_t vext_wd(uint32_t desc)
+{
+ return (simd_data(desc) >> 11) & 0x1;
+}
+
+/*
+ * Get vector group length in bytes. Its range is [64, 2048].
+ *
+ * As simd_desc support at most 256, the max vlen is 512 bits.
+ * So vlen in bytes is encoded as maxsz.
+ */
+static inline uint32_t vext_maxsz(uint32_t desc)
+{
+ return simd_maxsz(desc) << vext_lmul(desc);
+}
+
+/*
+ * This function checks watchpoint before real load operation.
+ *
+ * In softmmu mode, the TLB API probe_access is enough for watchpoint check.
+ * In user mode, there is no watchpoint support now.
+ *
+ * It will trigger an exception if there is no mapping in TLB
+ * and page table walk can't fill the TLB entry. Then the guest
+ * software can return here after process the exception or never return.
+ */
+static void probe_pages(CPURISCVState *env, target_ulong addr,
+ target_ulong len, uintptr_t ra,
+ MMUAccessType access_type)
+{
+ target_ulong pagelen = -(addr | TARGET_PAGE_MASK);
+ target_ulong curlen = MIN(pagelen, len);
+
+ probe_access(env, addr, curlen, access_type,
+ cpu_mmu_index(env, false), ra);
+ if (len > curlen) {
+ addr += curlen;
+ curlen = len - curlen;
+ probe_access(env, addr, curlen, access_type,
+ cpu_mmu_index(env, false), ra);
+ }
+}
+
+#ifdef HOST_WORDS_BIGENDIAN
+static void vext_clear(void *tail, uint32_t cnt, uint32_t tot)
+{
+ /*
+ * Split the remaining range to two parts.
+ * The first part is in the last uint64_t unit.
+ * The second part start from the next uint64_t unit.
+ */
+ int part1 = 0, part2 = tot - cnt;
+ if (cnt % 8) {
+ part1 = 8 - (cnt % 8);
+ part2 = tot - cnt - part1;
+ memset(QEMU_ALIGN_PTR_DOWN(tail, 8), 0, part1);
+ memset(QEMU_ALIGN_PTR_UP(tail, 8), 0, part2);
+ } else {
+ memset(tail, 0, part2);
+ }
+}
+#else
+static void vext_clear(void *tail, uint32_t cnt, uint32_t tot)
+{
+ memset(tail, 0, tot - cnt);
+}
+#endif
+
+static void clearb(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot)
+{
+ int8_t *cur = ((int8_t *)vd + H1(idx));
+ vext_clear(cur, cnt, tot);
+}
+
+static void clearh(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot)
+{
+ int16_t *cur = ((int16_t *)vd + H2(idx));
+ vext_clear(cur, cnt, tot);
+}
+
+static void clearl(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot)
+{
+ int32_t *cur = ((int32_t *)vd + H4(idx));
+ vext_clear(cur, cnt, tot);
+}
+
+static void clearq(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot)
+{
+ int64_t *cur = (int64_t *)vd + idx;
+ vext_clear(cur, cnt, tot);
+}
+
+static inline void vext_set_elem_mask(void *v0, int mlen, int index,
+ uint8_t value)
+{
+ int idx = (index * mlen) / 64;
+ int pos = (index * mlen) % 64;
+ uint64_t old = ((uint64_t *)v0)[idx];
+ ((uint64_t *)v0)[idx] = deposit64(old, pos, mlen, value);
+}
+
+static inline int vext_elem_mask(void *v0, int mlen, int index)
+{
+ int idx = (index * mlen) / 64;
+ int pos = (index * mlen) % 64;
+ return (((uint64_t *)v0)[idx] >> pos) & 1;
+}
+
+/* elements operations for load and store */
+typedef void vext_ldst_elem_fn(CPURISCVState *env, target_ulong addr,
+ uint32_t idx, void *vd, uintptr_t retaddr);
+typedef void clear_fn(void *vd, uint32_t idx, uint32_t cnt, uint32_t tot);
+
+#define GEN_VEXT_LD_ELEM(NAME, MTYPE, ETYPE, H, LDSUF) \
+static void NAME(CPURISCVState *env, abi_ptr addr, \
+ uint32_t idx, void *vd, uintptr_t retaddr)\
+{ \
+ MTYPE data; \
+ ETYPE *cur = ((ETYPE *)vd + H(idx)); \
+ data = cpu_##LDSUF##_data_ra(env, addr, retaddr); \
+ *cur = data; \
+} \
+
+GEN_VEXT_LD_ELEM(ldb_b, int8_t, int8_t, H1, ldsb)
+GEN_VEXT_LD_ELEM(ldb_h, int8_t, int16_t, H2, ldsb)
+GEN_VEXT_LD_ELEM(ldb_w, int8_t, int32_t, H4, ldsb)
+GEN_VEXT_LD_ELEM(ldb_d, int8_t, int64_t, H8, ldsb)
+GEN_VEXT_LD_ELEM(ldh_h, int16_t, int16_t, H2, ldsw)
+GEN_VEXT_LD_ELEM(ldh_w, int16_t, int32_t, H4, ldsw)
+GEN_VEXT_LD_ELEM(ldh_d, int16_t, int64_t, H8, ldsw)
+GEN_VEXT_LD_ELEM(ldw_w, int32_t, int32_t, H4, ldl)
+GEN_VEXT_LD_ELEM(ldw_d, int32_t, int64_t, H8, ldl)
+GEN_VEXT_LD_ELEM(lde_b, int8_t, int8_t, H1, ldsb)
+GEN_VEXT_LD_ELEM(lde_h, int16_t, int16_t, H2, ldsw)
+GEN_VEXT_LD_ELEM(lde_w, int32_t, int32_t, H4, ldl)
+GEN_VEXT_LD_ELEM(lde_d, int64_t, int64_t, H8, ldq)
+GEN_VEXT_LD_ELEM(ldbu_b, uint8_t, uint8_t, H1, ldub)
+GEN_VEXT_LD_ELEM(ldbu_h, uint8_t, uint16_t, H2, ldub)
+GEN_VEXT_LD_ELEM(ldbu_w, uint8_t, uint32_t, H4, ldub)
+GEN_VEXT_LD_ELEM(ldbu_d, uint8_t, uint64_t, H8, ldub)
+GEN_VEXT_LD_ELEM(ldhu_h, uint16_t, uint16_t, H2, lduw)
+GEN_VEXT_LD_ELEM(ldhu_w, uint16_t, uint32_t, H4, lduw)
+GEN_VEXT_LD_ELEM(ldhu_d, uint16_t, uint64_t, H8, lduw)
+GEN_VEXT_LD_ELEM(ldwu_w, uint32_t, uint32_t, H4, ldl)
+GEN_VEXT_LD_ELEM(ldwu_d, uint32_t, uint64_t, H8, ldl)
+
+#define GEN_VEXT_ST_ELEM(NAME, ETYPE, H, STSUF) \
+static void NAME(CPURISCVState *env, abi_ptr addr, \
+ uint32_t idx, void *vd, uintptr_t retaddr)\
+{ \
+ ETYPE data = *((ETYPE *)vd + H(idx)); \
+ cpu_##STSUF##_data_ra(env, addr, data, retaddr); \
+}
+
+GEN_VEXT_ST_ELEM(stb_b, int8_t, H1, stb)
+GEN_VEXT_ST_ELEM(stb_h, int16_t, H2, stb)
+GEN_VEXT_ST_ELEM(stb_w, int32_t, H4, stb)
+GEN_VEXT_ST_ELEM(stb_d, int64_t, H8, stb)
+GEN_VEXT_ST_ELEM(sth_h, int16_t, H2, stw)
+GEN_VEXT_ST_ELEM(sth_w, int32_t, H4, stw)
+GEN_VEXT_ST_ELEM(sth_d, int64_t, H8, stw)
+GEN_VEXT_ST_ELEM(stw_w, int32_t, H4, stl)
+GEN_VEXT_ST_ELEM(stw_d, int64_t, H8, stl)
+GEN_VEXT_ST_ELEM(ste_b, int8_t, H1, stb)
+GEN_VEXT_ST_ELEM(ste_h, int16_t, H2, stw)
+GEN_VEXT_ST_ELEM(ste_w, int32_t, H4, stl)
+GEN_VEXT_ST_ELEM(ste_d, int64_t, H8, stq)
+
+/*
+ *** stride: access vector element from strided memory
+ */
+static void
+vext_ldst_stride(void *vd, void *v0, target_ulong base,
+ target_ulong stride, CPURISCVState *env,
+ uint32_t desc, uint32_t vm,
+ vext_ldst_elem_fn *ldst_elem, clear_fn *clear_elem,
+ uint32_t esz, uint32_t msz, uintptr_t ra,
+ MMUAccessType access_type)
+{
+ uint32_t i, k;
+ uint32_t nf = vext_nf(desc);
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+
+ /* probe every access*/
+ for (i = 0; i < env->vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ probe_pages(env, base + stride * i, nf * msz, ra, access_type);
+ }
+ /* do real access */
+ for (i = 0; i < env->vl; i++) {
+ k = 0;
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ while (k < nf) {
+ target_ulong addr = base + stride * i + k * msz;
+ ldst_elem(env, addr, i + k * vlmax, vd, ra);
+ k++;
+ }
+ }
+ /* clear tail elements */
+ if (clear_elem) {
+ for (k = 0; k < nf; k++) {
+ clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz);
+ }
+ }
+}
+
+#define GEN_VEXT_LD_STRIDE(NAME, MTYPE, ETYPE, LOAD_FN, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void * v0, target_ulong base, \
+ target_ulong stride, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t vm = vext_vm(desc); \
+ vext_ldst_stride(vd, v0, base, stride, env, desc, vm, LOAD_FN, \
+ CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \
+ GETPC(), MMU_DATA_LOAD); \
+}
+
+GEN_VEXT_LD_STRIDE(vlsb_v_b, int8_t, int8_t, ldb_b, clearb)
+GEN_VEXT_LD_STRIDE(vlsb_v_h, int8_t, int16_t, ldb_h, clearh)
+GEN_VEXT_LD_STRIDE(vlsb_v_w, int8_t, int32_t, ldb_w, clearl)
+GEN_VEXT_LD_STRIDE(vlsb_v_d, int8_t, int64_t, ldb_d, clearq)
+GEN_VEXT_LD_STRIDE(vlsh_v_h, int16_t, int16_t, ldh_h, clearh)
+GEN_VEXT_LD_STRIDE(vlsh_v_w, int16_t, int32_t, ldh_w, clearl)
+GEN_VEXT_LD_STRIDE(vlsh_v_d, int16_t, int64_t, ldh_d, clearq)
+GEN_VEXT_LD_STRIDE(vlsw_v_w, int32_t, int32_t, ldw_w, clearl)
+GEN_VEXT_LD_STRIDE(vlsw_v_d, int32_t, int64_t, ldw_d, clearq)
+GEN_VEXT_LD_STRIDE(vlse_v_b, int8_t, int8_t, lde_b, clearb)
+GEN_VEXT_LD_STRIDE(vlse_v_h, int16_t, int16_t, lde_h, clearh)
+GEN_VEXT_LD_STRIDE(vlse_v_w, int32_t, int32_t, lde_w, clearl)
+GEN_VEXT_LD_STRIDE(vlse_v_d, int64_t, int64_t, lde_d, clearq)
+GEN_VEXT_LD_STRIDE(vlsbu_v_b, uint8_t, uint8_t, ldbu_b, clearb)
+GEN_VEXT_LD_STRIDE(vlsbu_v_h, uint8_t, uint16_t, ldbu_h, clearh)
+GEN_VEXT_LD_STRIDE(vlsbu_v_w, uint8_t, uint32_t, ldbu_w, clearl)
+GEN_VEXT_LD_STRIDE(vlsbu_v_d, uint8_t, uint64_t, ldbu_d, clearq)
+GEN_VEXT_LD_STRIDE(vlshu_v_h, uint16_t, uint16_t, ldhu_h, clearh)
+GEN_VEXT_LD_STRIDE(vlshu_v_w, uint16_t, uint32_t, ldhu_w, clearl)
+GEN_VEXT_LD_STRIDE(vlshu_v_d, uint16_t, uint64_t, ldhu_d, clearq)
+GEN_VEXT_LD_STRIDE(vlswu_v_w, uint32_t, uint32_t, ldwu_w, clearl)
+GEN_VEXT_LD_STRIDE(vlswu_v_d, uint32_t, uint64_t, ldwu_d, clearq)
+
+#define GEN_VEXT_ST_STRIDE(NAME, MTYPE, ETYPE, STORE_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong base, \
+ target_ulong stride, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t vm = vext_vm(desc); \
+ vext_ldst_stride(vd, v0, base, stride, env, desc, vm, STORE_FN, \
+ NULL, sizeof(ETYPE), sizeof(MTYPE), \
+ GETPC(), MMU_DATA_STORE); \
+}
+
+GEN_VEXT_ST_STRIDE(vssb_v_b, int8_t, int8_t, stb_b)
+GEN_VEXT_ST_STRIDE(vssb_v_h, int8_t, int16_t, stb_h)
+GEN_VEXT_ST_STRIDE(vssb_v_w, int8_t, int32_t, stb_w)
+GEN_VEXT_ST_STRIDE(vssb_v_d, int8_t, int64_t, stb_d)
+GEN_VEXT_ST_STRIDE(vssh_v_h, int16_t, int16_t, sth_h)
+GEN_VEXT_ST_STRIDE(vssh_v_w, int16_t, int32_t, sth_w)
+GEN_VEXT_ST_STRIDE(vssh_v_d, int16_t, int64_t, sth_d)
+GEN_VEXT_ST_STRIDE(vssw_v_w, int32_t, int32_t, stw_w)
+GEN_VEXT_ST_STRIDE(vssw_v_d, int32_t, int64_t, stw_d)
+GEN_VEXT_ST_STRIDE(vsse_v_b, int8_t, int8_t, ste_b)
+GEN_VEXT_ST_STRIDE(vsse_v_h, int16_t, int16_t, ste_h)
+GEN_VEXT_ST_STRIDE(vsse_v_w, int32_t, int32_t, ste_w)
+GEN_VEXT_ST_STRIDE(vsse_v_d, int64_t, int64_t, ste_d)
+
+/*
+ *** unit-stride: access elements stored contiguously in memory
+ */
+
+/* unmasked unit-stride load and store operation*/
+static void
+vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
+ vext_ldst_elem_fn *ldst_elem, clear_fn *clear_elem,
+ uint32_t esz, uint32_t msz, uintptr_t ra,
+ MMUAccessType access_type)
+{
+ uint32_t i, k;
+ uint32_t nf = vext_nf(desc);
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+
+ /* probe every access */
+ probe_pages(env, base, env->vl * nf * msz, ra, access_type);
+ /* load bytes from guest memory */
+ for (i = 0; i < env->vl; i++) {
+ k = 0;
+ while (k < nf) {
+ target_ulong addr = base + (i * nf + k) * msz;
+ ldst_elem(env, addr, i + k * vlmax, vd, ra);
+ k++;
+ }
+ }
+ /* clear tail elements */
+ if (clear_elem) {
+ for (k = 0; k < nf; k++) {
+ clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz);
+ }
+ }
+}
+
+/*
+ * masked unit-stride load and store operation will be a special case of stride,
+ * stride = NF * sizeof (MTYPE)
+ */
+
+#define GEN_VEXT_LD_US(NAME, MTYPE, ETYPE, LOAD_FN, CLEAR_FN) \
+void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t stride = vext_nf(desc) * sizeof(MTYPE); \
+ vext_ldst_stride(vd, v0, base, stride, env, desc, false, LOAD_FN, \
+ CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \
+ GETPC(), MMU_DATA_LOAD); \
+} \
+ \
+void HELPER(NAME)(void *vd, void *v0, target_ulong base, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_ldst_us(vd, base, env, desc, LOAD_FN, CLEAR_FN, \
+ sizeof(ETYPE), sizeof(MTYPE), GETPC(), MMU_DATA_LOAD); \
+}
+
+GEN_VEXT_LD_US(vlb_v_b, int8_t, int8_t, ldb_b, clearb)
+GEN_VEXT_LD_US(vlb_v_h, int8_t, int16_t, ldb_h, clearh)
+GEN_VEXT_LD_US(vlb_v_w, int8_t, int32_t, ldb_w, clearl)
+GEN_VEXT_LD_US(vlb_v_d, int8_t, int64_t, ldb_d, clearq)
+GEN_VEXT_LD_US(vlh_v_h, int16_t, int16_t, ldh_h, clearh)
+GEN_VEXT_LD_US(vlh_v_w, int16_t, int32_t, ldh_w, clearl)
+GEN_VEXT_LD_US(vlh_v_d, int16_t, int64_t, ldh_d, clearq)
+GEN_VEXT_LD_US(vlw_v_w, int32_t, int32_t, ldw_w, clearl)
+GEN_VEXT_LD_US(vlw_v_d, int32_t, int64_t, ldw_d, clearq)
+GEN_VEXT_LD_US(vle_v_b, int8_t, int8_t, lde_b, clearb)
+GEN_VEXT_LD_US(vle_v_h, int16_t, int16_t, lde_h, clearh)
+GEN_VEXT_LD_US(vle_v_w, int32_t, int32_t, lde_w, clearl)
+GEN_VEXT_LD_US(vle_v_d, int64_t, int64_t, lde_d, clearq)
+GEN_VEXT_LD_US(vlbu_v_b, uint8_t, uint8_t, ldbu_b, clearb)
+GEN_VEXT_LD_US(vlbu_v_h, uint8_t, uint16_t, ldbu_h, clearh)
+GEN_VEXT_LD_US(vlbu_v_w, uint8_t, uint32_t, ldbu_w, clearl)
+GEN_VEXT_LD_US(vlbu_v_d, uint8_t, uint64_t, ldbu_d, clearq)
+GEN_VEXT_LD_US(vlhu_v_h, uint16_t, uint16_t, ldhu_h, clearh)
+GEN_VEXT_LD_US(vlhu_v_w, uint16_t, uint32_t, ldhu_w, clearl)
+GEN_VEXT_LD_US(vlhu_v_d, uint16_t, uint64_t, ldhu_d, clearq)
+GEN_VEXT_LD_US(vlwu_v_w, uint32_t, uint32_t, ldwu_w, clearl)
+GEN_VEXT_LD_US(vlwu_v_d, uint32_t, uint64_t, ldwu_d, clearq)
+
+#define GEN_VEXT_ST_US(NAME, MTYPE, ETYPE, STORE_FN) \
+void HELPER(NAME##_mask)(void *vd, void *v0, target_ulong base, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t stride = vext_nf(desc) * sizeof(MTYPE); \
+ vext_ldst_stride(vd, v0, base, stride, env, desc, false, STORE_FN, \
+ NULL, sizeof(ETYPE), sizeof(MTYPE), \
+ GETPC(), MMU_DATA_STORE); \
+} \
+ \
+void HELPER(NAME)(void *vd, void *v0, target_ulong base, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_ldst_us(vd, base, env, desc, STORE_FN, NULL, \
+ sizeof(ETYPE), sizeof(MTYPE), GETPC(), MMU_DATA_STORE);\
+}
+
+GEN_VEXT_ST_US(vsb_v_b, int8_t, int8_t , stb_b)
+GEN_VEXT_ST_US(vsb_v_h, int8_t, int16_t, stb_h)
+GEN_VEXT_ST_US(vsb_v_w, int8_t, int32_t, stb_w)
+GEN_VEXT_ST_US(vsb_v_d, int8_t, int64_t, stb_d)
+GEN_VEXT_ST_US(vsh_v_h, int16_t, int16_t, sth_h)
+GEN_VEXT_ST_US(vsh_v_w, int16_t, int32_t, sth_w)
+GEN_VEXT_ST_US(vsh_v_d, int16_t, int64_t, sth_d)
+GEN_VEXT_ST_US(vsw_v_w, int32_t, int32_t, stw_w)
+GEN_VEXT_ST_US(vsw_v_d, int32_t, int64_t, stw_d)
+GEN_VEXT_ST_US(vse_v_b, int8_t, int8_t , ste_b)
+GEN_VEXT_ST_US(vse_v_h, int16_t, int16_t, ste_h)
+GEN_VEXT_ST_US(vse_v_w, int32_t, int32_t, ste_w)
+GEN_VEXT_ST_US(vse_v_d, int64_t, int64_t, ste_d)
+
+/*
+ *** index: access vector element from indexed memory
+ */
+typedef target_ulong vext_get_index_addr(target_ulong base,
+ uint32_t idx, void *vs2);
+
+#define GEN_VEXT_GET_INDEX_ADDR(NAME, ETYPE, H) \
+static target_ulong NAME(target_ulong base, \
+ uint32_t idx, void *vs2) \
+{ \
+ return (base + *((ETYPE *)vs2 + H(idx))); \
+}
+
+GEN_VEXT_GET_INDEX_ADDR(idx_b, int8_t, H1)
+GEN_VEXT_GET_INDEX_ADDR(idx_h, int16_t, H2)
+GEN_VEXT_GET_INDEX_ADDR(idx_w, int32_t, H4)
+GEN_VEXT_GET_INDEX_ADDR(idx_d, int64_t, H8)
+
+static inline void
+vext_ldst_index(void *vd, void *v0, target_ulong base,
+ void *vs2, CPURISCVState *env, uint32_t desc,
+ vext_get_index_addr get_index_addr,
+ vext_ldst_elem_fn *ldst_elem,
+ clear_fn *clear_elem,
+ uint32_t esz, uint32_t msz, uintptr_t ra,
+ MMUAccessType access_type)
+{
+ uint32_t i, k;
+ uint32_t nf = vext_nf(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+
+ /* probe every access*/
+ for (i = 0; i < env->vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ probe_pages(env, get_index_addr(base, i, vs2), nf * msz, ra,
+ access_type);
+ }
+ /* load bytes from guest memory */
+ for (i = 0; i < env->vl; i++) {
+ k = 0;
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ while (k < nf) {
+ abi_ptr addr = get_index_addr(base, i, vs2) + k * msz;
+ ldst_elem(env, addr, i + k * vlmax, vd, ra);
+ k++;
+ }
+ }
+ /* clear tail elements */
+ if (clear_elem) {
+ for (k = 0; k < nf; k++) {
+ clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz);
+ }
+ }
+}
+
+#define GEN_VEXT_LD_INDEX(NAME, MTYPE, ETYPE, INDEX_FN, LOAD_FN, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong base, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \
+ LOAD_FN, CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \
+ GETPC(), MMU_DATA_LOAD); \
+}
+
+GEN_VEXT_LD_INDEX(vlxb_v_b, int8_t, int8_t, idx_b, ldb_b, clearb)
+GEN_VEXT_LD_INDEX(vlxb_v_h, int8_t, int16_t, idx_h, ldb_h, clearh)
+GEN_VEXT_LD_INDEX(vlxb_v_w, int8_t, int32_t, idx_w, ldb_w, clearl)
+GEN_VEXT_LD_INDEX(vlxb_v_d, int8_t, int64_t, idx_d, ldb_d, clearq)
+GEN_VEXT_LD_INDEX(vlxh_v_h, int16_t, int16_t, idx_h, ldh_h, clearh)
+GEN_VEXT_LD_INDEX(vlxh_v_w, int16_t, int32_t, idx_w, ldh_w, clearl)
+GEN_VEXT_LD_INDEX(vlxh_v_d, int16_t, int64_t, idx_d, ldh_d, clearq)
+GEN_VEXT_LD_INDEX(vlxw_v_w, int32_t, int32_t, idx_w, ldw_w, clearl)
+GEN_VEXT_LD_INDEX(vlxw_v_d, int32_t, int64_t, idx_d, ldw_d, clearq)
+GEN_VEXT_LD_INDEX(vlxe_v_b, int8_t, int8_t, idx_b, lde_b, clearb)
+GEN_VEXT_LD_INDEX(vlxe_v_h, int16_t, int16_t, idx_h, lde_h, clearh)
+GEN_VEXT_LD_INDEX(vlxe_v_w, int32_t, int32_t, idx_w, lde_w, clearl)
+GEN_VEXT_LD_INDEX(vlxe_v_d, int64_t, int64_t, idx_d, lde_d, clearq)
+GEN_VEXT_LD_INDEX(vlxbu_v_b, uint8_t, uint8_t, idx_b, ldbu_b, clearb)
+GEN_VEXT_LD_INDEX(vlxbu_v_h, uint8_t, uint16_t, idx_h, ldbu_h, clearh)
+GEN_VEXT_LD_INDEX(vlxbu_v_w, uint8_t, uint32_t, idx_w, ldbu_w, clearl)
+GEN_VEXT_LD_INDEX(vlxbu_v_d, uint8_t, uint64_t, idx_d, ldbu_d, clearq)
+GEN_VEXT_LD_INDEX(vlxhu_v_h, uint16_t, uint16_t, idx_h, ldhu_h, clearh)
+GEN_VEXT_LD_INDEX(vlxhu_v_w, uint16_t, uint32_t, idx_w, ldhu_w, clearl)
+GEN_VEXT_LD_INDEX(vlxhu_v_d, uint16_t, uint64_t, idx_d, ldhu_d, clearq)
+GEN_VEXT_LD_INDEX(vlxwu_v_w, uint32_t, uint32_t, idx_w, ldwu_w, clearl)
+GEN_VEXT_LD_INDEX(vlxwu_v_d, uint32_t, uint64_t, idx_d, ldwu_d, clearq)
+
+#define GEN_VEXT_ST_INDEX(NAME, MTYPE, ETYPE, INDEX_FN, STORE_FN)\
+void HELPER(NAME)(void *vd, void *v0, target_ulong base, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_ldst_index(vd, v0, base, vs2, env, desc, INDEX_FN, \
+ STORE_FN, NULL, sizeof(ETYPE), sizeof(MTYPE),\
+ GETPC(), MMU_DATA_STORE); \
+}
+
+GEN_VEXT_ST_INDEX(vsxb_v_b, int8_t, int8_t, idx_b, stb_b)
+GEN_VEXT_ST_INDEX(vsxb_v_h, int8_t, int16_t, idx_h, stb_h)
+GEN_VEXT_ST_INDEX(vsxb_v_w, int8_t, int32_t, idx_w, stb_w)
+GEN_VEXT_ST_INDEX(vsxb_v_d, int8_t, int64_t, idx_d, stb_d)
+GEN_VEXT_ST_INDEX(vsxh_v_h, int16_t, int16_t, idx_h, sth_h)
+GEN_VEXT_ST_INDEX(vsxh_v_w, int16_t, int32_t, idx_w, sth_w)
+GEN_VEXT_ST_INDEX(vsxh_v_d, int16_t, int64_t, idx_d, sth_d)
+GEN_VEXT_ST_INDEX(vsxw_v_w, int32_t, int32_t, idx_w, stw_w)
+GEN_VEXT_ST_INDEX(vsxw_v_d, int32_t, int64_t, idx_d, stw_d)
+GEN_VEXT_ST_INDEX(vsxe_v_b, int8_t, int8_t, idx_b, ste_b)
+GEN_VEXT_ST_INDEX(vsxe_v_h, int16_t, int16_t, idx_h, ste_h)
+GEN_VEXT_ST_INDEX(vsxe_v_w, int32_t, int32_t, idx_w, ste_w)
+GEN_VEXT_ST_INDEX(vsxe_v_d, int64_t, int64_t, idx_d, ste_d)
+
+/*
+ *** unit-stride fault-only-fisrt load instructions
+ */
+static inline void
+vext_ldff(void *vd, void *v0, target_ulong base,
+ CPURISCVState *env, uint32_t desc,
+ vext_ldst_elem_fn *ldst_elem,
+ clear_fn *clear_elem,
+ uint32_t esz, uint32_t msz, uintptr_t ra)
+{
+ void *host;
+ uint32_t i, k, vl = 0;
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t nf = vext_nf(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+ target_ulong addr, offset, remain;
+
+ /* probe every access*/
+ for (i = 0; i < env->vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ addr = base + nf * i * msz;
+ if (i == 0) {
+ probe_pages(env, addr, nf * msz, ra, MMU_DATA_LOAD);
+ } else {
+ /* if it triggers an exception, no need to check watchpoint */
+ remain = nf * msz;
+ while (remain > 0) {
+ offset = -(addr | TARGET_PAGE_MASK);
+ host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD,
+ cpu_mmu_index(env, false));
+ if (host) {
+#ifdef CONFIG_USER_ONLY
+ if (page_check_range(addr, nf * msz, PAGE_READ) < 0) {
+ vl = i;
+ goto ProbeSuccess;
+ }
+#else
+ probe_pages(env, addr, nf * msz, ra, MMU_DATA_LOAD);
+#endif
+ } else {
+ vl = i;
+ goto ProbeSuccess;
+ }
+ if (remain <= offset) {
+ break;
+ }
+ remain -= offset;
+ addr += offset;
+ }
+ }
+ }
+ProbeSuccess:
+ /* load bytes from guest memory */
+ if (vl != 0) {
+ env->vl = vl;
+ }
+ for (i = 0; i < env->vl; i++) {
+ k = 0;
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ while (k < nf) {
+ target_ulong addr = base + (i * nf + k) * msz;
+ ldst_elem(env, addr, i + k * vlmax, vd, ra);
+ k++;
+ }
+ }
+ /* clear tail elements */
+ if (vl != 0) {
+ return;
+ }
+ for (k = 0; k < nf; k++) {
+ clear_elem(vd, env->vl + k * vlmax, env->vl * esz, vlmax * esz);
+ }
+}
+
+#define GEN_VEXT_LDFF(NAME, MTYPE, ETYPE, LOAD_FN, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong base, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_ldff(vd, v0, base, env, desc, LOAD_FN, CLEAR_FN, \
+ sizeof(ETYPE), sizeof(MTYPE), GETPC()); \
+}
+
+GEN_VEXT_LDFF(vlbff_v_b, int8_t, int8_t, ldb_b, clearb)
+GEN_VEXT_LDFF(vlbff_v_h, int8_t, int16_t, ldb_h, clearh)
+GEN_VEXT_LDFF(vlbff_v_w, int8_t, int32_t, ldb_w, clearl)
+GEN_VEXT_LDFF(vlbff_v_d, int8_t, int64_t, ldb_d, clearq)
+GEN_VEXT_LDFF(vlhff_v_h, int16_t, int16_t, ldh_h, clearh)
+GEN_VEXT_LDFF(vlhff_v_w, int16_t, int32_t, ldh_w, clearl)
+GEN_VEXT_LDFF(vlhff_v_d, int16_t, int64_t, ldh_d, clearq)
+GEN_VEXT_LDFF(vlwff_v_w, int32_t, int32_t, ldw_w, clearl)
+GEN_VEXT_LDFF(vlwff_v_d, int32_t, int64_t, ldw_d, clearq)
+GEN_VEXT_LDFF(vleff_v_b, int8_t, int8_t, lde_b, clearb)
+GEN_VEXT_LDFF(vleff_v_h, int16_t, int16_t, lde_h, clearh)
+GEN_VEXT_LDFF(vleff_v_w, int32_t, int32_t, lde_w, clearl)
+GEN_VEXT_LDFF(vleff_v_d, int64_t, int64_t, lde_d, clearq)
+GEN_VEXT_LDFF(vlbuff_v_b, uint8_t, uint8_t, ldbu_b, clearb)
+GEN_VEXT_LDFF(vlbuff_v_h, uint8_t, uint16_t, ldbu_h, clearh)
+GEN_VEXT_LDFF(vlbuff_v_w, uint8_t, uint32_t, ldbu_w, clearl)
+GEN_VEXT_LDFF(vlbuff_v_d, uint8_t, uint64_t, ldbu_d, clearq)
+GEN_VEXT_LDFF(vlhuff_v_h, uint16_t, uint16_t, ldhu_h, clearh)
+GEN_VEXT_LDFF(vlhuff_v_w, uint16_t, uint32_t, ldhu_w, clearl)
+GEN_VEXT_LDFF(vlhuff_v_d, uint16_t, uint64_t, ldhu_d, clearq)
+GEN_VEXT_LDFF(vlwuff_v_w, uint32_t, uint32_t, ldwu_w, clearl)
+GEN_VEXT_LDFF(vlwuff_v_d, uint32_t, uint64_t, ldwu_d, clearq)
+
+/*
+ *** Vector AMO Operations (Zvamo)
+ */
+typedef void vext_amo_noatomic_fn(void *vs3, target_ulong addr,
+ uint32_t wd, uint32_t idx, CPURISCVState *env,
+ uintptr_t retaddr);
+
+/* no atomic opreation for vector atomic insructions */
+#define DO_SWAP(N, M) (M)
+#define DO_AND(N, M) (N & M)
+#define DO_XOR(N, M) (N ^ M)
+#define DO_OR(N, M) (N | M)
+#define DO_ADD(N, M) (N + M)
+
+#define GEN_VEXT_AMO_NOATOMIC_OP(NAME, ESZ, MSZ, H, DO_OP, SUF) \
+static void \
+vext_##NAME##_noatomic_op(void *vs3, target_ulong addr, \
+ uint32_t wd, uint32_t idx, \
+ CPURISCVState *env, uintptr_t retaddr)\
+{ \
+ typedef int##ESZ##_t ETYPE; \
+ typedef int##MSZ##_t MTYPE; \
+ typedef uint##MSZ##_t UMTYPE __attribute__((unused)); \
+ ETYPE *pe3 = (ETYPE *)vs3 + H(idx); \
+ MTYPE a = cpu_ld##SUF##_data(env, addr), b = *pe3; \
+ \
+ cpu_st##SUF##_data(env, addr, DO_OP(a, b)); \
+ if (wd) { \
+ *pe3 = a; \
+ } \
+}
+
+/* Signed min/max */
+#define DO_MAX(N, M) ((N) >= (M) ? (N) : (M))
+#define DO_MIN(N, M) ((N) >= (M) ? (M) : (N))
+
+/* Unsigned min/max */
+#define DO_MAXU(N, M) DO_MAX((UMTYPE)N, (UMTYPE)M)
+#define DO_MINU(N, M) DO_MIN((UMTYPE)N, (UMTYPE)M)
+
+GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_w, 32, 32, H4, DO_SWAP, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_w, 32, 32, H4, DO_ADD, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoxorw_v_w, 32, 32, H4, DO_XOR, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoandw_v_w, 32, 32, H4, DO_AND, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoorw_v_w, 32, 32, H4, DO_OR, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_w, 32, 32, H4, DO_MIN, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_w, 32, 32, H4, DO_MAX, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_w, 32, 32, H4, DO_MINU, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_w, 32, 32, H4, DO_MAXU, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_d, 64, 32, H8, DO_SWAP, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoswapd_v_d, 64, 64, H8, DO_SWAP, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_d, 64, 32, H8, DO_ADD, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoaddd_v_d, 64, 64, H8, DO_ADD, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoxorw_v_d, 64, 32, H8, DO_XOR, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoxord_v_d, 64, 64, H8, DO_XOR, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoandw_v_d, 64, 32, H8, DO_AND, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoandd_v_d, 64, 64, H8, DO_AND, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoorw_v_d, 64, 32, H8, DO_OR, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamoord_v_d, 64, 64, H8, DO_OR, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_d, 64, 32, H8, DO_MIN, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomind_v_d, 64, 64, H8, DO_MIN, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_d, 64, 32, H8, DO_MAX, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomaxd_v_d, 64, 64, H8, DO_MAX, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_d, 64, 32, H8, DO_MINU, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamominud_v_d, 64, 64, H8, DO_MINU, q)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_d, 64, 32, H8, DO_MAXU, l)
+GEN_VEXT_AMO_NOATOMIC_OP(vamomaxud_v_d, 64, 64, H8, DO_MAXU, q)
+
+static inline void
+vext_amo_noatomic(void *vs3, void *v0, target_ulong base,
+ void *vs2, CPURISCVState *env, uint32_t desc,
+ vext_get_index_addr get_index_addr,
+ vext_amo_noatomic_fn *noatomic_op,
+ clear_fn *clear_elem,
+ uint32_t esz, uint32_t msz, uintptr_t ra)
+{
+ uint32_t i;
+ target_long addr;
+ uint32_t wd = vext_wd(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+
+ for (i = 0; i < env->vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ probe_pages(env, get_index_addr(base, i, vs2), msz, ra, MMU_DATA_LOAD);
+ probe_pages(env, get_index_addr(base, i, vs2), msz, ra, MMU_DATA_STORE);
+ }
+ for (i = 0; i < env->vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ addr = get_index_addr(base, i, vs2);
+ noatomic_op(vs3, addr, wd, i, env, ra);
+ }
+ clear_elem(vs3, env->vl, env->vl * esz, vlmax * esz);
+}
+
+#define GEN_VEXT_AMO(NAME, MTYPE, ETYPE, INDEX_FN, CLEAR_FN) \
+void HELPER(NAME)(void *vs3, void *v0, target_ulong base, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_amo_noatomic(vs3, v0, base, vs2, env, desc, \
+ INDEX_FN, vext_##NAME##_noatomic_op, \
+ CLEAR_FN, sizeof(ETYPE), sizeof(MTYPE), \
+ GETPC()); \
+}
+
+GEN_VEXT_AMO(vamoswapw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoswapd_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoaddw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoaddd_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoxorw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoxord_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoandw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoandd_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoorw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoord_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamominw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamomind_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamomaxw_v_d, int32_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamomaxd_v_d, int64_t, int64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamominuw_v_d, uint32_t, uint64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamominud_v_d, uint64_t, uint64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamomaxuw_v_d, uint32_t, uint64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamomaxud_v_d, uint64_t, uint64_t, idx_d, clearq)
+GEN_VEXT_AMO(vamoswapw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamoaddw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamoxorw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamoandw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamoorw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamominw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamomaxw_v_w, int32_t, int32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamominuw_v_w, uint32_t, uint32_t, idx_w, clearl)
+GEN_VEXT_AMO(vamomaxuw_v_w, uint32_t, uint32_t, idx_w, clearl)
+
+/*
+ *** Vector Integer Arithmetic Instructions
+ */
+
+/* expand macro args before macro */
+#define RVVCALL(macro, ...) macro(__VA_ARGS__)
+
+/* (TD, T1, T2, TX1, TX2) */
+#define OP_SSS_B int8_t, int8_t, int8_t, int8_t, int8_t
+#define OP_SSS_H int16_t, int16_t, int16_t, int16_t, int16_t
+#define OP_SSS_W int32_t, int32_t, int32_t, int32_t, int32_t
+#define OP_SSS_D int64_t, int64_t, int64_t, int64_t, int64_t
+#define OP_UUU_B uint8_t, uint8_t, uint8_t, uint8_t, uint8_t
+#define OP_UUU_H uint16_t, uint16_t, uint16_t, uint16_t, uint16_t
+#define OP_UUU_W uint32_t, uint32_t, uint32_t, uint32_t, uint32_t
+#define OP_UUU_D uint64_t, uint64_t, uint64_t, uint64_t, uint64_t
+#define OP_SUS_B int8_t, uint8_t, int8_t, uint8_t, int8_t
+#define OP_SUS_H int16_t, uint16_t, int16_t, uint16_t, int16_t
+#define OP_SUS_W int32_t, uint32_t, int32_t, uint32_t, int32_t
+#define OP_SUS_D int64_t, uint64_t, int64_t, uint64_t, int64_t
+#define WOP_UUU_B uint16_t, uint8_t, uint8_t, uint16_t, uint16_t
+#define WOP_UUU_H uint32_t, uint16_t, uint16_t, uint32_t, uint32_t
+#define WOP_UUU_W uint64_t, uint32_t, uint32_t, uint64_t, uint64_t
+#define WOP_SSS_B int16_t, int8_t, int8_t, int16_t, int16_t
+#define WOP_SSS_H int32_t, int16_t, int16_t, int32_t, int32_t
+#define WOP_SSS_W int64_t, int32_t, int32_t, int64_t, int64_t
+#define WOP_SUS_B int16_t, uint8_t, int8_t, uint16_t, int16_t
+#define WOP_SUS_H int32_t, uint16_t, int16_t, uint32_t, int32_t
+#define WOP_SUS_W int64_t, uint32_t, int32_t, uint64_t, int64_t
+#define WOP_SSU_B int16_t, int8_t, uint8_t, int16_t, uint16_t
+#define WOP_SSU_H int32_t, int16_t, uint16_t, int32_t, uint32_t
+#define WOP_SSU_W int64_t, int32_t, uint32_t, int64_t, uint64_t
+#define NOP_SSS_B int8_t, int8_t, int16_t, int8_t, int16_t
+#define NOP_SSS_H int16_t, int16_t, int32_t, int16_t, int32_t
+#define NOP_SSS_W int32_t, int32_t, int64_t, int32_t, int64_t
+#define NOP_UUU_B uint8_t, uint8_t, uint16_t, uint8_t, uint16_t
+#define NOP_UUU_H uint16_t, uint16_t, uint32_t, uint16_t, uint32_t
+#define NOP_UUU_W uint32_t, uint32_t, uint64_t, uint32_t, uint64_t
+
+/* operation of two vector elements */
+typedef void opivv2_fn(void *vd, void *vs1, void *vs2, int i);
+
+#define OPIVV2(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
+static void do_##NAME(void *vd, void *vs1, void *vs2, int i) \
+{ \
+ TX1 s1 = *((T1 *)vs1 + HS1(i)); \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, s1); \
+}
+#define DO_SUB(N, M) (N - M)
+#define DO_RSUB(N, M) (M - N)
+
+RVVCALL(OPIVV2, vadd_vv_b, OP_SSS_B, H1, H1, H1, DO_ADD)
+RVVCALL(OPIVV2, vadd_vv_h, OP_SSS_H, H2, H2, H2, DO_ADD)
+RVVCALL(OPIVV2, vadd_vv_w, OP_SSS_W, H4, H4, H4, DO_ADD)
+RVVCALL(OPIVV2, vadd_vv_d, OP_SSS_D, H8, H8, H8, DO_ADD)
+RVVCALL(OPIVV2, vsub_vv_b, OP_SSS_B, H1, H1, H1, DO_SUB)
+RVVCALL(OPIVV2, vsub_vv_h, OP_SSS_H, H2, H2, H2, DO_SUB)
+RVVCALL(OPIVV2, vsub_vv_w, OP_SSS_W, H4, H4, H4, DO_SUB)
+RVVCALL(OPIVV2, vsub_vv_d, OP_SSS_D, H8, H8, H8, DO_SUB)
+
+static void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
+ CPURISCVState *env, uint32_t desc,
+ uint32_t esz, uint32_t dsz,
+ opivv2_fn *fn, clear_fn *clearfn)
+{
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ uint32_t i;
+
+ for (i = 0; i < vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ fn(vd, vs1, vs2, i);
+ }
+ clearfn(vd, vl, vl * dsz, vlmax * dsz);
+}
+
+/* generate the helpers for OPIVV */
+#define GEN_VEXT_VV(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, \
+ void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ do_vext_vv(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \
+ do_##NAME, CLEAR_FN); \
+}
+
+GEN_VEXT_VV(vadd_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vadd_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vsub_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vsub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vsub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vsub_vv_d, 8, 8, clearq)
+
+typedef void opivx2_fn(void *vd, target_long s1, void *vs2, int i);
+
+/*
+ * (T1)s1 gives the real operator type.
+ * (TX1)(T1)s1 expands the operator type of widen or narrow operations.
+ */
+#define OPIVX2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
+static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1); \
+}
+
+RVVCALL(OPIVX2, vadd_vx_b, OP_SSS_B, H1, H1, DO_ADD)
+RVVCALL(OPIVX2, vadd_vx_h, OP_SSS_H, H2, H2, DO_ADD)
+RVVCALL(OPIVX2, vadd_vx_w, OP_SSS_W, H4, H4, DO_ADD)
+RVVCALL(OPIVX2, vadd_vx_d, OP_SSS_D, H8, H8, DO_ADD)
+RVVCALL(OPIVX2, vsub_vx_b, OP_SSS_B, H1, H1, DO_SUB)
+RVVCALL(OPIVX2, vsub_vx_h, OP_SSS_H, H2, H2, DO_SUB)
+RVVCALL(OPIVX2, vsub_vx_w, OP_SSS_W, H4, H4, DO_SUB)
+RVVCALL(OPIVX2, vsub_vx_d, OP_SSS_D, H8, H8, DO_SUB)
+RVVCALL(OPIVX2, vrsub_vx_b, OP_SSS_B, H1, H1, DO_RSUB)
+RVVCALL(OPIVX2, vrsub_vx_h, OP_SSS_H, H2, H2, DO_RSUB)
+RVVCALL(OPIVX2, vrsub_vx_w, OP_SSS_W, H4, H4, DO_RSUB)
+RVVCALL(OPIVX2, vrsub_vx_d, OP_SSS_D, H8, H8, DO_RSUB)
+
+static void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
+ CPURISCVState *env, uint32_t desc,
+ uint32_t esz, uint32_t dsz,
+ opivx2_fn fn, clear_fn *clearfn)
+{
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ uint32_t i;
+
+ for (i = 0; i < vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ fn(vd, s1, vs2, i);
+ }
+ clearfn(vd, vl, vl * dsz, vlmax * dsz);
+}
+
+/* generate the helpers for OPIVX */
+#define GEN_VEXT_VX(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
+ void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ do_vext_vx(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \
+ do_##NAME, CLEAR_FN); \
+}
+
+GEN_VEXT_VX(vadd_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vadd_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vadd_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vadd_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vsub_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vsub_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vsub_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vsub_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vrsub_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vrsub_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vrsub_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vrsub_vx_d, 8, 8, clearq)
+
+void HELPER(vec_rsubs8)(void *d, void *a, uint64_t b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = (uint8_t)b - *(uint8_t *)(a + i);
+ }
+}
+
+void HELPER(vec_rsubs16)(void *d, void *a, uint64_t b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = (uint16_t)b - *(uint16_t *)(a + i);
+ }
+}
+
+void HELPER(vec_rsubs32)(void *d, void *a, uint64_t b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = (uint32_t)b - *(uint32_t *)(a + i);
+ }
+}
+
+void HELPER(vec_rsubs64)(void *d, void *a, uint64_t b, uint32_t desc)
+{
+ intptr_t oprsz = simd_oprsz(desc);
+ intptr_t i;
+
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = b - *(uint64_t *)(a + i);
+ }
+}
+
+/* Vector Widening Integer Add/Subtract */
+#define WOP_UUU_B uint16_t, uint8_t, uint8_t, uint16_t, uint16_t
+#define WOP_UUU_H uint32_t, uint16_t, uint16_t, uint32_t, uint32_t
+#define WOP_UUU_W uint64_t, uint32_t, uint32_t, uint64_t, uint64_t
+#define WOP_SSS_B int16_t, int8_t, int8_t, int16_t, int16_t
+#define WOP_SSS_H int32_t, int16_t, int16_t, int32_t, int32_t
+#define WOP_SSS_W int64_t, int32_t, int32_t, int64_t, int64_t
+#define WOP_WUUU_B uint16_t, uint8_t, uint16_t, uint16_t, uint16_t
+#define WOP_WUUU_H uint32_t, uint16_t, uint32_t, uint32_t, uint32_t
+#define WOP_WUUU_W uint64_t, uint32_t, uint64_t, uint64_t, uint64_t
+#define WOP_WSSS_B int16_t, int8_t, int16_t, int16_t, int16_t
+#define WOP_WSSS_H int32_t, int16_t, int32_t, int32_t, int32_t
+#define WOP_WSSS_W int64_t, int32_t, int64_t, int64_t, int64_t
+RVVCALL(OPIVV2, vwaddu_vv_b, WOP_UUU_B, H2, H1, H1, DO_ADD)
+RVVCALL(OPIVV2, vwaddu_vv_h, WOP_UUU_H, H4, H2, H2, DO_ADD)
+RVVCALL(OPIVV2, vwaddu_vv_w, WOP_UUU_W, H8, H4, H4, DO_ADD)
+RVVCALL(OPIVV2, vwsubu_vv_b, WOP_UUU_B, H2, H1, H1, DO_SUB)
+RVVCALL(OPIVV2, vwsubu_vv_h, WOP_UUU_H, H4, H2, H2, DO_SUB)
+RVVCALL(OPIVV2, vwsubu_vv_w, WOP_UUU_W, H8, H4, H4, DO_SUB)
+RVVCALL(OPIVV2, vwadd_vv_b, WOP_SSS_B, H2, H1, H1, DO_ADD)
+RVVCALL(OPIVV2, vwadd_vv_h, WOP_SSS_H, H4, H2, H2, DO_ADD)
+RVVCALL(OPIVV2, vwadd_vv_w, WOP_SSS_W, H8, H4, H4, DO_ADD)
+RVVCALL(OPIVV2, vwsub_vv_b, WOP_SSS_B, H2, H1, H1, DO_SUB)
+RVVCALL(OPIVV2, vwsub_vv_h, WOP_SSS_H, H4, H2, H2, DO_SUB)
+RVVCALL(OPIVV2, vwsub_vv_w, WOP_SSS_W, H8, H4, H4, DO_SUB)
+RVVCALL(OPIVV2, vwaddu_wv_b, WOP_WUUU_B, H2, H1, H1, DO_ADD)
+RVVCALL(OPIVV2, vwaddu_wv_h, WOP_WUUU_H, H4, H2, H2, DO_ADD)
+RVVCALL(OPIVV2, vwaddu_wv_w, WOP_WUUU_W, H8, H4, H4, DO_ADD)
+RVVCALL(OPIVV2, vwsubu_wv_b, WOP_WUUU_B, H2, H1, H1, DO_SUB)
+RVVCALL(OPIVV2, vwsubu_wv_h, WOP_WUUU_H, H4, H2, H2, DO_SUB)
+RVVCALL(OPIVV2, vwsubu_wv_w, WOP_WUUU_W, H8, H4, H4, DO_SUB)
+RVVCALL(OPIVV2, vwadd_wv_b, WOP_WSSS_B, H2, H1, H1, DO_ADD)
+RVVCALL(OPIVV2, vwadd_wv_h, WOP_WSSS_H, H4, H2, H2, DO_ADD)
+RVVCALL(OPIVV2, vwadd_wv_w, WOP_WSSS_W, H8, H4, H4, DO_ADD)
+RVVCALL(OPIVV2, vwsub_wv_b, WOP_WSSS_B, H2, H1, H1, DO_SUB)
+RVVCALL(OPIVV2, vwsub_wv_h, WOP_WSSS_H, H4, H2, H2, DO_SUB)
+RVVCALL(OPIVV2, vwsub_wv_w, WOP_WSSS_W, H8, H4, H4, DO_SUB)
+GEN_VEXT_VV(vwaddu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwaddu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwaddu_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwsubu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwsubu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwsubu_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwadd_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwadd_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwadd_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwsub_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwsub_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwsub_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwaddu_wv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwaddu_wv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwaddu_wv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwsubu_wv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwsubu_wv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwsubu_wv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwadd_wv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwadd_wv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwadd_wv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwsub_wv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwsub_wv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwsub_wv_w, 4, 8, clearq)
+
+RVVCALL(OPIVX2, vwaddu_vx_b, WOP_UUU_B, H2, H1, DO_ADD)
+RVVCALL(OPIVX2, vwaddu_vx_h, WOP_UUU_H, H4, H2, DO_ADD)
+RVVCALL(OPIVX2, vwaddu_vx_w, WOP_UUU_W, H8, H4, DO_ADD)
+RVVCALL(OPIVX2, vwsubu_vx_b, WOP_UUU_B, H2, H1, DO_SUB)
+RVVCALL(OPIVX2, vwsubu_vx_h, WOP_UUU_H, H4, H2, DO_SUB)
+RVVCALL(OPIVX2, vwsubu_vx_w, WOP_UUU_W, H8, H4, DO_SUB)
+RVVCALL(OPIVX2, vwadd_vx_b, WOP_SSS_B, H2, H1, DO_ADD)
+RVVCALL(OPIVX2, vwadd_vx_h, WOP_SSS_H, H4, H2, DO_ADD)
+RVVCALL(OPIVX2, vwadd_vx_w, WOP_SSS_W, H8, H4, DO_ADD)
+RVVCALL(OPIVX2, vwsub_vx_b, WOP_SSS_B, H2, H1, DO_SUB)
+RVVCALL(OPIVX2, vwsub_vx_h, WOP_SSS_H, H4, H2, DO_SUB)
+RVVCALL(OPIVX2, vwsub_vx_w, WOP_SSS_W, H8, H4, DO_SUB)
+RVVCALL(OPIVX2, vwaddu_wx_b, WOP_WUUU_B, H2, H1, DO_ADD)
+RVVCALL(OPIVX2, vwaddu_wx_h, WOP_WUUU_H, H4, H2, DO_ADD)
+RVVCALL(OPIVX2, vwaddu_wx_w, WOP_WUUU_W, H8, H4, DO_ADD)
+RVVCALL(OPIVX2, vwsubu_wx_b, WOP_WUUU_B, H2, H1, DO_SUB)
+RVVCALL(OPIVX2, vwsubu_wx_h, WOP_WUUU_H, H4, H2, DO_SUB)
+RVVCALL(OPIVX2, vwsubu_wx_w, WOP_WUUU_W, H8, H4, DO_SUB)
+RVVCALL(OPIVX2, vwadd_wx_b, WOP_WSSS_B, H2, H1, DO_ADD)
+RVVCALL(OPIVX2, vwadd_wx_h, WOP_WSSS_H, H4, H2, DO_ADD)
+RVVCALL(OPIVX2, vwadd_wx_w, WOP_WSSS_W, H8, H4, DO_ADD)
+RVVCALL(OPIVX2, vwsub_wx_b, WOP_WSSS_B, H2, H1, DO_SUB)
+RVVCALL(OPIVX2, vwsub_wx_h, WOP_WSSS_H, H4, H2, DO_SUB)
+RVVCALL(OPIVX2, vwsub_wx_w, WOP_WSSS_W, H8, H4, DO_SUB)
+GEN_VEXT_VX(vwaddu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwaddu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwaddu_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwsubu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwsubu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwsubu_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwadd_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwadd_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwadd_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwsub_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwsub_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwsub_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwaddu_wx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwaddu_wx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwaddu_wx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwsubu_wx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwsubu_wx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwsubu_wx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwadd_wx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwadd_wx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwadd_wx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwsub_wx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwsub_wx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwsub_wx_w, 4, 8, clearq)
+
+/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
+#define DO_VADC(N, M, C) (N + M + C)
+#define DO_VSBC(N, M, C) (N - M - C)
+
+#define GEN_VEXT_VADC_VVM(NAME, ETYPE, H, DO_OP, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ uint8_t carry = vext_elem_mask(v0, mlen, i); \
+ \
+ *((ETYPE *)vd + H(i)) = DO_OP(s2, s1, carry); \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_VADC_VVM(vadc_vvm_b, uint8_t, H1, DO_VADC, clearb)
+GEN_VEXT_VADC_VVM(vadc_vvm_h, uint16_t, H2, DO_VADC, clearh)
+GEN_VEXT_VADC_VVM(vadc_vvm_w, uint32_t, H4, DO_VADC, clearl)
+GEN_VEXT_VADC_VVM(vadc_vvm_d, uint64_t, H8, DO_VADC, clearq)
+
+GEN_VEXT_VADC_VVM(vsbc_vvm_b, uint8_t, H1, DO_VSBC, clearb)
+GEN_VEXT_VADC_VVM(vsbc_vvm_h, uint16_t, H2, DO_VSBC, clearh)
+GEN_VEXT_VADC_VVM(vsbc_vvm_w, uint32_t, H4, DO_VSBC, clearl)
+GEN_VEXT_VADC_VVM(vsbc_vvm_d, uint64_t, H8, DO_VSBC, clearq)
+
+#define GEN_VEXT_VADC_VXM(NAME, ETYPE, H, DO_OP, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ uint8_t carry = vext_elem_mask(v0, mlen, i); \
+ \
+ *((ETYPE *)vd + H(i)) = DO_OP(s2, (ETYPE)(target_long)s1, carry);\
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_VADC_VXM(vadc_vxm_b, uint8_t, H1, DO_VADC, clearb)
+GEN_VEXT_VADC_VXM(vadc_vxm_h, uint16_t, H2, DO_VADC, clearh)
+GEN_VEXT_VADC_VXM(vadc_vxm_w, uint32_t, H4, DO_VADC, clearl)
+GEN_VEXT_VADC_VXM(vadc_vxm_d, uint64_t, H8, DO_VADC, clearq)
+
+GEN_VEXT_VADC_VXM(vsbc_vxm_b, uint8_t, H1, DO_VSBC, clearb)
+GEN_VEXT_VADC_VXM(vsbc_vxm_h, uint16_t, H2, DO_VSBC, clearh)
+GEN_VEXT_VADC_VXM(vsbc_vxm_w, uint32_t, H4, DO_VSBC, clearl)
+GEN_VEXT_VADC_VXM(vsbc_vxm_d, uint64_t, H8, DO_VSBC, clearq)
+
+#define DO_MADC(N, M, C) (C ? (__typeof(N))(N + M + 1) <= N : \
+ (__typeof(N))(N + M) < N)
+#define DO_MSBC(N, M, C) (C ? N <= M : N < M)
+
+#define GEN_VEXT_VMADC_VVM(NAME, ETYPE, H, DO_OP) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ uint8_t carry = vext_elem_mask(v0, mlen, i); \
+ \
+ vext_set_elem_mask(vd, mlen, i, DO_OP(s2, s1, carry));\
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+GEN_VEXT_VMADC_VVM(vmadc_vvm_b, uint8_t, H1, DO_MADC)
+GEN_VEXT_VMADC_VVM(vmadc_vvm_h, uint16_t, H2, DO_MADC)
+GEN_VEXT_VMADC_VVM(vmadc_vvm_w, uint32_t, H4, DO_MADC)
+GEN_VEXT_VMADC_VVM(vmadc_vvm_d, uint64_t, H8, DO_MADC)
+
+GEN_VEXT_VMADC_VVM(vmsbc_vvm_b, uint8_t, H1, DO_MSBC)
+GEN_VEXT_VMADC_VVM(vmsbc_vvm_h, uint16_t, H2, DO_MSBC)
+GEN_VEXT_VMADC_VVM(vmsbc_vvm_w, uint32_t, H4, DO_MSBC)
+GEN_VEXT_VMADC_VVM(vmsbc_vvm_d, uint64_t, H8, DO_MSBC)
+
+#define GEN_VEXT_VMADC_VXM(NAME, ETYPE, H, DO_OP) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ uint8_t carry = vext_elem_mask(v0, mlen, i); \
+ \
+ vext_set_elem_mask(vd, mlen, i, \
+ DO_OP(s2, (ETYPE)(target_long)s1, carry)); \
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+GEN_VEXT_VMADC_VXM(vmadc_vxm_b, uint8_t, H1, DO_MADC)
+GEN_VEXT_VMADC_VXM(vmadc_vxm_h, uint16_t, H2, DO_MADC)
+GEN_VEXT_VMADC_VXM(vmadc_vxm_w, uint32_t, H4, DO_MADC)
+GEN_VEXT_VMADC_VXM(vmadc_vxm_d, uint64_t, H8, DO_MADC)
+
+GEN_VEXT_VMADC_VXM(vmsbc_vxm_b, uint8_t, H1, DO_MSBC)
+GEN_VEXT_VMADC_VXM(vmsbc_vxm_h, uint16_t, H2, DO_MSBC)
+GEN_VEXT_VMADC_VXM(vmsbc_vxm_w, uint32_t, H4, DO_MSBC)
+GEN_VEXT_VMADC_VXM(vmsbc_vxm_d, uint64_t, H8, DO_MSBC)
+
+/* Vector Bitwise Logical Instructions */
+RVVCALL(OPIVV2, vand_vv_b, OP_SSS_B, H1, H1, H1, DO_AND)
+RVVCALL(OPIVV2, vand_vv_h, OP_SSS_H, H2, H2, H2, DO_AND)
+RVVCALL(OPIVV2, vand_vv_w, OP_SSS_W, H4, H4, H4, DO_AND)
+RVVCALL(OPIVV2, vand_vv_d, OP_SSS_D, H8, H8, H8, DO_AND)
+RVVCALL(OPIVV2, vor_vv_b, OP_SSS_B, H1, H1, H1, DO_OR)
+RVVCALL(OPIVV2, vor_vv_h, OP_SSS_H, H2, H2, H2, DO_OR)
+RVVCALL(OPIVV2, vor_vv_w, OP_SSS_W, H4, H4, H4, DO_OR)
+RVVCALL(OPIVV2, vor_vv_d, OP_SSS_D, H8, H8, H8, DO_OR)
+RVVCALL(OPIVV2, vxor_vv_b, OP_SSS_B, H1, H1, H1, DO_XOR)
+RVVCALL(OPIVV2, vxor_vv_h, OP_SSS_H, H2, H2, H2, DO_XOR)
+RVVCALL(OPIVV2, vxor_vv_w, OP_SSS_W, H4, H4, H4, DO_XOR)
+RVVCALL(OPIVV2, vxor_vv_d, OP_SSS_D, H8, H8, H8, DO_XOR)
+GEN_VEXT_VV(vand_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vand_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vand_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vand_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vor_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vor_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vor_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vor_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vxor_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vxor_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vxor_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vxor_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2, vand_vx_b, OP_SSS_B, H1, H1, DO_AND)
+RVVCALL(OPIVX2, vand_vx_h, OP_SSS_H, H2, H2, DO_AND)
+RVVCALL(OPIVX2, vand_vx_w, OP_SSS_W, H4, H4, DO_AND)
+RVVCALL(OPIVX2, vand_vx_d, OP_SSS_D, H8, H8, DO_AND)
+RVVCALL(OPIVX2, vor_vx_b, OP_SSS_B, H1, H1, DO_OR)
+RVVCALL(OPIVX2, vor_vx_h, OP_SSS_H, H2, H2, DO_OR)
+RVVCALL(OPIVX2, vor_vx_w, OP_SSS_W, H4, H4, DO_OR)
+RVVCALL(OPIVX2, vor_vx_d, OP_SSS_D, H8, H8, DO_OR)
+RVVCALL(OPIVX2, vxor_vx_b, OP_SSS_B, H1, H1, DO_XOR)
+RVVCALL(OPIVX2, vxor_vx_h, OP_SSS_H, H2, H2, DO_XOR)
+RVVCALL(OPIVX2, vxor_vx_w, OP_SSS_W, H4, H4, DO_XOR)
+RVVCALL(OPIVX2, vxor_vx_d, OP_SSS_D, H8, H8, DO_XOR)
+GEN_VEXT_VX(vand_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vand_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vand_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vand_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vor_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vor_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vor_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vor_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vxor_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vxor_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vxor_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vxor_vx_d, 8, 8, clearq)
+
+/* Vector Single-Width Bit Shift Instructions */
+#define DO_SLL(N, M) (N << (M))
+#define DO_SRL(N, M) (N >> (M))
+
+/* generate the helpers for shift instructions with two vector operators */
+#define GEN_VEXT_SHIFT_VV(NAME, TS1, TS2, HS1, HS2, OP, MASK, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(TS1); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ TS1 s1 = *((TS1 *)vs1 + HS1(i)); \
+ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
+ *((TS1 *)vd + HS1(i)) = OP(s2, s1 & MASK); \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_SHIFT_VV(vsll_vv_b, uint8_t, uint8_t, H1, H1, DO_SLL, 0x7, clearb)
+GEN_VEXT_SHIFT_VV(vsll_vv_h, uint16_t, uint16_t, H2, H2, DO_SLL, 0xf, clearh)
+GEN_VEXT_SHIFT_VV(vsll_vv_w, uint32_t, uint32_t, H4, H4, DO_SLL, 0x1f, clearl)
+GEN_VEXT_SHIFT_VV(vsll_vv_d, uint64_t, uint64_t, H8, H8, DO_SLL, 0x3f, clearq)
+
+GEN_VEXT_SHIFT_VV(vsrl_vv_b, uint8_t, uint8_t, H1, H1, DO_SRL, 0x7, clearb)
+GEN_VEXT_SHIFT_VV(vsrl_vv_h, uint16_t, uint16_t, H2, H2, DO_SRL, 0xf, clearh)
+GEN_VEXT_SHIFT_VV(vsrl_vv_w, uint32_t, uint32_t, H4, H4, DO_SRL, 0x1f, clearl)
+GEN_VEXT_SHIFT_VV(vsrl_vv_d, uint64_t, uint64_t, H8, H8, DO_SRL, 0x3f, clearq)
+
+GEN_VEXT_SHIFT_VV(vsra_vv_b, uint8_t, int8_t, H1, H1, DO_SRL, 0x7, clearb)
+GEN_VEXT_SHIFT_VV(vsra_vv_h, uint16_t, int16_t, H2, H2, DO_SRL, 0xf, clearh)
+GEN_VEXT_SHIFT_VV(vsra_vv_w, uint32_t, int32_t, H4, H4, DO_SRL, 0x1f, clearl)
+GEN_VEXT_SHIFT_VV(vsra_vv_d, uint64_t, int64_t, H8, H8, DO_SRL, 0x3f, clearq)
+
+/* generate the helpers for shift instructions with one vector and one scalar */
+#define GEN_VEXT_SHIFT_VX(NAME, TD, TS2, HD, HS2, OP, MASK, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(TD); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, s1 & MASK); \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_SHIFT_VX(vsll_vx_b, uint8_t, int8_t, H1, H1, DO_SLL, 0x7, clearb)
+GEN_VEXT_SHIFT_VX(vsll_vx_h, uint16_t, int16_t, H2, H2, DO_SLL, 0xf, clearh)
+GEN_VEXT_SHIFT_VX(vsll_vx_w, uint32_t, int32_t, H4, H4, DO_SLL, 0x1f, clearl)
+GEN_VEXT_SHIFT_VX(vsll_vx_d, uint64_t, int64_t, H8, H8, DO_SLL, 0x3f, clearq)
+
+GEN_VEXT_SHIFT_VX(vsrl_vx_b, uint8_t, uint8_t, H1, H1, DO_SRL, 0x7, clearb)
+GEN_VEXT_SHIFT_VX(vsrl_vx_h, uint16_t, uint16_t, H2, H2, DO_SRL, 0xf, clearh)
+GEN_VEXT_SHIFT_VX(vsrl_vx_w, uint32_t, uint32_t, H4, H4, DO_SRL, 0x1f, clearl)
+GEN_VEXT_SHIFT_VX(vsrl_vx_d, uint64_t, uint64_t, H8, H8, DO_SRL, 0x3f, clearq)
+
+GEN_VEXT_SHIFT_VX(vsra_vx_b, int8_t, int8_t, H1, H1, DO_SRL, 0x7, clearb)
+GEN_VEXT_SHIFT_VX(vsra_vx_h, int16_t, int16_t, H2, H2, DO_SRL, 0xf, clearh)
+GEN_VEXT_SHIFT_VX(vsra_vx_w, int32_t, int32_t, H4, H4, DO_SRL, 0x1f, clearl)
+GEN_VEXT_SHIFT_VX(vsra_vx_d, int64_t, int64_t, H8, H8, DO_SRL, 0x3f, clearq)
+
+/* Vector Narrowing Integer Right Shift Instructions */
+GEN_VEXT_SHIFT_VV(vnsrl_vv_b, uint8_t, uint16_t, H1, H2, DO_SRL, 0xf, clearb)
+GEN_VEXT_SHIFT_VV(vnsrl_vv_h, uint16_t, uint32_t, H2, H4, DO_SRL, 0x1f, clearh)
+GEN_VEXT_SHIFT_VV(vnsrl_vv_w, uint32_t, uint64_t, H4, H8, DO_SRL, 0x3f, clearl)
+GEN_VEXT_SHIFT_VV(vnsra_vv_b, uint8_t, int16_t, H1, H2, DO_SRL, 0xf, clearb)
+GEN_VEXT_SHIFT_VV(vnsra_vv_h, uint16_t, int32_t, H2, H4, DO_SRL, 0x1f, clearh)
+GEN_VEXT_SHIFT_VV(vnsra_vv_w, uint32_t, int64_t, H4, H8, DO_SRL, 0x3f, clearl)
+GEN_VEXT_SHIFT_VX(vnsrl_vx_b, uint8_t, uint16_t, H1, H2, DO_SRL, 0xf, clearb)
+GEN_VEXT_SHIFT_VX(vnsrl_vx_h, uint16_t, uint32_t, H2, H4, DO_SRL, 0x1f, clearh)
+GEN_VEXT_SHIFT_VX(vnsrl_vx_w, uint32_t, uint64_t, H4, H8, DO_SRL, 0x3f, clearl)
+GEN_VEXT_SHIFT_VX(vnsra_vx_b, int8_t, int16_t, H1, H2, DO_SRL, 0xf, clearb)
+GEN_VEXT_SHIFT_VX(vnsra_vx_h, int16_t, int32_t, H2, H4, DO_SRL, 0x1f, clearh)
+GEN_VEXT_SHIFT_VX(vnsra_vx_w, int32_t, int64_t, H4, H8, DO_SRL, 0x3f, clearl)
+
+/* Vector Integer Comparison Instructions */
+#define DO_MSEQ(N, M) (N == M)
+#define DO_MSNE(N, M) (N != M)
+#define DO_MSLT(N, M) (N < M)
+#define DO_MSLE(N, M) (N <= M)
+#define DO_MSGT(N, M) (N > M)
+
+#define GEN_VEXT_CMP_VV(NAME, ETYPE, H, DO_OP) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ vext_set_elem_mask(vd, mlen, i, DO_OP(s2, s1)); \
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+GEN_VEXT_CMP_VV(vmseq_vv_b, uint8_t, H1, DO_MSEQ)
+GEN_VEXT_CMP_VV(vmseq_vv_h, uint16_t, H2, DO_MSEQ)
+GEN_VEXT_CMP_VV(vmseq_vv_w, uint32_t, H4, DO_MSEQ)
+GEN_VEXT_CMP_VV(vmseq_vv_d, uint64_t, H8, DO_MSEQ)
+
+GEN_VEXT_CMP_VV(vmsne_vv_b, uint8_t, H1, DO_MSNE)
+GEN_VEXT_CMP_VV(vmsne_vv_h, uint16_t, H2, DO_MSNE)
+GEN_VEXT_CMP_VV(vmsne_vv_w, uint32_t, H4, DO_MSNE)
+GEN_VEXT_CMP_VV(vmsne_vv_d, uint64_t, H8, DO_MSNE)
+
+GEN_VEXT_CMP_VV(vmsltu_vv_b, uint8_t, H1, DO_MSLT)
+GEN_VEXT_CMP_VV(vmsltu_vv_h, uint16_t, H2, DO_MSLT)
+GEN_VEXT_CMP_VV(vmsltu_vv_w, uint32_t, H4, DO_MSLT)
+GEN_VEXT_CMP_VV(vmsltu_vv_d, uint64_t, H8, DO_MSLT)
+
+GEN_VEXT_CMP_VV(vmslt_vv_b, int8_t, H1, DO_MSLT)
+GEN_VEXT_CMP_VV(vmslt_vv_h, int16_t, H2, DO_MSLT)
+GEN_VEXT_CMP_VV(vmslt_vv_w, int32_t, H4, DO_MSLT)
+GEN_VEXT_CMP_VV(vmslt_vv_d, int64_t, H8, DO_MSLT)
+
+GEN_VEXT_CMP_VV(vmsleu_vv_b, uint8_t, H1, DO_MSLE)
+GEN_VEXT_CMP_VV(vmsleu_vv_h, uint16_t, H2, DO_MSLE)
+GEN_VEXT_CMP_VV(vmsleu_vv_w, uint32_t, H4, DO_MSLE)
+GEN_VEXT_CMP_VV(vmsleu_vv_d, uint64_t, H8, DO_MSLE)
+
+GEN_VEXT_CMP_VV(vmsle_vv_b, int8_t, H1, DO_MSLE)
+GEN_VEXT_CMP_VV(vmsle_vv_h, int16_t, H2, DO_MSLE)
+GEN_VEXT_CMP_VV(vmsle_vv_w, int32_t, H4, DO_MSLE)
+GEN_VEXT_CMP_VV(vmsle_vv_d, int64_t, H8, DO_MSLE)
+
+#define GEN_VEXT_CMP_VX(NAME, ETYPE, H, DO_OP) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ vext_set_elem_mask(vd, mlen, i, \
+ DO_OP(s2, (ETYPE)(target_long)s1)); \
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+GEN_VEXT_CMP_VX(vmseq_vx_b, uint8_t, H1, DO_MSEQ)
+GEN_VEXT_CMP_VX(vmseq_vx_h, uint16_t, H2, DO_MSEQ)
+GEN_VEXT_CMP_VX(vmseq_vx_w, uint32_t, H4, DO_MSEQ)
+GEN_VEXT_CMP_VX(vmseq_vx_d, uint64_t, H8, DO_MSEQ)
+
+GEN_VEXT_CMP_VX(vmsne_vx_b, uint8_t, H1, DO_MSNE)
+GEN_VEXT_CMP_VX(vmsne_vx_h, uint16_t, H2, DO_MSNE)
+GEN_VEXT_CMP_VX(vmsne_vx_w, uint32_t, H4, DO_MSNE)
+GEN_VEXT_CMP_VX(vmsne_vx_d, uint64_t, H8, DO_MSNE)
+
+GEN_VEXT_CMP_VX(vmsltu_vx_b, uint8_t, H1, DO_MSLT)
+GEN_VEXT_CMP_VX(vmsltu_vx_h, uint16_t, H2, DO_MSLT)
+GEN_VEXT_CMP_VX(vmsltu_vx_w, uint32_t, H4, DO_MSLT)
+GEN_VEXT_CMP_VX(vmsltu_vx_d, uint64_t, H8, DO_MSLT)
+
+GEN_VEXT_CMP_VX(vmslt_vx_b, int8_t, H1, DO_MSLT)
+GEN_VEXT_CMP_VX(vmslt_vx_h, int16_t, H2, DO_MSLT)
+GEN_VEXT_CMP_VX(vmslt_vx_w, int32_t, H4, DO_MSLT)
+GEN_VEXT_CMP_VX(vmslt_vx_d, int64_t, H8, DO_MSLT)
+
+GEN_VEXT_CMP_VX(vmsleu_vx_b, uint8_t, H1, DO_MSLE)
+GEN_VEXT_CMP_VX(vmsleu_vx_h, uint16_t, H2, DO_MSLE)
+GEN_VEXT_CMP_VX(vmsleu_vx_w, uint32_t, H4, DO_MSLE)
+GEN_VEXT_CMP_VX(vmsleu_vx_d, uint64_t, H8, DO_MSLE)
+
+GEN_VEXT_CMP_VX(vmsle_vx_b, int8_t, H1, DO_MSLE)
+GEN_VEXT_CMP_VX(vmsle_vx_h, int16_t, H2, DO_MSLE)
+GEN_VEXT_CMP_VX(vmsle_vx_w, int32_t, H4, DO_MSLE)
+GEN_VEXT_CMP_VX(vmsle_vx_d, int64_t, H8, DO_MSLE)
+
+GEN_VEXT_CMP_VX(vmsgtu_vx_b, uint8_t, H1, DO_MSGT)
+GEN_VEXT_CMP_VX(vmsgtu_vx_h, uint16_t, H2, DO_MSGT)
+GEN_VEXT_CMP_VX(vmsgtu_vx_w, uint32_t, H4, DO_MSGT)
+GEN_VEXT_CMP_VX(vmsgtu_vx_d, uint64_t, H8, DO_MSGT)
+
+GEN_VEXT_CMP_VX(vmsgt_vx_b, int8_t, H1, DO_MSGT)
+GEN_VEXT_CMP_VX(vmsgt_vx_h, int16_t, H2, DO_MSGT)
+GEN_VEXT_CMP_VX(vmsgt_vx_w, int32_t, H4, DO_MSGT)
+GEN_VEXT_CMP_VX(vmsgt_vx_d, int64_t, H8, DO_MSGT)
+
+/* Vector Integer Min/Max Instructions */
+RVVCALL(OPIVV2, vminu_vv_b, OP_UUU_B, H1, H1, H1, DO_MIN)
+RVVCALL(OPIVV2, vminu_vv_h, OP_UUU_H, H2, H2, H2, DO_MIN)
+RVVCALL(OPIVV2, vminu_vv_w, OP_UUU_W, H4, H4, H4, DO_MIN)
+RVVCALL(OPIVV2, vminu_vv_d, OP_UUU_D, H8, H8, H8, DO_MIN)
+RVVCALL(OPIVV2, vmin_vv_b, OP_SSS_B, H1, H1, H1, DO_MIN)
+RVVCALL(OPIVV2, vmin_vv_h, OP_SSS_H, H2, H2, H2, DO_MIN)
+RVVCALL(OPIVV2, vmin_vv_w, OP_SSS_W, H4, H4, H4, DO_MIN)
+RVVCALL(OPIVV2, vmin_vv_d, OP_SSS_D, H8, H8, H8, DO_MIN)
+RVVCALL(OPIVV2, vmaxu_vv_b, OP_UUU_B, H1, H1, H1, DO_MAX)
+RVVCALL(OPIVV2, vmaxu_vv_h, OP_UUU_H, H2, H2, H2, DO_MAX)
+RVVCALL(OPIVV2, vmaxu_vv_w, OP_UUU_W, H4, H4, H4, DO_MAX)
+RVVCALL(OPIVV2, vmaxu_vv_d, OP_UUU_D, H8, H8, H8, DO_MAX)
+RVVCALL(OPIVV2, vmax_vv_b, OP_SSS_B, H1, H1, H1, DO_MAX)
+RVVCALL(OPIVV2, vmax_vv_h, OP_SSS_H, H2, H2, H2, DO_MAX)
+RVVCALL(OPIVV2, vmax_vv_w, OP_SSS_W, H4, H4, H4, DO_MAX)
+RVVCALL(OPIVV2, vmax_vv_d, OP_SSS_D, H8, H8, H8, DO_MAX)
+GEN_VEXT_VV(vminu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vminu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vminu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vminu_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vmin_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmin_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmin_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmin_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vmaxu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmaxu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmaxu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmaxu_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vmax_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmax_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmax_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmax_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2, vminu_vx_b, OP_UUU_B, H1, H1, DO_MIN)
+RVVCALL(OPIVX2, vminu_vx_h, OP_UUU_H, H2, H2, DO_MIN)
+RVVCALL(OPIVX2, vminu_vx_w, OP_UUU_W, H4, H4, DO_MIN)
+RVVCALL(OPIVX2, vminu_vx_d, OP_UUU_D, H8, H8, DO_MIN)
+RVVCALL(OPIVX2, vmin_vx_b, OP_SSS_B, H1, H1, DO_MIN)
+RVVCALL(OPIVX2, vmin_vx_h, OP_SSS_H, H2, H2, DO_MIN)
+RVVCALL(OPIVX2, vmin_vx_w, OP_SSS_W, H4, H4, DO_MIN)
+RVVCALL(OPIVX2, vmin_vx_d, OP_SSS_D, H8, H8, DO_MIN)
+RVVCALL(OPIVX2, vmaxu_vx_b, OP_UUU_B, H1, H1, DO_MAX)
+RVVCALL(OPIVX2, vmaxu_vx_h, OP_UUU_H, H2, H2, DO_MAX)
+RVVCALL(OPIVX2, vmaxu_vx_w, OP_UUU_W, H4, H4, DO_MAX)
+RVVCALL(OPIVX2, vmaxu_vx_d, OP_UUU_D, H8, H8, DO_MAX)
+RVVCALL(OPIVX2, vmax_vx_b, OP_SSS_B, H1, H1, DO_MAX)
+RVVCALL(OPIVX2, vmax_vx_h, OP_SSS_H, H2, H2, DO_MAX)
+RVVCALL(OPIVX2, vmax_vx_w, OP_SSS_W, H4, H4, DO_MAX)
+RVVCALL(OPIVX2, vmax_vx_d, OP_SSS_D, H8, H8, DO_MAX)
+GEN_VEXT_VX(vminu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vminu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vminu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vminu_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmin_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmin_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmin_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmin_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmaxu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmaxu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmaxu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmaxu_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmax_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmax_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmax_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmax_vx_d, 8, 8, clearq)
+
+/* Vector Single-Width Integer Multiply Instructions */
+#define DO_MUL(N, M) (N * M)
+RVVCALL(OPIVV2, vmul_vv_b, OP_SSS_B, H1, H1, H1, DO_MUL)
+RVVCALL(OPIVV2, vmul_vv_h, OP_SSS_H, H2, H2, H2, DO_MUL)
+RVVCALL(OPIVV2, vmul_vv_w, OP_SSS_W, H4, H4, H4, DO_MUL)
+RVVCALL(OPIVV2, vmul_vv_d, OP_SSS_D, H8, H8, H8, DO_MUL)
+GEN_VEXT_VV(vmul_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmul_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmul_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmul_vv_d, 8, 8, clearq)
+
+static int8_t do_mulh_b(int8_t s2, int8_t s1)
+{
+ return (int16_t)s2 * (int16_t)s1 >> 8;
+}
+
+static int16_t do_mulh_h(int16_t s2, int16_t s1)
+{
+ return (int32_t)s2 * (int32_t)s1 >> 16;
+}
+
+static int32_t do_mulh_w(int32_t s2, int32_t s1)
+{
+ return (int64_t)s2 * (int64_t)s1 >> 32;
+}
+
+static int64_t do_mulh_d(int64_t s2, int64_t s1)
+{
+ uint64_t hi_64, lo_64;
+
+ muls64(&lo_64, &hi_64, s1, s2);
+ return hi_64;
+}
+
+static uint8_t do_mulhu_b(uint8_t s2, uint8_t s1)
+{
+ return (uint16_t)s2 * (uint16_t)s1 >> 8;
+}
+
+static uint16_t do_mulhu_h(uint16_t s2, uint16_t s1)
+{
+ return (uint32_t)s2 * (uint32_t)s1 >> 16;
+}
+
+static uint32_t do_mulhu_w(uint32_t s2, uint32_t s1)
+{
+ return (uint64_t)s2 * (uint64_t)s1 >> 32;
+}
+
+static uint64_t do_mulhu_d(uint64_t s2, uint64_t s1)
+{
+ uint64_t hi_64, lo_64;
+
+ mulu64(&lo_64, &hi_64, s2, s1);
+ return hi_64;
+}
+
+static int8_t do_mulhsu_b(int8_t s2, uint8_t s1)
+{
+ return (int16_t)s2 * (uint16_t)s1 >> 8;
+}
+
+static int16_t do_mulhsu_h(int16_t s2, uint16_t s1)
+{
+ return (int32_t)s2 * (uint32_t)s1 >> 16;
+}
+
+static int32_t do_mulhsu_w(int32_t s2, uint32_t s1)
+{
+ return (int64_t)s2 * (uint64_t)s1 >> 32;
+}
+
+/*
+ * Let A = signed operand,
+ * B = unsigned operand
+ * P = mulu64(A, B), unsigned product
+ *
+ * LET X = 2 ** 64 - A, 2's complement of A
+ * SP = signed product
+ * THEN
+ * IF A < 0
+ * SP = -X * B
+ * = -(2 ** 64 - A) * B
+ * = A * B - 2 ** 64 * B
+ * = P - 2 ** 64 * B
+ * ELSE
+ * SP = P
+ * THEN
+ * HI_P -= (A < 0 ? B : 0)
+ */
+
+static int64_t do_mulhsu_d(int64_t s2, uint64_t s1)
+{
+ uint64_t hi_64, lo_64;
+
+ mulu64(&lo_64, &hi_64, s2, s1);
+
+ hi_64 -= s2 < 0 ? s1 : 0;
+ return hi_64;
+}
+
+RVVCALL(OPIVV2, vmulh_vv_b, OP_SSS_B, H1, H1, H1, do_mulh_b)
+RVVCALL(OPIVV2, vmulh_vv_h, OP_SSS_H, H2, H2, H2, do_mulh_h)
+RVVCALL(OPIVV2, vmulh_vv_w, OP_SSS_W, H4, H4, H4, do_mulh_w)
+RVVCALL(OPIVV2, vmulh_vv_d, OP_SSS_D, H8, H8, H8, do_mulh_d)
+RVVCALL(OPIVV2, vmulhu_vv_b, OP_UUU_B, H1, H1, H1, do_mulhu_b)
+RVVCALL(OPIVV2, vmulhu_vv_h, OP_UUU_H, H2, H2, H2, do_mulhu_h)
+RVVCALL(OPIVV2, vmulhu_vv_w, OP_UUU_W, H4, H4, H4, do_mulhu_w)
+RVVCALL(OPIVV2, vmulhu_vv_d, OP_UUU_D, H8, H8, H8, do_mulhu_d)
+RVVCALL(OPIVV2, vmulhsu_vv_b, OP_SUS_B, H1, H1, H1, do_mulhsu_b)
+RVVCALL(OPIVV2, vmulhsu_vv_h, OP_SUS_H, H2, H2, H2, do_mulhsu_h)
+RVVCALL(OPIVV2, vmulhsu_vv_w, OP_SUS_W, H4, H4, H4, do_mulhsu_w)
+RVVCALL(OPIVV2, vmulhsu_vv_d, OP_SUS_D, H8, H8, H8, do_mulhsu_d)
+GEN_VEXT_VV(vmulh_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmulh_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmulh_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmulh_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vmulhu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmulhu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmulhu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmulhu_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vmulhsu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmulhsu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmulhsu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmulhsu_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2, vmul_vx_b, OP_SSS_B, H1, H1, DO_MUL)
+RVVCALL(OPIVX2, vmul_vx_h, OP_SSS_H, H2, H2, DO_MUL)
+RVVCALL(OPIVX2, vmul_vx_w, OP_SSS_W, H4, H4, DO_MUL)
+RVVCALL(OPIVX2, vmul_vx_d, OP_SSS_D, H8, H8, DO_MUL)
+RVVCALL(OPIVX2, vmulh_vx_b, OP_SSS_B, H1, H1, do_mulh_b)
+RVVCALL(OPIVX2, vmulh_vx_h, OP_SSS_H, H2, H2, do_mulh_h)
+RVVCALL(OPIVX2, vmulh_vx_w, OP_SSS_W, H4, H4, do_mulh_w)
+RVVCALL(OPIVX2, vmulh_vx_d, OP_SSS_D, H8, H8, do_mulh_d)
+RVVCALL(OPIVX2, vmulhu_vx_b, OP_UUU_B, H1, H1, do_mulhu_b)
+RVVCALL(OPIVX2, vmulhu_vx_h, OP_UUU_H, H2, H2, do_mulhu_h)
+RVVCALL(OPIVX2, vmulhu_vx_w, OP_UUU_W, H4, H4, do_mulhu_w)
+RVVCALL(OPIVX2, vmulhu_vx_d, OP_UUU_D, H8, H8, do_mulhu_d)
+RVVCALL(OPIVX2, vmulhsu_vx_b, OP_SUS_B, H1, H1, do_mulhsu_b)
+RVVCALL(OPIVX2, vmulhsu_vx_h, OP_SUS_H, H2, H2, do_mulhsu_h)
+RVVCALL(OPIVX2, vmulhsu_vx_w, OP_SUS_W, H4, H4, do_mulhsu_w)
+RVVCALL(OPIVX2, vmulhsu_vx_d, OP_SUS_D, H8, H8, do_mulhsu_d)
+GEN_VEXT_VX(vmul_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmul_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmul_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmul_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmulh_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmulh_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmulh_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmulh_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmulhu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmulhu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmulhu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmulhu_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmulhsu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmulhsu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmulhsu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmulhsu_vx_d, 8, 8, clearq)
+
+/* Vector Integer Divide Instructions */
+#define DO_DIVU(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) : N / M)
+#define DO_REMU(N, M) (unlikely(M == 0) ? N : N % M)
+#define DO_DIV(N, M) (unlikely(M == 0) ? (__typeof(N))(-1) :\
+ unlikely((N == -N) && (M == (__typeof(N))(-1))) ? N : N / M)
+#define DO_REM(N, M) (unlikely(M == 0) ? N :\
+ unlikely((N == -N) && (M == (__typeof(N))(-1))) ? 0 : N % M)
+
+RVVCALL(OPIVV2, vdivu_vv_b, OP_UUU_B, H1, H1, H1, DO_DIVU)
+RVVCALL(OPIVV2, vdivu_vv_h, OP_UUU_H, H2, H2, H2, DO_DIVU)
+RVVCALL(OPIVV2, vdivu_vv_w, OP_UUU_W, H4, H4, H4, DO_DIVU)
+RVVCALL(OPIVV2, vdivu_vv_d, OP_UUU_D, H8, H8, H8, DO_DIVU)
+RVVCALL(OPIVV2, vdiv_vv_b, OP_SSS_B, H1, H1, H1, DO_DIV)
+RVVCALL(OPIVV2, vdiv_vv_h, OP_SSS_H, H2, H2, H2, DO_DIV)
+RVVCALL(OPIVV2, vdiv_vv_w, OP_SSS_W, H4, H4, H4, DO_DIV)
+RVVCALL(OPIVV2, vdiv_vv_d, OP_SSS_D, H8, H8, H8, DO_DIV)
+RVVCALL(OPIVV2, vremu_vv_b, OP_UUU_B, H1, H1, H1, DO_REMU)
+RVVCALL(OPIVV2, vremu_vv_h, OP_UUU_H, H2, H2, H2, DO_REMU)
+RVVCALL(OPIVV2, vremu_vv_w, OP_UUU_W, H4, H4, H4, DO_REMU)
+RVVCALL(OPIVV2, vremu_vv_d, OP_UUU_D, H8, H8, H8, DO_REMU)
+RVVCALL(OPIVV2, vrem_vv_b, OP_SSS_B, H1, H1, H1, DO_REM)
+RVVCALL(OPIVV2, vrem_vv_h, OP_SSS_H, H2, H2, H2, DO_REM)
+RVVCALL(OPIVV2, vrem_vv_w, OP_SSS_W, H4, H4, H4, DO_REM)
+RVVCALL(OPIVV2, vrem_vv_d, OP_SSS_D, H8, H8, H8, DO_REM)
+GEN_VEXT_VV(vdivu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vdivu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vdivu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vdivu_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vdiv_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vdiv_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vdiv_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vdiv_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vremu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vremu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vremu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vremu_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vrem_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vrem_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vrem_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vrem_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2, vdivu_vx_b, OP_UUU_B, H1, H1, DO_DIVU)
+RVVCALL(OPIVX2, vdivu_vx_h, OP_UUU_H, H2, H2, DO_DIVU)
+RVVCALL(OPIVX2, vdivu_vx_w, OP_UUU_W, H4, H4, DO_DIVU)
+RVVCALL(OPIVX2, vdivu_vx_d, OP_UUU_D, H8, H8, DO_DIVU)
+RVVCALL(OPIVX2, vdiv_vx_b, OP_SSS_B, H1, H1, DO_DIV)
+RVVCALL(OPIVX2, vdiv_vx_h, OP_SSS_H, H2, H2, DO_DIV)
+RVVCALL(OPIVX2, vdiv_vx_w, OP_SSS_W, H4, H4, DO_DIV)
+RVVCALL(OPIVX2, vdiv_vx_d, OP_SSS_D, H8, H8, DO_DIV)
+RVVCALL(OPIVX2, vremu_vx_b, OP_UUU_B, H1, H1, DO_REMU)
+RVVCALL(OPIVX2, vremu_vx_h, OP_UUU_H, H2, H2, DO_REMU)
+RVVCALL(OPIVX2, vremu_vx_w, OP_UUU_W, H4, H4, DO_REMU)
+RVVCALL(OPIVX2, vremu_vx_d, OP_UUU_D, H8, H8, DO_REMU)
+RVVCALL(OPIVX2, vrem_vx_b, OP_SSS_B, H1, H1, DO_REM)
+RVVCALL(OPIVX2, vrem_vx_h, OP_SSS_H, H2, H2, DO_REM)
+RVVCALL(OPIVX2, vrem_vx_w, OP_SSS_W, H4, H4, DO_REM)
+RVVCALL(OPIVX2, vrem_vx_d, OP_SSS_D, H8, H8, DO_REM)
+GEN_VEXT_VX(vdivu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vdivu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vdivu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vdivu_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vdiv_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vdiv_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vdiv_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vdiv_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vremu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vremu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vremu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vremu_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vrem_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vrem_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vrem_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vrem_vx_d, 8, 8, clearq)
+
+/* Vector Widening Integer Multiply Instructions */
+RVVCALL(OPIVV2, vwmul_vv_b, WOP_SSS_B, H2, H1, H1, DO_MUL)
+RVVCALL(OPIVV2, vwmul_vv_h, WOP_SSS_H, H4, H2, H2, DO_MUL)
+RVVCALL(OPIVV2, vwmul_vv_w, WOP_SSS_W, H8, H4, H4, DO_MUL)
+RVVCALL(OPIVV2, vwmulu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MUL)
+RVVCALL(OPIVV2, vwmulu_vv_h, WOP_UUU_H, H4, H2, H2, DO_MUL)
+RVVCALL(OPIVV2, vwmulu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MUL)
+RVVCALL(OPIVV2, vwmulsu_vv_b, WOP_SUS_B, H2, H1, H1, DO_MUL)
+RVVCALL(OPIVV2, vwmulsu_vv_h, WOP_SUS_H, H4, H2, H2, DO_MUL)
+RVVCALL(OPIVV2, vwmulsu_vv_w, WOP_SUS_W, H8, H4, H4, DO_MUL)
+GEN_VEXT_VV(vwmul_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwmul_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwmul_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwmulu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwmulu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwmulu_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwmulsu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwmulsu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwmulsu_vv_w, 4, 8, clearq)
+
+RVVCALL(OPIVX2, vwmul_vx_b, WOP_SSS_B, H2, H1, DO_MUL)
+RVVCALL(OPIVX2, vwmul_vx_h, WOP_SSS_H, H4, H2, DO_MUL)
+RVVCALL(OPIVX2, vwmul_vx_w, WOP_SSS_W, H8, H4, DO_MUL)
+RVVCALL(OPIVX2, vwmulu_vx_b, WOP_UUU_B, H2, H1, DO_MUL)
+RVVCALL(OPIVX2, vwmulu_vx_h, WOP_UUU_H, H4, H2, DO_MUL)
+RVVCALL(OPIVX2, vwmulu_vx_w, WOP_UUU_W, H8, H4, DO_MUL)
+RVVCALL(OPIVX2, vwmulsu_vx_b, WOP_SUS_B, H2, H1, DO_MUL)
+RVVCALL(OPIVX2, vwmulsu_vx_h, WOP_SUS_H, H4, H2, DO_MUL)
+RVVCALL(OPIVX2, vwmulsu_vx_w, WOP_SUS_W, H8, H4, DO_MUL)
+GEN_VEXT_VX(vwmul_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmul_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmul_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwmulu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmulu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmulu_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwmulsu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmulsu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmulsu_vx_w, 4, 8, clearq)
+
+/* Vector Single-Width Integer Multiply-Add Instructions */
+#define OPIVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
+static void do_##NAME(void *vd, void *vs1, void *vs2, int i) \
+{ \
+ TX1 s1 = *((T1 *)vs1 + HS1(i)); \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ TD d = *((TD *)vd + HD(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, s1, d); \
+}
+
+#define DO_MACC(N, M, D) (M * N + D)
+#define DO_NMSAC(N, M, D) (-(M * N) + D)
+#define DO_MADD(N, M, D) (M * D + N)
+#define DO_NMSUB(N, M, D) (-(M * D) + N)
+RVVCALL(OPIVV3, vmacc_vv_b, OP_SSS_B, H1, H1, H1, DO_MACC)
+RVVCALL(OPIVV3, vmacc_vv_h, OP_SSS_H, H2, H2, H2, DO_MACC)
+RVVCALL(OPIVV3, vmacc_vv_w, OP_SSS_W, H4, H4, H4, DO_MACC)
+RVVCALL(OPIVV3, vmacc_vv_d, OP_SSS_D, H8, H8, H8, DO_MACC)
+RVVCALL(OPIVV3, vnmsac_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSAC)
+RVVCALL(OPIVV3, vnmsac_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSAC)
+RVVCALL(OPIVV3, vnmsac_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSAC)
+RVVCALL(OPIVV3, vnmsac_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSAC)
+RVVCALL(OPIVV3, vmadd_vv_b, OP_SSS_B, H1, H1, H1, DO_MADD)
+RVVCALL(OPIVV3, vmadd_vv_h, OP_SSS_H, H2, H2, H2, DO_MADD)
+RVVCALL(OPIVV3, vmadd_vv_w, OP_SSS_W, H4, H4, H4, DO_MADD)
+RVVCALL(OPIVV3, vmadd_vv_d, OP_SSS_D, H8, H8, H8, DO_MADD)
+RVVCALL(OPIVV3, vnmsub_vv_b, OP_SSS_B, H1, H1, H1, DO_NMSUB)
+RVVCALL(OPIVV3, vnmsub_vv_h, OP_SSS_H, H2, H2, H2, DO_NMSUB)
+RVVCALL(OPIVV3, vnmsub_vv_w, OP_SSS_W, H4, H4, H4, DO_NMSUB)
+RVVCALL(OPIVV3, vnmsub_vv_d, OP_SSS_D, H8, H8, H8, DO_NMSUB)
+GEN_VEXT_VV(vmacc_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmacc_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmacc_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmacc_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vnmsac_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vnmsac_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vnmsac_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vnmsac_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vmadd_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vmadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vmadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vmadd_vv_d, 8, 8, clearq)
+GEN_VEXT_VV(vnmsub_vv_b, 1, 1, clearb)
+GEN_VEXT_VV(vnmsub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV(vnmsub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV(vnmsub_vv_d, 8, 8, clearq)
+
+#define OPIVX3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
+static void do_##NAME(void *vd, target_long s1, void *vs2, int i) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ TD d = *((TD *)vd + HD(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, d); \
+}
+
+RVVCALL(OPIVX3, vmacc_vx_b, OP_SSS_B, H1, H1, DO_MACC)
+RVVCALL(OPIVX3, vmacc_vx_h, OP_SSS_H, H2, H2, DO_MACC)
+RVVCALL(OPIVX3, vmacc_vx_w, OP_SSS_W, H4, H4, DO_MACC)
+RVVCALL(OPIVX3, vmacc_vx_d, OP_SSS_D, H8, H8, DO_MACC)
+RVVCALL(OPIVX3, vnmsac_vx_b, OP_SSS_B, H1, H1, DO_NMSAC)
+RVVCALL(OPIVX3, vnmsac_vx_h, OP_SSS_H, H2, H2, DO_NMSAC)
+RVVCALL(OPIVX3, vnmsac_vx_w, OP_SSS_W, H4, H4, DO_NMSAC)
+RVVCALL(OPIVX3, vnmsac_vx_d, OP_SSS_D, H8, H8, DO_NMSAC)
+RVVCALL(OPIVX3, vmadd_vx_b, OP_SSS_B, H1, H1, DO_MADD)
+RVVCALL(OPIVX3, vmadd_vx_h, OP_SSS_H, H2, H2, DO_MADD)
+RVVCALL(OPIVX3, vmadd_vx_w, OP_SSS_W, H4, H4, DO_MADD)
+RVVCALL(OPIVX3, vmadd_vx_d, OP_SSS_D, H8, H8, DO_MADD)
+RVVCALL(OPIVX3, vnmsub_vx_b, OP_SSS_B, H1, H1, DO_NMSUB)
+RVVCALL(OPIVX3, vnmsub_vx_h, OP_SSS_H, H2, H2, DO_NMSUB)
+RVVCALL(OPIVX3, vnmsub_vx_w, OP_SSS_W, H4, H4, DO_NMSUB)
+RVVCALL(OPIVX3, vnmsub_vx_d, OP_SSS_D, H8, H8, DO_NMSUB)
+GEN_VEXT_VX(vmacc_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmacc_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmacc_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmacc_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vnmsac_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vnmsac_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vnmsac_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vnmsac_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vmadd_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vmadd_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vmadd_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vmadd_vx_d, 8, 8, clearq)
+GEN_VEXT_VX(vnmsub_vx_b, 1, 1, clearb)
+GEN_VEXT_VX(vnmsub_vx_h, 2, 2, clearh)
+GEN_VEXT_VX(vnmsub_vx_w, 4, 4, clearl)
+GEN_VEXT_VX(vnmsub_vx_d, 8, 8, clearq)
+
+/* Vector Widening Integer Multiply-Add Instructions */
+RVVCALL(OPIVV3, vwmaccu_vv_b, WOP_UUU_B, H2, H1, H1, DO_MACC)
+RVVCALL(OPIVV3, vwmaccu_vv_h, WOP_UUU_H, H4, H2, H2, DO_MACC)
+RVVCALL(OPIVV3, vwmaccu_vv_w, WOP_UUU_W, H8, H4, H4, DO_MACC)
+RVVCALL(OPIVV3, vwmacc_vv_b, WOP_SSS_B, H2, H1, H1, DO_MACC)
+RVVCALL(OPIVV3, vwmacc_vv_h, WOP_SSS_H, H4, H2, H2, DO_MACC)
+RVVCALL(OPIVV3, vwmacc_vv_w, WOP_SSS_W, H8, H4, H4, DO_MACC)
+RVVCALL(OPIVV3, vwmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, DO_MACC)
+RVVCALL(OPIVV3, vwmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, DO_MACC)
+RVVCALL(OPIVV3, vwmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, DO_MACC)
+GEN_VEXT_VV(vwmaccu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwmaccu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwmaccu_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwmacc_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwmacc_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwmacc_vv_w, 4, 8, clearq)
+GEN_VEXT_VV(vwmaccsu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV(vwmaccsu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV(vwmaccsu_vv_w, 4, 8, clearq)
+
+RVVCALL(OPIVX3, vwmaccu_vx_b, WOP_UUU_B, H2, H1, DO_MACC)
+RVVCALL(OPIVX3, vwmaccu_vx_h, WOP_UUU_H, H4, H2, DO_MACC)
+RVVCALL(OPIVX3, vwmaccu_vx_w, WOP_UUU_W, H8, H4, DO_MACC)
+RVVCALL(OPIVX3, vwmacc_vx_b, WOP_SSS_B, H2, H1, DO_MACC)
+RVVCALL(OPIVX3, vwmacc_vx_h, WOP_SSS_H, H4, H2, DO_MACC)
+RVVCALL(OPIVX3, vwmacc_vx_w, WOP_SSS_W, H8, H4, DO_MACC)
+RVVCALL(OPIVX3, vwmaccsu_vx_b, WOP_SSU_B, H2, H1, DO_MACC)
+RVVCALL(OPIVX3, vwmaccsu_vx_h, WOP_SSU_H, H4, H2, DO_MACC)
+RVVCALL(OPIVX3, vwmaccsu_vx_w, WOP_SSU_W, H8, H4, DO_MACC)
+RVVCALL(OPIVX3, vwmaccus_vx_b, WOP_SUS_B, H2, H1, DO_MACC)
+RVVCALL(OPIVX3, vwmaccus_vx_h, WOP_SUS_H, H4, H2, DO_MACC)
+RVVCALL(OPIVX3, vwmaccus_vx_w, WOP_SUS_W, H8, H4, DO_MACC)
+GEN_VEXT_VX(vwmaccu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmaccu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmaccu_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwmacc_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmacc_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmacc_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwmaccsu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmaccsu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmaccsu_vx_w, 4, 8, clearq)
+GEN_VEXT_VX(vwmaccus_vx_b, 1, 2, clearh)
+GEN_VEXT_VX(vwmaccus_vx_h, 2, 4, clearl)
+GEN_VEXT_VX(vwmaccus_vx_w, 4, 8, clearq)
+
+/* Vector Integer Merge and Move Instructions */
+#define GEN_VEXT_VMV_VV(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
+ *((ETYPE *)vd + H(i)) = s1; \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_VMV_VV(vmv_v_v_b, int8_t, H1, clearb)
+GEN_VEXT_VMV_VV(vmv_v_v_h, int16_t, H2, clearh)
+GEN_VEXT_VMV_VV(vmv_v_v_w, int32_t, H4, clearl)
+GEN_VEXT_VMV_VV(vmv_v_v_d, int64_t, H8, clearq)
+
+#define GEN_VEXT_VMV_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ *((ETYPE *)vd + H(i)) = (ETYPE)s1; \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_VMV_VX(vmv_v_x_b, int8_t, H1, clearb)
+GEN_VEXT_VMV_VX(vmv_v_x_h, int16_t, H2, clearh)
+GEN_VEXT_VMV_VX(vmv_v_x_w, int32_t, H4, clearl)
+GEN_VEXT_VMV_VX(vmv_v_x_d, int64_t, H8, clearq)
+
+#define GEN_VEXT_VMERGE_VV(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE *vt = (!vext_elem_mask(v0, mlen, i) ? vs2 : vs1); \
+ *((ETYPE *)vd + H(i)) = *(vt + H(i)); \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_VMERGE_VV(vmerge_vvm_b, int8_t, H1, clearb)
+GEN_VEXT_VMERGE_VV(vmerge_vvm_h, int16_t, H2, clearh)
+GEN_VEXT_VMERGE_VV(vmerge_vvm_w, int32_t, H4, clearl)
+GEN_VEXT_VMERGE_VV(vmerge_vvm_d, int64_t, H8, clearq)
+
+#define GEN_VEXT_VMERGE_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ ETYPE d = (!vext_elem_mask(v0, mlen, i) ? s2 : \
+ (ETYPE)(target_long)s1); \
+ *((ETYPE *)vd + H(i)) = d; \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VEXT_VMERGE_VX(vmerge_vxm_b, int8_t, H1, clearb)
+GEN_VEXT_VMERGE_VX(vmerge_vxm_h, int16_t, H2, clearh)
+GEN_VEXT_VMERGE_VX(vmerge_vxm_w, int32_t, H4, clearl)
+GEN_VEXT_VMERGE_VX(vmerge_vxm_d, int64_t, H8, clearq)
+
+/*
+ *** Vector Fixed-Point Arithmetic Instructions
+ */
+
+/* Vector Single-Width Saturating Add and Subtract */
+
+/*
+ * As fixed point instructions probably have round mode and saturation,
+ * define common macros for fixed point here.
+ */
+typedef void opivv2_rm_fn(void *vd, void *vs1, void *vs2, int i,
+ CPURISCVState *env, int vxrm);
+
+#define OPIVV2_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
+static inline void \
+do_##NAME(void *vd, void *vs1, void *vs2, int i, \
+ CPURISCVState *env, int vxrm) \
+{ \
+ TX1 s1 = *((T1 *)vs1 + HS1(i)); \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(env, vxrm, s2, s1); \
+}
+
+static inline void
+vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2,
+ CPURISCVState *env,
+ uint32_t vl, uint32_t vm, uint32_t mlen, int vxrm,
+ opivv2_rm_fn *fn)
+{
+ for (uint32_t i = 0; i < vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ fn(vd, vs1, vs2, i, env, vxrm);
+ }
+}
+
+static inline void
+vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2,
+ CPURISCVState *env,
+ uint32_t desc, uint32_t esz, uint32_t dsz,
+ opivv2_rm_fn *fn, clear_fn *clearfn)
+{
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+
+ switch (env->vxrm) {
+ case 0: /* rnu */
+ vext_vv_rm_1(vd, v0, vs1, vs2,
+ env, vl, vm, mlen, 0, fn);
+ break;
+ case 1: /* rne */
+ vext_vv_rm_1(vd, v0, vs1, vs2,
+ env, vl, vm, mlen, 1, fn);
+ break;
+ case 2: /* rdn */
+ vext_vv_rm_1(vd, v0, vs1, vs2,
+ env, vl, vm, mlen, 2, fn);
+ break;
+ default: /* rod */
+ vext_vv_rm_1(vd, v0, vs1, vs2,
+ env, vl, vm, mlen, 3, fn);
+ break;
+ }
+
+ clearfn(vd, vl, vl * dsz, vlmax * dsz);
+}
+
+/* generate helpers for fixed point instructions with OPIVV format */
+#define GEN_VEXT_VV_RM(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_vv_rm_2(vd, v0, vs1, vs2, env, desc, ESZ, DSZ, \
+ do_##NAME, CLEAR_FN); \
+}
+
+static inline uint8_t saddu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b)
+{
+ uint8_t res = a + b;
+ if (res < a) {
+ res = UINT8_MAX;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline uint16_t saddu16(CPURISCVState *env, int vxrm, uint16_t a,
+ uint16_t b)
+{
+ uint16_t res = a + b;
+ if (res < a) {
+ res = UINT16_MAX;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline uint32_t saddu32(CPURISCVState *env, int vxrm, uint32_t a,
+ uint32_t b)
+{
+ uint32_t res = a + b;
+ if (res < a) {
+ res = UINT32_MAX;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline uint64_t saddu64(CPURISCVState *env, int vxrm, uint64_t a,
+ uint64_t b)
+{
+ uint64_t res = a + b;
+ if (res < a) {
+ res = UINT64_MAX;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+RVVCALL(OPIVV2_RM, vsaddu_vv_b, OP_UUU_B, H1, H1, H1, saddu8)
+RVVCALL(OPIVV2_RM, vsaddu_vv_h, OP_UUU_H, H2, H2, H2, saddu16)
+RVVCALL(OPIVV2_RM, vsaddu_vv_w, OP_UUU_W, H4, H4, H4, saddu32)
+RVVCALL(OPIVV2_RM, vsaddu_vv_d, OP_UUU_D, H8, H8, H8, saddu64)
+GEN_VEXT_VV_RM(vsaddu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vsaddu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vsaddu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vsaddu_vv_d, 8, 8, clearq)
+
+typedef void opivx2_rm_fn(void *vd, target_long s1, void *vs2, int i,
+ CPURISCVState *env, int vxrm);
+
+#define OPIVX2_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
+static inline void \
+do_##NAME(void *vd, target_long s1, void *vs2, int i, \
+ CPURISCVState *env, int vxrm) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(env, vxrm, s2, (TX1)(T1)s1); \
+}
+
+static inline void
+vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2,
+ CPURISCVState *env,
+ uint32_t vl, uint32_t vm, uint32_t mlen, int vxrm,
+ opivx2_rm_fn *fn)
+{
+ for (uint32_t i = 0; i < vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ fn(vd, s1, vs2, i, env, vxrm);
+ }
+}
+
+static inline void
+vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2,
+ CPURISCVState *env,
+ uint32_t desc, uint32_t esz, uint32_t dsz,
+ opivx2_rm_fn *fn, clear_fn *clearfn)
+{
+ uint32_t vlmax = vext_maxsz(desc) / esz;
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+
+ switch (env->vxrm) {
+ case 0: /* rnu */
+ vext_vx_rm_1(vd, v0, s1, vs2,
+ env, vl, vm, mlen, 0, fn);
+ break;
+ case 1: /* rne */
+ vext_vx_rm_1(vd, v0, s1, vs2,
+ env, vl, vm, mlen, 1, fn);
+ break;
+ case 2: /* rdn */
+ vext_vx_rm_1(vd, v0, s1, vs2,
+ env, vl, vm, mlen, 2, fn);
+ break;
+ default: /* rod */
+ vext_vx_rm_1(vd, v0, s1, vs2,
+ env, vl, vm, mlen, 3, fn);
+ break;
+ }
+
+ clearfn(vd, vl, vl * dsz, vlmax * dsz);
+}
+
+/* generate helpers for fixed point instructions with OPIVX format */
+#define GEN_VEXT_VX_RM(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ vext_vx_rm_2(vd, v0, s1, vs2, env, desc, ESZ, DSZ, \
+ do_##NAME, CLEAR_FN); \
+}
+
+RVVCALL(OPIVX2_RM, vsaddu_vx_b, OP_UUU_B, H1, H1, saddu8)
+RVVCALL(OPIVX2_RM, vsaddu_vx_h, OP_UUU_H, H2, H2, saddu16)
+RVVCALL(OPIVX2_RM, vsaddu_vx_w, OP_UUU_W, H4, H4, saddu32)
+RVVCALL(OPIVX2_RM, vsaddu_vx_d, OP_UUU_D, H8, H8, saddu64)
+GEN_VEXT_VX_RM(vsaddu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vsaddu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vsaddu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vsaddu_vx_d, 8, 8, clearq)
+
+static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+{
+ int8_t res = a + b;
+ if ((res ^ a) & (res ^ b) & INT8_MIN) {
+ res = a > 0 ? INT8_MAX : INT8_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline int16_t sadd16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
+{
+ int16_t res = a + b;
+ if ((res ^ a) & (res ^ b) & INT16_MIN) {
+ res = a > 0 ? INT16_MAX : INT16_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline int32_t sadd32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+{
+ int32_t res = a + b;
+ if ((res ^ a) & (res ^ b) & INT32_MIN) {
+ res = a > 0 ? INT32_MAX : INT32_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline int64_t sadd64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+{
+ int64_t res = a + b;
+ if ((res ^ a) & (res ^ b) & INT64_MIN) {
+ res = a > 0 ? INT64_MAX : INT64_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+RVVCALL(OPIVV2_RM, vsadd_vv_b, OP_SSS_B, H1, H1, H1, sadd8)
+RVVCALL(OPIVV2_RM, vsadd_vv_h, OP_SSS_H, H2, H2, H2, sadd16)
+RVVCALL(OPIVV2_RM, vsadd_vv_w, OP_SSS_W, H4, H4, H4, sadd32)
+RVVCALL(OPIVV2_RM, vsadd_vv_d, OP_SSS_D, H8, H8, H8, sadd64)
+GEN_VEXT_VV_RM(vsadd_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vsadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vsadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vsadd_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vsadd_vx_b, OP_SSS_B, H1, H1, sadd8)
+RVVCALL(OPIVX2_RM, vsadd_vx_h, OP_SSS_H, H2, H2, sadd16)
+RVVCALL(OPIVX2_RM, vsadd_vx_w, OP_SSS_W, H4, H4, sadd32)
+RVVCALL(OPIVX2_RM, vsadd_vx_d, OP_SSS_D, H8, H8, sadd64)
+GEN_VEXT_VX_RM(vsadd_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vsadd_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vsadd_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vsadd_vx_d, 8, 8, clearq)
+
+static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b)
+{
+ uint8_t res = a - b;
+ if (res > a) {
+ res = 0;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline uint16_t ssubu16(CPURISCVState *env, int vxrm, uint16_t a,
+ uint16_t b)
+{
+ uint16_t res = a - b;
+ if (res > a) {
+ res = 0;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline uint32_t ssubu32(CPURISCVState *env, int vxrm, uint32_t a,
+ uint32_t b)
+{
+ uint32_t res = a - b;
+ if (res > a) {
+ res = 0;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline uint64_t ssubu64(CPURISCVState *env, int vxrm, uint64_t a,
+ uint64_t b)
+{
+ uint64_t res = a - b;
+ if (res > a) {
+ res = 0;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+RVVCALL(OPIVV2_RM, vssubu_vv_b, OP_UUU_B, H1, H1, H1, ssubu8)
+RVVCALL(OPIVV2_RM, vssubu_vv_h, OP_UUU_H, H2, H2, H2, ssubu16)
+RVVCALL(OPIVV2_RM, vssubu_vv_w, OP_UUU_W, H4, H4, H4, ssubu32)
+RVVCALL(OPIVV2_RM, vssubu_vv_d, OP_UUU_D, H8, H8, H8, ssubu64)
+GEN_VEXT_VV_RM(vssubu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vssubu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vssubu_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vssubu_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vssubu_vx_b, OP_UUU_B, H1, H1, ssubu8)
+RVVCALL(OPIVX2_RM, vssubu_vx_h, OP_UUU_H, H2, H2, ssubu16)
+RVVCALL(OPIVX2_RM, vssubu_vx_w, OP_UUU_W, H4, H4, ssubu32)
+RVVCALL(OPIVX2_RM, vssubu_vx_d, OP_UUU_D, H8, H8, ssubu64)
+GEN_VEXT_VX_RM(vssubu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vssubu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vssubu_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vssubu_vx_d, 8, 8, clearq)
+
+static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+{
+ int8_t res = a - b;
+ if ((res ^ a) & (a ^ b) & INT8_MIN) {
+ res = a >= 0 ? INT8_MAX : INT8_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
+{
+ int16_t res = a - b;
+ if ((res ^ a) & (a ^ b) & INT16_MIN) {
+ res = a >= 0 ? INT16_MAX : INT16_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+{
+ int32_t res = a - b;
+ if ((res ^ a) & (a ^ b) & INT32_MIN) {
+ res = a >= 0 ? INT32_MAX : INT32_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+static inline int64_t ssub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+{
+ int64_t res = a - b;
+ if ((res ^ a) & (a ^ b) & INT64_MIN) {
+ res = a >= 0 ? INT64_MAX : INT64_MIN;
+ env->vxsat = 0x1;
+ }
+ return res;
+}
+
+RVVCALL(OPIVV2_RM, vssub_vv_b, OP_SSS_B, H1, H1, H1, ssub8)
+RVVCALL(OPIVV2_RM, vssub_vv_h, OP_SSS_H, H2, H2, H2, ssub16)
+RVVCALL(OPIVV2_RM, vssub_vv_w, OP_SSS_W, H4, H4, H4, ssub32)
+RVVCALL(OPIVV2_RM, vssub_vv_d, OP_SSS_D, H8, H8, H8, ssub64)
+GEN_VEXT_VV_RM(vssub_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vssub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vssub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vssub_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vssub_vx_b, OP_SSS_B, H1, H1, ssub8)
+RVVCALL(OPIVX2_RM, vssub_vx_h, OP_SSS_H, H2, H2, ssub16)
+RVVCALL(OPIVX2_RM, vssub_vx_w, OP_SSS_W, H4, H4, ssub32)
+RVVCALL(OPIVX2_RM, vssub_vx_d, OP_SSS_D, H8, H8, ssub64)
+GEN_VEXT_VX_RM(vssub_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vssub_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vssub_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vssub_vx_d, 8, 8, clearq)
+
+/* Vector Single-Width Averaging Add and Subtract */
+static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift)
+{
+ uint8_t d = extract64(v, shift, 1);
+ uint8_t d1;
+ uint64_t D1, D2;
+
+ if (shift == 0 || shift > 64) {
+ return 0;
+ }
+
+ d1 = extract64(v, shift - 1, 1);
+ D1 = extract64(v, 0, shift);
+ if (vxrm == 0) { /* round-to-nearest-up (add +0.5 LSB) */
+ return d1;
+ } else if (vxrm == 1) { /* round-to-nearest-even */
+ if (shift > 1) {
+ D2 = extract64(v, 0, shift - 1);
+ return d1 & ((D2 != 0) | d);
+ } else {
+ return d1 & d;
+ }
+ } else if (vxrm == 3) { /* round-to-odd (OR bits into LSB, aka "jam") */
+ return !d & (D1 != 0);
+ }
+ return 0; /* round-down (truncate) */
+}
+
+static inline int32_t aadd32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+{
+ int64_t res = (int64_t)a + b;
+ uint8_t round = get_round(vxrm, res, 1);
+
+ return (res >> 1) + round;
+}
+
+static inline int64_t aadd64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+{
+ int64_t res = a + b;
+ uint8_t round = get_round(vxrm, res, 1);
+ int64_t over = (res ^ a) & (res ^ b) & INT64_MIN;
+
+ /* With signed overflow, bit 64 is inverse of bit 63. */
+ return ((res >> 1) ^ over) + round;
+}
+
+RVVCALL(OPIVV2_RM, vaadd_vv_b, OP_SSS_B, H1, H1, H1, aadd32)
+RVVCALL(OPIVV2_RM, vaadd_vv_h, OP_SSS_H, H2, H2, H2, aadd32)
+RVVCALL(OPIVV2_RM, vaadd_vv_w, OP_SSS_W, H4, H4, H4, aadd32)
+RVVCALL(OPIVV2_RM, vaadd_vv_d, OP_SSS_D, H8, H8, H8, aadd64)
+GEN_VEXT_VV_RM(vaadd_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vaadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vaadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vaadd_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vaadd_vx_b, OP_SSS_B, H1, H1, aadd32)
+RVVCALL(OPIVX2_RM, vaadd_vx_h, OP_SSS_H, H2, H2, aadd32)
+RVVCALL(OPIVX2_RM, vaadd_vx_w, OP_SSS_W, H4, H4, aadd32)
+RVVCALL(OPIVX2_RM, vaadd_vx_d, OP_SSS_D, H8, H8, aadd64)
+GEN_VEXT_VX_RM(vaadd_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vaadd_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vaadd_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vaadd_vx_d, 8, 8, clearq)
+
+static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+{
+ int64_t res = (int64_t)a - b;
+ uint8_t round = get_round(vxrm, res, 1);
+
+ return (res >> 1) + round;
+}
+
+static inline int64_t asub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+{
+ int64_t res = (int64_t)a - b;
+ uint8_t round = get_round(vxrm, res, 1);
+ int64_t over = (res ^ a) & (a ^ b) & INT64_MIN;
+
+ /* With signed overflow, bit 64 is inverse of bit 63. */
+ return ((res >> 1) ^ over) + round;
+}
+
+RVVCALL(OPIVV2_RM, vasub_vv_b, OP_SSS_B, H1, H1, H1, asub32)
+RVVCALL(OPIVV2_RM, vasub_vv_h, OP_SSS_H, H2, H2, H2, asub32)
+RVVCALL(OPIVV2_RM, vasub_vv_w, OP_SSS_W, H4, H4, H4, asub32)
+RVVCALL(OPIVV2_RM, vasub_vv_d, OP_SSS_D, H8, H8, H8, asub64)
+GEN_VEXT_VV_RM(vasub_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vasub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vasub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vasub_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vasub_vx_b, OP_SSS_B, H1, H1, asub32)
+RVVCALL(OPIVX2_RM, vasub_vx_h, OP_SSS_H, H2, H2, asub32)
+RVVCALL(OPIVX2_RM, vasub_vx_w, OP_SSS_W, H4, H4, asub32)
+RVVCALL(OPIVX2_RM, vasub_vx_d, OP_SSS_D, H8, H8, asub64)
+GEN_VEXT_VX_RM(vasub_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vasub_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vasub_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vasub_vx_d, 8, 8, clearq)
+
+/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
+static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+{
+ uint8_t round;
+ int16_t res;
+
+ res = (int16_t)a * (int16_t)b;
+ round = get_round(vxrm, res, 7);
+ res = (res >> 7) + round;
+
+ if (res > INT8_MAX) {
+ env->vxsat = 0x1;
+ return INT8_MAX;
+ } else if (res < INT8_MIN) {
+ env->vxsat = 0x1;
+ return INT8_MIN;
+ } else {
+ return res;
+ }
+}
+
+static int16_t vsmul16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
+{
+ uint8_t round;
+ int32_t res;
+
+ res = (int32_t)a * (int32_t)b;
+ round = get_round(vxrm, res, 15);
+ res = (res >> 15) + round;
+
+ if (res > INT16_MAX) {
+ env->vxsat = 0x1;
+ return INT16_MAX;
+ } else if (res < INT16_MIN) {
+ env->vxsat = 0x1;
+ return INT16_MIN;
+ } else {
+ return res;
+ }
+}
+
+static int32_t vsmul32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+{
+ uint8_t round;
+ int64_t res;
+
+ res = (int64_t)a * (int64_t)b;
+ round = get_round(vxrm, res, 31);
+ res = (res >> 31) + round;
+
+ if (res > INT32_MAX) {
+ env->vxsat = 0x1;
+ return INT32_MAX;
+ } else if (res < INT32_MIN) {
+ env->vxsat = 0x1;
+ return INT32_MIN;
+ } else {
+ return res;
+ }
+}
+
+static int64_t vsmul64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+{
+ uint8_t round;
+ uint64_t hi_64, lo_64;
+ int64_t res;
+
+ if (a == INT64_MIN && b == INT64_MIN) {
+ env->vxsat = 1;
+ return INT64_MAX;
+ }
+
+ muls64(&lo_64, &hi_64, a, b);
+ round = get_round(vxrm, lo_64, 63);
+ /*
+ * Cannot overflow, as there are always
+ * 2 sign bits after multiply.
+ */
+ res = (hi_64 << 1) | (lo_64 >> 63);
+ if (round) {
+ if (res == INT64_MAX) {
+ env->vxsat = 1;
+ } else {
+ res += 1;
+ }
+ }
+ return res;
+}
+
+RVVCALL(OPIVV2_RM, vsmul_vv_b, OP_SSS_B, H1, H1, H1, vsmul8)
+RVVCALL(OPIVV2_RM, vsmul_vv_h, OP_SSS_H, H2, H2, H2, vsmul16)
+RVVCALL(OPIVV2_RM, vsmul_vv_w, OP_SSS_W, H4, H4, H4, vsmul32)
+RVVCALL(OPIVV2_RM, vsmul_vv_d, OP_SSS_D, H8, H8, H8, vsmul64)
+GEN_VEXT_VV_RM(vsmul_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vsmul_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vsmul_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vsmul_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vsmul_vx_b, OP_SSS_B, H1, H1, vsmul8)
+RVVCALL(OPIVX2_RM, vsmul_vx_h, OP_SSS_H, H2, H2, vsmul16)
+RVVCALL(OPIVX2_RM, vsmul_vx_w, OP_SSS_W, H4, H4, vsmul32)
+RVVCALL(OPIVX2_RM, vsmul_vx_d, OP_SSS_D, H8, H8, vsmul64)
+GEN_VEXT_VX_RM(vsmul_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vsmul_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vsmul_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vsmul_vx_d, 8, 8, clearq)
+
+/* Vector Widening Saturating Scaled Multiply-Add */
+static inline uint16_t
+vwsmaccu8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b,
+ uint16_t c)
+{
+ uint8_t round;
+ uint16_t res = (uint16_t)a * b;
+
+ round = get_round(vxrm, res, 4);
+ res = (res >> 4) + round;
+ return saddu16(env, vxrm, c, res);
+}
+
+static inline uint32_t
+vwsmaccu16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b,
+ uint32_t c)
+{
+ uint8_t round;
+ uint32_t res = (uint32_t)a * b;
+
+ round = get_round(vxrm, res, 8);
+ res = (res >> 8) + round;
+ return saddu32(env, vxrm, c, res);
+}
+
+static inline uint64_t
+vwsmaccu32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b,
+ uint64_t c)
+{
+ uint8_t round;
+ uint64_t res = (uint64_t)a * b;
+
+ round = get_round(vxrm, res, 16);
+ res = (res >> 16) + round;
+ return saddu64(env, vxrm, c, res);
+}
+
+#define OPIVV3_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
+static inline void \
+do_##NAME(void *vd, void *vs1, void *vs2, int i, \
+ CPURISCVState *env, int vxrm) \
+{ \
+ TX1 s1 = *((T1 *)vs1 + HS1(i)); \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ TD d = *((TD *)vd + HD(i)); \
+ *((TD *)vd + HD(i)) = OP(env, vxrm, s2, s1, d); \
+}
+
+RVVCALL(OPIVV3_RM, vwsmaccu_vv_b, WOP_UUU_B, H2, H1, H1, vwsmaccu8)
+RVVCALL(OPIVV3_RM, vwsmaccu_vv_h, WOP_UUU_H, H4, H2, H2, vwsmaccu16)
+RVVCALL(OPIVV3_RM, vwsmaccu_vv_w, WOP_UUU_W, H8, H4, H4, vwsmaccu32)
+GEN_VEXT_VV_RM(vwsmaccu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV_RM(vwsmaccu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_RM(vwsmaccu_vv_w, 4, 8, clearq)
+
+#define OPIVX3_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
+static inline void \
+do_##NAME(void *vd, target_long s1, void *vs2, int i, \
+ CPURISCVState *env, int vxrm) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ TD d = *((TD *)vd + HD(i)); \
+ *((TD *)vd + HD(i)) = OP(env, vxrm, s2, (TX1)(T1)s1, d); \
+}
+
+RVVCALL(OPIVX3_RM, vwsmaccu_vx_b, WOP_UUU_B, H2, H1, vwsmaccu8)
+RVVCALL(OPIVX3_RM, vwsmaccu_vx_h, WOP_UUU_H, H4, H2, vwsmaccu16)
+RVVCALL(OPIVX3_RM, vwsmaccu_vx_w, WOP_UUU_W, H8, H4, vwsmaccu32)
+GEN_VEXT_VX_RM(vwsmaccu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX_RM(vwsmaccu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX_RM(vwsmaccu_vx_w, 4, 8, clearq)
+
+static inline int16_t
+vwsmacc8(CPURISCVState *env, int vxrm, int8_t a, int8_t b, int16_t c)
+{
+ uint8_t round;
+ int16_t res = (int16_t)a * b;
+
+ round = get_round(vxrm, res, 4);
+ res = (res >> 4) + round;
+ return sadd16(env, vxrm, c, res);
+}
+
+static inline int32_t
+vwsmacc16(CPURISCVState *env, int vxrm, int16_t a, int16_t b, int32_t c)
+{
+ uint8_t round;
+ int32_t res = (int32_t)a * b;
+
+ round = get_round(vxrm, res, 8);
+ res = (res >> 8) + round;
+ return sadd32(env, vxrm, c, res);
+
+}
+
+static inline int64_t
+vwsmacc32(CPURISCVState *env, int vxrm, int32_t a, int32_t b, int64_t c)
+{
+ uint8_t round;
+ int64_t res = (int64_t)a * b;
+
+ round = get_round(vxrm, res, 16);
+ res = (res >> 16) + round;
+ return sadd64(env, vxrm, c, res);
+}
+
+RVVCALL(OPIVV3_RM, vwsmacc_vv_b, WOP_SSS_B, H2, H1, H1, vwsmacc8)
+RVVCALL(OPIVV3_RM, vwsmacc_vv_h, WOP_SSS_H, H4, H2, H2, vwsmacc16)
+RVVCALL(OPIVV3_RM, vwsmacc_vv_w, WOP_SSS_W, H8, H4, H4, vwsmacc32)
+GEN_VEXT_VV_RM(vwsmacc_vv_b, 1, 2, clearh)
+GEN_VEXT_VV_RM(vwsmacc_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_RM(vwsmacc_vv_w, 4, 8, clearq)
+RVVCALL(OPIVX3_RM, vwsmacc_vx_b, WOP_SSS_B, H2, H1, vwsmacc8)
+RVVCALL(OPIVX3_RM, vwsmacc_vx_h, WOP_SSS_H, H4, H2, vwsmacc16)
+RVVCALL(OPIVX3_RM, vwsmacc_vx_w, WOP_SSS_W, H8, H4, vwsmacc32)
+GEN_VEXT_VX_RM(vwsmacc_vx_b, 1, 2, clearh)
+GEN_VEXT_VX_RM(vwsmacc_vx_h, 2, 4, clearl)
+GEN_VEXT_VX_RM(vwsmacc_vx_w, 4, 8, clearq)
+
+static inline int16_t
+vwsmaccsu8(CPURISCVState *env, int vxrm, uint8_t a, int8_t b, int16_t c)
+{
+ uint8_t round;
+ int16_t res = a * (int16_t)b;
+
+ round = get_round(vxrm, res, 4);
+ res = (res >> 4) + round;
+ return ssub16(env, vxrm, c, res);
+}
+
+static inline int32_t
+vwsmaccsu16(CPURISCVState *env, int vxrm, uint16_t a, int16_t b, uint32_t c)
+{
+ uint8_t round;
+ int32_t res = a * (int32_t)b;
+
+ round = get_round(vxrm, res, 8);
+ res = (res >> 8) + round;
+ return ssub32(env, vxrm, c, res);
+}
+
+static inline int64_t
+vwsmaccsu32(CPURISCVState *env, int vxrm, uint32_t a, int32_t b, int64_t c)
+{
+ uint8_t round;
+ int64_t res = a * (int64_t)b;
+
+ round = get_round(vxrm, res, 16);
+ res = (res >> 16) + round;
+ return ssub64(env, vxrm, c, res);
+}
+
+RVVCALL(OPIVV3_RM, vwsmaccsu_vv_b, WOP_SSU_B, H2, H1, H1, vwsmaccsu8)
+RVVCALL(OPIVV3_RM, vwsmaccsu_vv_h, WOP_SSU_H, H4, H2, H2, vwsmaccsu16)
+RVVCALL(OPIVV3_RM, vwsmaccsu_vv_w, WOP_SSU_W, H8, H4, H4, vwsmaccsu32)
+GEN_VEXT_VV_RM(vwsmaccsu_vv_b, 1, 2, clearh)
+GEN_VEXT_VV_RM(vwsmaccsu_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_RM(vwsmaccsu_vv_w, 4, 8, clearq)
+RVVCALL(OPIVX3_RM, vwsmaccsu_vx_b, WOP_SSU_B, H2, H1, vwsmaccsu8)
+RVVCALL(OPIVX3_RM, vwsmaccsu_vx_h, WOP_SSU_H, H4, H2, vwsmaccsu16)
+RVVCALL(OPIVX3_RM, vwsmaccsu_vx_w, WOP_SSU_W, H8, H4, vwsmaccsu32)
+GEN_VEXT_VX_RM(vwsmaccsu_vx_b, 1, 2, clearh)
+GEN_VEXT_VX_RM(vwsmaccsu_vx_h, 2, 4, clearl)
+GEN_VEXT_VX_RM(vwsmaccsu_vx_w, 4, 8, clearq)
+
+static inline int16_t
+vwsmaccus8(CPURISCVState *env, int vxrm, int8_t a, uint8_t b, int16_t c)
+{
+ uint8_t round;
+ int16_t res = (int16_t)a * b;
+
+ round = get_round(vxrm, res, 4);
+ res = (res >> 4) + round;
+ return ssub16(env, vxrm, c, res);
+}
+
+static inline int32_t
+vwsmaccus16(CPURISCVState *env, int vxrm, int16_t a, uint16_t b, int32_t c)
+{
+ uint8_t round;
+ int32_t res = (int32_t)a * b;
+
+ round = get_round(vxrm, res, 8);
+ res = (res >> 8) + round;
+ return ssub32(env, vxrm, c, res);
+}
+
+static inline int64_t
+vwsmaccus32(CPURISCVState *env, int vxrm, int32_t a, uint32_t b, int64_t c)
+{
+ uint8_t round;
+ int64_t res = (int64_t)a * b;
+
+ round = get_round(vxrm, res, 16);
+ res = (res >> 16) + round;
+ return ssub64(env, vxrm, c, res);
+}
+
+RVVCALL(OPIVX3_RM, vwsmaccus_vx_b, WOP_SUS_B, H2, H1, vwsmaccus8)
+RVVCALL(OPIVX3_RM, vwsmaccus_vx_h, WOP_SUS_H, H4, H2, vwsmaccus16)
+RVVCALL(OPIVX3_RM, vwsmaccus_vx_w, WOP_SUS_W, H8, H4, vwsmaccus32)
+GEN_VEXT_VX_RM(vwsmaccus_vx_b, 1, 2, clearh)
+GEN_VEXT_VX_RM(vwsmaccus_vx_h, 2, 4, clearl)
+GEN_VEXT_VX_RM(vwsmaccus_vx_w, 4, 8, clearq)
+
+/* Vector Single-Width Scaling Shift Instructions */
+static inline uint8_t
+vssrl8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b)
+{
+ uint8_t round, shift = b & 0x7;
+ uint8_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+static inline uint16_t
+vssrl16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b)
+{
+ uint8_t round, shift = b & 0xf;
+ uint16_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+static inline uint32_t
+vssrl32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b)
+{
+ uint8_t round, shift = b & 0x1f;
+ uint32_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+static inline uint64_t
+vssrl64(CPURISCVState *env, int vxrm, uint64_t a, uint64_t b)
+{
+ uint8_t round, shift = b & 0x3f;
+ uint64_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+RVVCALL(OPIVV2_RM, vssrl_vv_b, OP_UUU_B, H1, H1, H1, vssrl8)
+RVVCALL(OPIVV2_RM, vssrl_vv_h, OP_UUU_H, H2, H2, H2, vssrl16)
+RVVCALL(OPIVV2_RM, vssrl_vv_w, OP_UUU_W, H4, H4, H4, vssrl32)
+RVVCALL(OPIVV2_RM, vssrl_vv_d, OP_UUU_D, H8, H8, H8, vssrl64)
+GEN_VEXT_VV_RM(vssrl_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vssrl_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vssrl_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vssrl_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vssrl_vx_b, OP_UUU_B, H1, H1, vssrl8)
+RVVCALL(OPIVX2_RM, vssrl_vx_h, OP_UUU_H, H2, H2, vssrl16)
+RVVCALL(OPIVX2_RM, vssrl_vx_w, OP_UUU_W, H4, H4, vssrl32)
+RVVCALL(OPIVX2_RM, vssrl_vx_d, OP_UUU_D, H8, H8, vssrl64)
+GEN_VEXT_VX_RM(vssrl_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vssrl_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vssrl_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vssrl_vx_d, 8, 8, clearq)
+
+static inline int8_t
+vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+{
+ uint8_t round, shift = b & 0x7;
+ int8_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+static inline int16_t
+vssra16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
+{
+ uint8_t round, shift = b & 0xf;
+ int16_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+static inline int32_t
+vssra32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+{
+ uint8_t round, shift = b & 0x1f;
+ int32_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+static inline int64_t
+vssra64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+{
+ uint8_t round, shift = b & 0x3f;
+ int64_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ return res;
+}
+
+RVVCALL(OPIVV2_RM, vssra_vv_b, OP_SSS_B, H1, H1, H1, vssra8)
+RVVCALL(OPIVV2_RM, vssra_vv_h, OP_SSS_H, H2, H2, H2, vssra16)
+RVVCALL(OPIVV2_RM, vssra_vv_w, OP_SSS_W, H4, H4, H4, vssra32)
+RVVCALL(OPIVV2_RM, vssra_vv_d, OP_SSS_D, H8, H8, H8, vssra64)
+GEN_VEXT_VV_RM(vssra_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vssra_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vssra_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_RM(vssra_vv_d, 8, 8, clearq)
+
+RVVCALL(OPIVX2_RM, vssra_vx_b, OP_SSS_B, H1, H1, vssra8)
+RVVCALL(OPIVX2_RM, vssra_vx_h, OP_SSS_H, H2, H2, vssra16)
+RVVCALL(OPIVX2_RM, vssra_vx_w, OP_SSS_W, H4, H4, vssra32)
+RVVCALL(OPIVX2_RM, vssra_vx_d, OP_SSS_D, H8, H8, vssra64)
+GEN_VEXT_VX_RM(vssra_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vssra_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vssra_vx_w, 4, 4, clearl)
+GEN_VEXT_VX_RM(vssra_vx_d, 8, 8, clearq)
+
+/* Vector Narrowing Fixed-Point Clip Instructions */
+static inline int8_t
+vnclip8(CPURISCVState *env, int vxrm, int16_t a, int8_t b)
+{
+ uint8_t round, shift = b & 0xf;
+ int16_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ if (res > INT8_MAX) {
+ env->vxsat = 0x1;
+ return INT8_MAX;
+ } else if (res < INT8_MIN) {
+ env->vxsat = 0x1;
+ return INT8_MIN;
+ } else {
+ return res;
+ }
+}
+
+static inline int16_t
+vnclip16(CPURISCVState *env, int vxrm, int32_t a, int16_t b)
+{
+ uint8_t round, shift = b & 0x1f;
+ int32_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ if (res > INT16_MAX) {
+ env->vxsat = 0x1;
+ return INT16_MAX;
+ } else if (res < INT16_MIN) {
+ env->vxsat = 0x1;
+ return INT16_MIN;
+ } else {
+ return res;
+ }
+}
+
+static inline int32_t
+vnclip32(CPURISCVState *env, int vxrm, int64_t a, int32_t b)
+{
+ uint8_t round, shift = b & 0x3f;
+ int64_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ if (res > INT32_MAX) {
+ env->vxsat = 0x1;
+ return INT32_MAX;
+ } else if (res < INT32_MIN) {
+ env->vxsat = 0x1;
+ return INT32_MIN;
+ } else {
+ return res;
+ }
+}
+
+RVVCALL(OPIVV2_RM, vnclip_vv_b, NOP_SSS_B, H1, H2, H1, vnclip8)
+RVVCALL(OPIVV2_RM, vnclip_vv_h, NOP_SSS_H, H2, H4, H2, vnclip16)
+RVVCALL(OPIVV2_RM, vnclip_vv_w, NOP_SSS_W, H4, H8, H4, vnclip32)
+GEN_VEXT_VV_RM(vnclip_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vnclip_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vnclip_vv_w, 4, 4, clearl)
+
+RVVCALL(OPIVX2_RM, vnclip_vx_b, NOP_SSS_B, H1, H2, vnclip8)
+RVVCALL(OPIVX2_RM, vnclip_vx_h, NOP_SSS_H, H2, H4, vnclip16)
+RVVCALL(OPIVX2_RM, vnclip_vx_w, NOP_SSS_W, H4, H8, vnclip32)
+GEN_VEXT_VX_RM(vnclip_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vnclip_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vnclip_vx_w, 4, 4, clearl)
+
+static inline uint8_t
+vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b)
+{
+ uint8_t round, shift = b & 0xf;
+ uint16_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ if (res > UINT8_MAX) {
+ env->vxsat = 0x1;
+ return UINT8_MAX;
+ } else {
+ return res;
+ }
+}
+
+static inline uint16_t
+vnclipu16(CPURISCVState *env, int vxrm, uint32_t a, uint16_t b)
+{
+ uint8_t round, shift = b & 0x1f;
+ uint32_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ if (res > UINT16_MAX) {
+ env->vxsat = 0x1;
+ return UINT16_MAX;
+ } else {
+ return res;
+ }
+}
+
+static inline uint32_t
+vnclipu32(CPURISCVState *env, int vxrm, uint64_t a, uint32_t b)
+{
+ uint8_t round, shift = b & 0x3f;
+ int64_t res;
+
+ round = get_round(vxrm, a, shift);
+ res = (a >> shift) + round;
+ if (res > UINT32_MAX) {
+ env->vxsat = 0x1;
+ return UINT32_MAX;
+ } else {
+ return res;
+ }
+}
+
+RVVCALL(OPIVV2_RM, vnclipu_vv_b, NOP_UUU_B, H1, H2, H1, vnclipu8)
+RVVCALL(OPIVV2_RM, vnclipu_vv_h, NOP_UUU_H, H2, H4, H2, vnclipu16)
+RVVCALL(OPIVV2_RM, vnclipu_vv_w, NOP_UUU_W, H4, H8, H4, vnclipu32)
+GEN_VEXT_VV_RM(vnclipu_vv_b, 1, 1, clearb)
+GEN_VEXT_VV_RM(vnclipu_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_RM(vnclipu_vv_w, 4, 4, clearl)
+
+RVVCALL(OPIVX2_RM, vnclipu_vx_b, NOP_UUU_B, H1, H2, vnclipu8)
+RVVCALL(OPIVX2_RM, vnclipu_vx_h, NOP_UUU_H, H2, H4, vnclipu16)
+RVVCALL(OPIVX2_RM, vnclipu_vx_w, NOP_UUU_W, H4, H8, vnclipu32)
+GEN_VEXT_VX_RM(vnclipu_vx_b, 1, 1, clearb)
+GEN_VEXT_VX_RM(vnclipu_vx_h, 2, 2, clearh)
+GEN_VEXT_VX_RM(vnclipu_vx_w, 4, 4, clearl)
+
+/*
+ *** Vector Float Point Arithmetic Instructions
+ */
+/* Vector Single-Width Floating-Point Add/Subtract Instructions */
+#define OPFVV2(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
+static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \
+ CPURISCVState *env) \
+{ \
+ TX1 s1 = *((T1 *)vs1 + HS1(i)); \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, s1, &env->fp_status); \
+}
+
+#define GEN_VEXT_VV_ENV(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, \
+ void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t vlmax = vext_maxsz(desc) / ESZ; \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ do_##NAME(vd, vs1, vs2, i, env); \
+ } \
+ CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \
+}
+
+RVVCALL(OPFVV2, vfadd_vv_h, OP_UUU_H, H2, H2, H2, float16_add)
+RVVCALL(OPFVV2, vfadd_vv_w, OP_UUU_W, H4, H4, H4, float32_add)
+RVVCALL(OPFVV2, vfadd_vv_d, OP_UUU_D, H8, H8, H8, float64_add)
+GEN_VEXT_VV_ENV(vfadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfadd_vv_d, 8, 8, clearq)
+
+#define OPFVF2(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
+static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \
+ CPURISCVState *env) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, &env->fp_status);\
+}
+
+#define GEN_VEXT_VF(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \
+ void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t vlmax = vext_maxsz(desc) / ESZ; \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ do_##NAME(vd, s1, vs2, i, env); \
+ } \
+ CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \
+}
+
+RVVCALL(OPFVF2, vfadd_vf_h, OP_UUU_H, H2, H2, float16_add)
+RVVCALL(OPFVF2, vfadd_vf_w, OP_UUU_W, H4, H4, float32_add)
+RVVCALL(OPFVF2, vfadd_vf_d, OP_UUU_D, H8, H8, float64_add)
+GEN_VEXT_VF(vfadd_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfadd_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfadd_vf_d, 8, 8, clearq)
+
+RVVCALL(OPFVV2, vfsub_vv_h, OP_UUU_H, H2, H2, H2, float16_sub)
+RVVCALL(OPFVV2, vfsub_vv_w, OP_UUU_W, H4, H4, H4, float32_sub)
+RVVCALL(OPFVV2, vfsub_vv_d, OP_UUU_D, H8, H8, H8, float64_sub)
+GEN_VEXT_VV_ENV(vfsub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfsub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfsub_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfsub_vf_h, OP_UUU_H, H2, H2, float16_sub)
+RVVCALL(OPFVF2, vfsub_vf_w, OP_UUU_W, H4, H4, float32_sub)
+RVVCALL(OPFVF2, vfsub_vf_d, OP_UUU_D, H8, H8, float64_sub)
+GEN_VEXT_VF(vfsub_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfsub_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfsub_vf_d, 8, 8, clearq)
+
+static uint16_t float16_rsub(uint16_t a, uint16_t b, float_status *s)
+{
+ return float16_sub(b, a, s);
+}
+
+static uint32_t float32_rsub(uint32_t a, uint32_t b, float_status *s)
+{
+ return float32_sub(b, a, s);
+}
+
+static uint64_t float64_rsub(uint64_t a, uint64_t b, float_status *s)
+{
+ return float64_sub(b, a, s);
+}
+
+RVVCALL(OPFVF2, vfrsub_vf_h, OP_UUU_H, H2, H2, float16_rsub)
+RVVCALL(OPFVF2, vfrsub_vf_w, OP_UUU_W, H4, H4, float32_rsub)
+RVVCALL(OPFVF2, vfrsub_vf_d, OP_UUU_D, H8, H8, float64_rsub)
+GEN_VEXT_VF(vfrsub_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfrsub_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfrsub_vf_d, 8, 8, clearq)
+
+/* Vector Widening Floating-Point Add/Subtract Instructions */
+static uint32_t vfwadd16(uint16_t a, uint16_t b, float_status *s)
+{
+ return float32_add(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), s);
+}
+
+static uint64_t vfwadd32(uint32_t a, uint32_t b, float_status *s)
+{
+ return float64_add(float32_to_float64(a, s),
+ float32_to_float64(b, s), s);
+
+}
+
+RVVCALL(OPFVV2, vfwadd_vv_h, WOP_UUU_H, H4, H2, H2, vfwadd16)
+RVVCALL(OPFVV2, vfwadd_vv_w, WOP_UUU_W, H8, H4, H4, vfwadd32)
+GEN_VEXT_VV_ENV(vfwadd_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwadd_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF2, vfwadd_vf_h, WOP_UUU_H, H4, H2, vfwadd16)
+RVVCALL(OPFVF2, vfwadd_vf_w, WOP_UUU_W, H8, H4, vfwadd32)
+GEN_VEXT_VF(vfwadd_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwadd_vf_w, 4, 8, clearq)
+
+static uint32_t vfwsub16(uint16_t a, uint16_t b, float_status *s)
+{
+ return float32_sub(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), s);
+}
+
+static uint64_t vfwsub32(uint32_t a, uint32_t b, float_status *s)
+{
+ return float64_sub(float32_to_float64(a, s),
+ float32_to_float64(b, s), s);
+
+}
+
+RVVCALL(OPFVV2, vfwsub_vv_h, WOP_UUU_H, H4, H2, H2, vfwsub16)
+RVVCALL(OPFVV2, vfwsub_vv_w, WOP_UUU_W, H8, H4, H4, vfwsub32)
+GEN_VEXT_VV_ENV(vfwsub_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwsub_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF2, vfwsub_vf_h, WOP_UUU_H, H4, H2, vfwsub16)
+RVVCALL(OPFVF2, vfwsub_vf_w, WOP_UUU_W, H8, H4, vfwsub32)
+GEN_VEXT_VF(vfwsub_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwsub_vf_w, 4, 8, clearq)
+
+static uint32_t vfwaddw16(uint32_t a, uint16_t b, float_status *s)
+{
+ return float32_add(a, float16_to_float32(b, true, s), s);
+}
+
+static uint64_t vfwaddw32(uint64_t a, uint32_t b, float_status *s)
+{
+ return float64_add(a, float32_to_float64(b, s), s);
+}
+
+RVVCALL(OPFVV2, vfwadd_wv_h, WOP_WUUU_H, H4, H2, H2, vfwaddw16)
+RVVCALL(OPFVV2, vfwadd_wv_w, WOP_WUUU_W, H8, H4, H4, vfwaddw32)
+GEN_VEXT_VV_ENV(vfwadd_wv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwadd_wv_w, 4, 8, clearq)
+RVVCALL(OPFVF2, vfwadd_wf_h, WOP_WUUU_H, H4, H2, vfwaddw16)
+RVVCALL(OPFVF2, vfwadd_wf_w, WOP_WUUU_W, H8, H4, vfwaddw32)
+GEN_VEXT_VF(vfwadd_wf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwadd_wf_w, 4, 8, clearq)
+
+static uint32_t vfwsubw16(uint32_t a, uint16_t b, float_status *s)
+{
+ return float32_sub(a, float16_to_float32(b, true, s), s);
+}
+
+static uint64_t vfwsubw32(uint64_t a, uint32_t b, float_status *s)
+{
+ return float64_sub(a, float32_to_float64(b, s), s);
+}
+
+RVVCALL(OPFVV2, vfwsub_wv_h, WOP_WUUU_H, H4, H2, H2, vfwsubw16)
+RVVCALL(OPFVV2, vfwsub_wv_w, WOP_WUUU_W, H8, H4, H4, vfwsubw32)
+GEN_VEXT_VV_ENV(vfwsub_wv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwsub_wv_w, 4, 8, clearq)
+RVVCALL(OPFVF2, vfwsub_wf_h, WOP_WUUU_H, H4, H2, vfwsubw16)
+RVVCALL(OPFVF2, vfwsub_wf_w, WOP_WUUU_W, H8, H4, vfwsubw32)
+GEN_VEXT_VF(vfwsub_wf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwsub_wf_w, 4, 8, clearq)
+
+/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
+RVVCALL(OPFVV2, vfmul_vv_h, OP_UUU_H, H2, H2, H2, float16_mul)
+RVVCALL(OPFVV2, vfmul_vv_w, OP_UUU_W, H4, H4, H4, float32_mul)
+RVVCALL(OPFVV2, vfmul_vv_d, OP_UUU_D, H8, H8, H8, float64_mul)
+GEN_VEXT_VV_ENV(vfmul_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmul_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmul_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfmul_vf_h, OP_UUU_H, H2, H2, float16_mul)
+RVVCALL(OPFVF2, vfmul_vf_w, OP_UUU_W, H4, H4, float32_mul)
+RVVCALL(OPFVF2, vfmul_vf_d, OP_UUU_D, H8, H8, float64_mul)
+GEN_VEXT_VF(vfmul_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmul_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmul_vf_d, 8, 8, clearq)
+
+RVVCALL(OPFVV2, vfdiv_vv_h, OP_UUU_H, H2, H2, H2, float16_div)
+RVVCALL(OPFVV2, vfdiv_vv_w, OP_UUU_W, H4, H4, H4, float32_div)
+RVVCALL(OPFVV2, vfdiv_vv_d, OP_UUU_D, H8, H8, H8, float64_div)
+GEN_VEXT_VV_ENV(vfdiv_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfdiv_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfdiv_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfdiv_vf_h, OP_UUU_H, H2, H2, float16_div)
+RVVCALL(OPFVF2, vfdiv_vf_w, OP_UUU_W, H4, H4, float32_div)
+RVVCALL(OPFVF2, vfdiv_vf_d, OP_UUU_D, H8, H8, float64_div)
+GEN_VEXT_VF(vfdiv_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfdiv_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfdiv_vf_d, 8, 8, clearq)
+
+static uint16_t float16_rdiv(uint16_t a, uint16_t b, float_status *s)
+{
+ return float16_div(b, a, s);
+}
+
+static uint32_t float32_rdiv(uint32_t a, uint32_t b, float_status *s)
+{
+ return float32_div(b, a, s);
+}
+
+static uint64_t float64_rdiv(uint64_t a, uint64_t b, float_status *s)
+{
+ return float64_div(b, a, s);
+}
+
+RVVCALL(OPFVF2, vfrdiv_vf_h, OP_UUU_H, H2, H2, float16_rdiv)
+RVVCALL(OPFVF2, vfrdiv_vf_w, OP_UUU_W, H4, H4, float32_rdiv)
+RVVCALL(OPFVF2, vfrdiv_vf_d, OP_UUU_D, H8, H8, float64_rdiv)
+GEN_VEXT_VF(vfrdiv_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfrdiv_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfrdiv_vf_d, 8, 8, clearq)
+
+/* Vector Widening Floating-Point Multiply */
+static uint32_t vfwmul16(uint16_t a, uint16_t b, float_status *s)
+{
+ return float32_mul(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), s);
+}
+
+static uint64_t vfwmul32(uint32_t a, uint32_t b, float_status *s)
+{
+ return float64_mul(float32_to_float64(a, s),
+ float32_to_float64(b, s), s);
+
+}
+RVVCALL(OPFVV2, vfwmul_vv_h, WOP_UUU_H, H4, H2, H2, vfwmul16)
+RVVCALL(OPFVV2, vfwmul_vv_w, WOP_UUU_W, H8, H4, H4, vfwmul32)
+GEN_VEXT_VV_ENV(vfwmul_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwmul_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF2, vfwmul_vf_h, WOP_UUU_H, H4, H2, vfwmul16)
+RVVCALL(OPFVF2, vfwmul_vf_w, WOP_UUU_W, H8, H4, vfwmul32)
+GEN_VEXT_VF(vfwmul_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwmul_vf_w, 4, 8, clearq)
+
+/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
+#define OPFVV3(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP) \
+static void do_##NAME(void *vd, void *vs1, void *vs2, int i, \
+ CPURISCVState *env) \
+{ \
+ TX1 s1 = *((T1 *)vs1 + HS1(i)); \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ TD d = *((TD *)vd + HD(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, s1, d, &env->fp_status); \
+}
+
+static uint16_t fmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(a, b, d, 0, s);
+}
+
+static uint32_t fmacc32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(a, b, d, 0, s);
+}
+
+static uint64_t fmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(a, b, d, 0, s);
+}
+
+RVVCALL(OPFVV3, vfmacc_vv_h, OP_UUU_H, H2, H2, H2, fmacc16)
+RVVCALL(OPFVV3, vfmacc_vv_w, OP_UUU_W, H4, H4, H4, fmacc32)
+RVVCALL(OPFVV3, vfmacc_vv_d, OP_UUU_D, H8, H8, H8, fmacc64)
+GEN_VEXT_VV_ENV(vfmacc_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmacc_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmacc_vv_d, 8, 8, clearq)
+
+#define OPFVF3(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP) \
+static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \
+ CPURISCVState *env) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ TD d = *((TD *)vd + HD(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, d, &env->fp_status);\
+}
+
+RVVCALL(OPFVF3, vfmacc_vf_h, OP_UUU_H, H2, H2, fmacc16)
+RVVCALL(OPFVF3, vfmacc_vf_w, OP_UUU_W, H4, H4, fmacc32)
+RVVCALL(OPFVF3, vfmacc_vf_d, OP_UUU_D, H8, H8, fmacc64)
+GEN_VEXT_VF(vfmacc_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmacc_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmacc_vf_d, 8, 8, clearq)
+
+static uint16_t fnmacc16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(a, b, d,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+static uint32_t fnmacc32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(a, b, d,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+static uint64_t fnmacc64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(a, b, d,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+RVVCALL(OPFVV3, vfnmacc_vv_h, OP_UUU_H, H2, H2, H2, fnmacc16)
+RVVCALL(OPFVV3, vfnmacc_vv_w, OP_UUU_W, H4, H4, H4, fnmacc32)
+RVVCALL(OPFVV3, vfnmacc_vv_d, OP_UUU_D, H8, H8, H8, fnmacc64)
+GEN_VEXT_VV_ENV(vfnmacc_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfnmacc_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfnmacc_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfnmacc_vf_h, OP_UUU_H, H2, H2, fnmacc16)
+RVVCALL(OPFVF3, vfnmacc_vf_w, OP_UUU_W, H4, H4, fnmacc32)
+RVVCALL(OPFVF3, vfnmacc_vf_d, OP_UUU_D, H8, H8, fnmacc64)
+GEN_VEXT_VF(vfnmacc_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfnmacc_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfnmacc_vf_d, 8, 8, clearq)
+
+static uint16_t fmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(a, b, d, float_muladd_negate_c, s);
+}
+
+static uint32_t fmsac32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(a, b, d, float_muladd_negate_c, s);
+}
+
+static uint64_t fmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(a, b, d, float_muladd_negate_c, s);
+}
+
+RVVCALL(OPFVV3, vfmsac_vv_h, OP_UUU_H, H2, H2, H2, fmsac16)
+RVVCALL(OPFVV3, vfmsac_vv_w, OP_UUU_W, H4, H4, H4, fmsac32)
+RVVCALL(OPFVV3, vfmsac_vv_d, OP_UUU_D, H8, H8, H8, fmsac64)
+GEN_VEXT_VV_ENV(vfmsac_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmsac_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmsac_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfmsac_vf_h, OP_UUU_H, H2, H2, fmsac16)
+RVVCALL(OPFVF3, vfmsac_vf_w, OP_UUU_W, H4, H4, fmsac32)
+RVVCALL(OPFVF3, vfmsac_vf_d, OP_UUU_D, H8, H8, fmsac64)
+GEN_VEXT_VF(vfmsac_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmsac_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmsac_vf_d, 8, 8, clearq)
+
+static uint16_t fnmsac16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(a, b, d, float_muladd_negate_product, s);
+}
+
+static uint32_t fnmsac32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(a, b, d, float_muladd_negate_product, s);
+}
+
+static uint64_t fnmsac64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(a, b, d, float_muladd_negate_product, s);
+}
+
+RVVCALL(OPFVV3, vfnmsac_vv_h, OP_UUU_H, H2, H2, H2, fnmsac16)
+RVVCALL(OPFVV3, vfnmsac_vv_w, OP_UUU_W, H4, H4, H4, fnmsac32)
+RVVCALL(OPFVV3, vfnmsac_vv_d, OP_UUU_D, H8, H8, H8, fnmsac64)
+GEN_VEXT_VV_ENV(vfnmsac_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfnmsac_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfnmsac_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfnmsac_vf_h, OP_UUU_H, H2, H2, fnmsac16)
+RVVCALL(OPFVF3, vfnmsac_vf_w, OP_UUU_W, H4, H4, fnmsac32)
+RVVCALL(OPFVF3, vfnmsac_vf_d, OP_UUU_D, H8, H8, fnmsac64)
+GEN_VEXT_VF(vfnmsac_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfnmsac_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfnmsac_vf_d, 8, 8, clearq)
+
+static uint16_t fmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(d, b, a, 0, s);
+}
+
+static uint32_t fmadd32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(d, b, a, 0, s);
+}
+
+static uint64_t fmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(d, b, a, 0, s);
+}
+
+RVVCALL(OPFVV3, vfmadd_vv_h, OP_UUU_H, H2, H2, H2, fmadd16)
+RVVCALL(OPFVV3, vfmadd_vv_w, OP_UUU_W, H4, H4, H4, fmadd32)
+RVVCALL(OPFVV3, vfmadd_vv_d, OP_UUU_D, H8, H8, H8, fmadd64)
+GEN_VEXT_VV_ENV(vfmadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmadd_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfmadd_vf_h, OP_UUU_H, H2, H2, fmadd16)
+RVVCALL(OPFVF3, vfmadd_vf_w, OP_UUU_W, H4, H4, fmadd32)
+RVVCALL(OPFVF3, vfmadd_vf_d, OP_UUU_D, H8, H8, fmadd64)
+GEN_VEXT_VF(vfmadd_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmadd_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmadd_vf_d, 8, 8, clearq)
+
+static uint16_t fnmadd16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(d, b, a,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+static uint32_t fnmadd32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(d, b, a,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+static uint64_t fnmadd64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(d, b, a,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+RVVCALL(OPFVV3, vfnmadd_vv_h, OP_UUU_H, H2, H2, H2, fnmadd16)
+RVVCALL(OPFVV3, vfnmadd_vv_w, OP_UUU_W, H4, H4, H4, fnmadd32)
+RVVCALL(OPFVV3, vfnmadd_vv_d, OP_UUU_D, H8, H8, H8, fnmadd64)
+GEN_VEXT_VV_ENV(vfnmadd_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfnmadd_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfnmadd_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfnmadd_vf_h, OP_UUU_H, H2, H2, fnmadd16)
+RVVCALL(OPFVF3, vfnmadd_vf_w, OP_UUU_W, H4, H4, fnmadd32)
+RVVCALL(OPFVF3, vfnmadd_vf_d, OP_UUU_D, H8, H8, fnmadd64)
+GEN_VEXT_VF(vfnmadd_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfnmadd_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfnmadd_vf_d, 8, 8, clearq)
+
+static uint16_t fmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(d, b, a, float_muladd_negate_c, s);
+}
+
+static uint32_t fmsub32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(d, b, a, float_muladd_negate_c, s);
+}
+
+static uint64_t fmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(d, b, a, float_muladd_negate_c, s);
+}
+
+RVVCALL(OPFVV3, vfmsub_vv_h, OP_UUU_H, H2, H2, H2, fmsub16)
+RVVCALL(OPFVV3, vfmsub_vv_w, OP_UUU_W, H4, H4, H4, fmsub32)
+RVVCALL(OPFVV3, vfmsub_vv_d, OP_UUU_D, H8, H8, H8, fmsub64)
+GEN_VEXT_VV_ENV(vfmsub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmsub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmsub_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfmsub_vf_h, OP_UUU_H, H2, H2, fmsub16)
+RVVCALL(OPFVF3, vfmsub_vf_w, OP_UUU_W, H4, H4, fmsub32)
+RVVCALL(OPFVF3, vfmsub_vf_d, OP_UUU_D, H8, H8, fmsub64)
+GEN_VEXT_VF(vfmsub_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmsub_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmsub_vf_d, 8, 8, clearq)
+
+static uint16_t fnmsub16(uint16_t a, uint16_t b, uint16_t d, float_status *s)
+{
+ return float16_muladd(d, b, a, float_muladd_negate_product, s);
+}
+
+static uint32_t fnmsub32(uint32_t a, uint32_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(d, b, a, float_muladd_negate_product, s);
+}
+
+static uint64_t fnmsub64(uint64_t a, uint64_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(d, b, a, float_muladd_negate_product, s);
+}
+
+RVVCALL(OPFVV3, vfnmsub_vv_h, OP_UUU_H, H2, H2, H2, fnmsub16)
+RVVCALL(OPFVV3, vfnmsub_vv_w, OP_UUU_W, H4, H4, H4, fnmsub32)
+RVVCALL(OPFVV3, vfnmsub_vv_d, OP_UUU_D, H8, H8, H8, fnmsub64)
+GEN_VEXT_VV_ENV(vfnmsub_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfnmsub_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfnmsub_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF3, vfnmsub_vf_h, OP_UUU_H, H2, H2, fnmsub16)
+RVVCALL(OPFVF3, vfnmsub_vf_w, OP_UUU_W, H4, H4, fnmsub32)
+RVVCALL(OPFVF3, vfnmsub_vf_d, OP_UUU_D, H8, H8, fnmsub64)
+GEN_VEXT_VF(vfnmsub_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfnmsub_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfnmsub_vf_d, 8, 8, clearq)
+
+/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
+static uint32_t fwmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), d, 0, s);
+}
+
+static uint64_t fwmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(float32_to_float64(a, s),
+ float32_to_float64(b, s), d, 0, s);
+}
+
+RVVCALL(OPFVV3, vfwmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwmacc16)
+RVVCALL(OPFVV3, vfwmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwmacc32)
+GEN_VEXT_VV_ENV(vfwmacc_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwmacc_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF3, vfwmacc_vf_h, WOP_UUU_H, H4, H2, fwmacc16)
+RVVCALL(OPFVF3, vfwmacc_vf_w, WOP_UUU_W, H8, H4, fwmacc32)
+GEN_VEXT_VF(vfwmacc_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwmacc_vf_w, 4, 8, clearq)
+
+static uint32_t fwnmacc16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), d,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+static uint64_t fwnmacc32(uint32_t a, uint32_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(float32_to_float64(a, s),
+ float32_to_float64(b, s), d,
+ float_muladd_negate_c | float_muladd_negate_product, s);
+}
+
+RVVCALL(OPFVV3, vfwnmacc_vv_h, WOP_UUU_H, H4, H2, H2, fwnmacc16)
+RVVCALL(OPFVV3, vfwnmacc_vv_w, WOP_UUU_W, H8, H4, H4, fwnmacc32)
+GEN_VEXT_VV_ENV(vfwnmacc_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwnmacc_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF3, vfwnmacc_vf_h, WOP_UUU_H, H4, H2, fwnmacc16)
+RVVCALL(OPFVF3, vfwnmacc_vf_w, WOP_UUU_W, H8, H4, fwnmacc32)
+GEN_VEXT_VF(vfwnmacc_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwnmacc_vf_w, 4, 8, clearq)
+
+static uint32_t fwmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), d,
+ float_muladd_negate_c, s);
+}
+
+static uint64_t fwmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(float32_to_float64(a, s),
+ float32_to_float64(b, s), d,
+ float_muladd_negate_c, s);
+}
+
+RVVCALL(OPFVV3, vfwmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwmsac16)
+RVVCALL(OPFVV3, vfwmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwmsac32)
+GEN_VEXT_VV_ENV(vfwmsac_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwmsac_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF3, vfwmsac_vf_h, WOP_UUU_H, H4, H2, fwmsac16)
+RVVCALL(OPFVF3, vfwmsac_vf_w, WOP_UUU_W, H8, H4, fwmsac32)
+GEN_VEXT_VF(vfwmsac_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwmsac_vf_w, 4, 8, clearq)
+
+static uint32_t fwnmsac16(uint16_t a, uint16_t b, uint32_t d, float_status *s)
+{
+ return float32_muladd(float16_to_float32(a, true, s),
+ float16_to_float32(b, true, s), d,
+ float_muladd_negate_product, s);
+}
+
+static uint64_t fwnmsac32(uint32_t a, uint32_t b, uint64_t d, float_status *s)
+{
+ return float64_muladd(float32_to_float64(a, s),
+ float32_to_float64(b, s), d,
+ float_muladd_negate_product, s);
+}
+
+RVVCALL(OPFVV3, vfwnmsac_vv_h, WOP_UUU_H, H4, H2, H2, fwnmsac16)
+RVVCALL(OPFVV3, vfwnmsac_vv_w, WOP_UUU_W, H8, H4, H4, fwnmsac32)
+GEN_VEXT_VV_ENV(vfwnmsac_vv_h, 2, 4, clearl)
+GEN_VEXT_VV_ENV(vfwnmsac_vv_w, 4, 8, clearq)
+RVVCALL(OPFVF3, vfwnmsac_vf_h, WOP_UUU_H, H4, H2, fwnmsac16)
+RVVCALL(OPFVF3, vfwnmsac_vf_w, WOP_UUU_W, H8, H4, fwnmsac32)
+GEN_VEXT_VF(vfwnmsac_vf_h, 2, 4, clearl)
+GEN_VEXT_VF(vfwnmsac_vf_w, 4, 8, clearq)
+
+/* Vector Floating-Point Square-Root Instruction */
+/* (TD, T2, TX2) */
+#define OP_UU_H uint16_t, uint16_t, uint16_t
+#define OP_UU_W uint32_t, uint32_t, uint32_t
+#define OP_UU_D uint64_t, uint64_t, uint64_t
+
+#define OPFVV1(NAME, TD, T2, TX2, HD, HS2, OP) \
+static void do_##NAME(void *vd, void *vs2, int i, \
+ CPURISCVState *env) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2, &env->fp_status); \
+}
+
+#define GEN_VEXT_V_ENV(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t vlmax = vext_maxsz(desc) / ESZ; \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ \
+ if (vl == 0) { \
+ return; \
+ } \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ do_##NAME(vd, vs2, i, env); \
+ } \
+ CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \
+}
+
+RVVCALL(OPFVV1, vfsqrt_v_h, OP_UU_H, H2, H2, float16_sqrt)
+RVVCALL(OPFVV1, vfsqrt_v_w, OP_UU_W, H4, H4, float32_sqrt)
+RVVCALL(OPFVV1, vfsqrt_v_d, OP_UU_D, H8, H8, float64_sqrt)
+GEN_VEXT_V_ENV(vfsqrt_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfsqrt_v_w, 4, 4, clearl)
+GEN_VEXT_V_ENV(vfsqrt_v_d, 8, 8, clearq)
+
+/* Vector Floating-Point MIN/MAX Instructions */
+RVVCALL(OPFVV2, vfmin_vv_h, OP_UUU_H, H2, H2, H2, float16_minnum)
+RVVCALL(OPFVV2, vfmin_vv_w, OP_UUU_W, H4, H4, H4, float32_minnum)
+RVVCALL(OPFVV2, vfmin_vv_d, OP_UUU_D, H8, H8, H8, float64_minnum)
+GEN_VEXT_VV_ENV(vfmin_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmin_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmin_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfmin_vf_h, OP_UUU_H, H2, H2, float16_minnum)
+RVVCALL(OPFVF2, vfmin_vf_w, OP_UUU_W, H4, H4, float32_minnum)
+RVVCALL(OPFVF2, vfmin_vf_d, OP_UUU_D, H8, H8, float64_minnum)
+GEN_VEXT_VF(vfmin_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmin_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmin_vf_d, 8, 8, clearq)
+
+RVVCALL(OPFVV2, vfmax_vv_h, OP_UUU_H, H2, H2, H2, float16_maxnum)
+RVVCALL(OPFVV2, vfmax_vv_w, OP_UUU_W, H4, H4, H4, float32_maxnum)
+RVVCALL(OPFVV2, vfmax_vv_d, OP_UUU_D, H8, H8, H8, float64_maxnum)
+GEN_VEXT_VV_ENV(vfmax_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfmax_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfmax_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfmax_vf_h, OP_UUU_H, H2, H2, float16_maxnum)
+RVVCALL(OPFVF2, vfmax_vf_w, OP_UUU_W, H4, H4, float32_maxnum)
+RVVCALL(OPFVF2, vfmax_vf_d, OP_UUU_D, H8, H8, float64_maxnum)
+GEN_VEXT_VF(vfmax_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfmax_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfmax_vf_d, 8, 8, clearq)
+
+/* Vector Floating-Point Sign-Injection Instructions */
+static uint16_t fsgnj16(uint16_t a, uint16_t b, float_status *s)
+{
+ return deposit64(b, 0, 15, a);
+}
+
+static uint32_t fsgnj32(uint32_t a, uint32_t b, float_status *s)
+{
+ return deposit64(b, 0, 31, a);
+}
+
+static uint64_t fsgnj64(uint64_t a, uint64_t b, float_status *s)
+{
+ return deposit64(b, 0, 63, a);
+}
+
+RVVCALL(OPFVV2, vfsgnj_vv_h, OP_UUU_H, H2, H2, H2, fsgnj16)
+RVVCALL(OPFVV2, vfsgnj_vv_w, OP_UUU_W, H4, H4, H4, fsgnj32)
+RVVCALL(OPFVV2, vfsgnj_vv_d, OP_UUU_D, H8, H8, H8, fsgnj64)
+GEN_VEXT_VV_ENV(vfsgnj_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfsgnj_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfsgnj_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfsgnj_vf_h, OP_UUU_H, H2, H2, fsgnj16)
+RVVCALL(OPFVF2, vfsgnj_vf_w, OP_UUU_W, H4, H4, fsgnj32)
+RVVCALL(OPFVF2, vfsgnj_vf_d, OP_UUU_D, H8, H8, fsgnj64)
+GEN_VEXT_VF(vfsgnj_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfsgnj_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfsgnj_vf_d, 8, 8, clearq)
+
+static uint16_t fsgnjn16(uint16_t a, uint16_t b, float_status *s)
+{
+ return deposit64(~b, 0, 15, a);
+}
+
+static uint32_t fsgnjn32(uint32_t a, uint32_t b, float_status *s)
+{
+ return deposit64(~b, 0, 31, a);
+}
+
+static uint64_t fsgnjn64(uint64_t a, uint64_t b, float_status *s)
+{
+ return deposit64(~b, 0, 63, a);
+}
+
+RVVCALL(OPFVV2, vfsgnjn_vv_h, OP_UUU_H, H2, H2, H2, fsgnjn16)
+RVVCALL(OPFVV2, vfsgnjn_vv_w, OP_UUU_W, H4, H4, H4, fsgnjn32)
+RVVCALL(OPFVV2, vfsgnjn_vv_d, OP_UUU_D, H8, H8, H8, fsgnjn64)
+GEN_VEXT_VV_ENV(vfsgnjn_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfsgnjn_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfsgnjn_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfsgnjn_vf_h, OP_UUU_H, H2, H2, fsgnjn16)
+RVVCALL(OPFVF2, vfsgnjn_vf_w, OP_UUU_W, H4, H4, fsgnjn32)
+RVVCALL(OPFVF2, vfsgnjn_vf_d, OP_UUU_D, H8, H8, fsgnjn64)
+GEN_VEXT_VF(vfsgnjn_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfsgnjn_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfsgnjn_vf_d, 8, 8, clearq)
+
+static uint16_t fsgnjx16(uint16_t a, uint16_t b, float_status *s)
+{
+ return deposit64(b ^ a, 0, 15, a);
+}
+
+static uint32_t fsgnjx32(uint32_t a, uint32_t b, float_status *s)
+{
+ return deposit64(b ^ a, 0, 31, a);
+}
+
+static uint64_t fsgnjx64(uint64_t a, uint64_t b, float_status *s)
+{
+ return deposit64(b ^ a, 0, 63, a);
+}
+
+RVVCALL(OPFVV2, vfsgnjx_vv_h, OP_UUU_H, H2, H2, H2, fsgnjx16)
+RVVCALL(OPFVV2, vfsgnjx_vv_w, OP_UUU_W, H4, H4, H4, fsgnjx32)
+RVVCALL(OPFVV2, vfsgnjx_vv_d, OP_UUU_D, H8, H8, H8, fsgnjx64)
+GEN_VEXT_VV_ENV(vfsgnjx_vv_h, 2, 2, clearh)
+GEN_VEXT_VV_ENV(vfsgnjx_vv_w, 4, 4, clearl)
+GEN_VEXT_VV_ENV(vfsgnjx_vv_d, 8, 8, clearq)
+RVVCALL(OPFVF2, vfsgnjx_vf_h, OP_UUU_H, H2, H2, fsgnjx16)
+RVVCALL(OPFVF2, vfsgnjx_vf_w, OP_UUU_W, H4, H4, fsgnjx32)
+RVVCALL(OPFVF2, vfsgnjx_vf_d, OP_UUU_D, H8, H8, fsgnjx64)
+GEN_VEXT_VF(vfsgnjx_vf_h, 2, 2, clearh)
+GEN_VEXT_VF(vfsgnjx_vf_w, 4, 4, clearl)
+GEN_VEXT_VF(vfsgnjx_vf_d, 8, 8, clearq)
+
+/* Vector Floating-Point Compare Instructions */
+#define GEN_VEXT_CMP_VV_ENV(NAME, ETYPE, H, DO_OP) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ vext_set_elem_mask(vd, mlen, i, \
+ DO_OP(s2, s1, &env->fp_status)); \
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+GEN_VEXT_CMP_VV_ENV(vmfeq_vv_h, uint16_t, H2, float16_eq_quiet)
+GEN_VEXT_CMP_VV_ENV(vmfeq_vv_w, uint32_t, H4, float32_eq_quiet)
+GEN_VEXT_CMP_VV_ENV(vmfeq_vv_d, uint64_t, H8, float64_eq_quiet)
+
+#define GEN_VEXT_CMP_VF(NAME, ETYPE, H, DO_OP) \
+void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t vlmax = vext_maxsz(desc) / sizeof(ETYPE); \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ vext_set_elem_mask(vd, mlen, i, \
+ DO_OP(s2, (ETYPE)s1, &env->fp_status)); \
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+GEN_VEXT_CMP_VF(vmfeq_vf_h, uint16_t, H2, float16_eq_quiet)
+GEN_VEXT_CMP_VF(vmfeq_vf_w, uint32_t, H4, float32_eq_quiet)
+GEN_VEXT_CMP_VF(vmfeq_vf_d, uint64_t, H8, float64_eq_quiet)
+
+static bool vmfne16(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare_quiet(a, b, s);
+ return compare != float_relation_equal;
+}
+
+static bool vmfne32(uint32_t a, uint32_t b, float_status *s)
+{
+ FloatRelation compare = float32_compare_quiet(a, b, s);
+ return compare != float_relation_equal;
+}
+
+static bool vmfne64(uint64_t a, uint64_t b, float_status *s)
+{
+ FloatRelation compare = float64_compare_quiet(a, b, s);
+ return compare != float_relation_equal;
+}
+
+GEN_VEXT_CMP_VV_ENV(vmfne_vv_h, uint16_t, H2, vmfne16)
+GEN_VEXT_CMP_VV_ENV(vmfne_vv_w, uint32_t, H4, vmfne32)
+GEN_VEXT_CMP_VV_ENV(vmfne_vv_d, uint64_t, H8, vmfne64)
+GEN_VEXT_CMP_VF(vmfne_vf_h, uint16_t, H2, vmfne16)
+GEN_VEXT_CMP_VF(vmfne_vf_w, uint32_t, H4, vmfne32)
+GEN_VEXT_CMP_VF(vmfne_vf_d, uint64_t, H8, vmfne64)
+
+GEN_VEXT_CMP_VV_ENV(vmflt_vv_h, uint16_t, H2, float16_lt)
+GEN_VEXT_CMP_VV_ENV(vmflt_vv_w, uint32_t, H4, float32_lt)
+GEN_VEXT_CMP_VV_ENV(vmflt_vv_d, uint64_t, H8, float64_lt)
+GEN_VEXT_CMP_VF(vmflt_vf_h, uint16_t, H2, float16_lt)
+GEN_VEXT_CMP_VF(vmflt_vf_w, uint32_t, H4, float32_lt)
+GEN_VEXT_CMP_VF(vmflt_vf_d, uint64_t, H8, float64_lt)
+
+GEN_VEXT_CMP_VV_ENV(vmfle_vv_h, uint16_t, H2, float16_le)
+GEN_VEXT_CMP_VV_ENV(vmfle_vv_w, uint32_t, H4, float32_le)
+GEN_VEXT_CMP_VV_ENV(vmfle_vv_d, uint64_t, H8, float64_le)
+GEN_VEXT_CMP_VF(vmfle_vf_h, uint16_t, H2, float16_le)
+GEN_VEXT_CMP_VF(vmfle_vf_w, uint32_t, H4, float32_le)
+GEN_VEXT_CMP_VF(vmfle_vf_d, uint64_t, H8, float64_le)
+
+static bool vmfgt16(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare(a, b, s);
+ return compare == float_relation_greater;
+}
+
+static bool vmfgt32(uint32_t a, uint32_t b, float_status *s)
+{
+ FloatRelation compare = float32_compare(a, b, s);
+ return compare == float_relation_greater;
+}
+
+static bool vmfgt64(uint64_t a, uint64_t b, float_status *s)
+{
+ FloatRelation compare = float64_compare(a, b, s);
+ return compare == float_relation_greater;
+}
+
+GEN_VEXT_CMP_VF(vmfgt_vf_h, uint16_t, H2, vmfgt16)
+GEN_VEXT_CMP_VF(vmfgt_vf_w, uint32_t, H4, vmfgt32)
+GEN_VEXT_CMP_VF(vmfgt_vf_d, uint64_t, H8, vmfgt64)
+
+static bool vmfge16(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare(a, b, s);
+ return compare == float_relation_greater ||
+ compare == float_relation_equal;
+}
+
+static bool vmfge32(uint32_t a, uint32_t b, float_status *s)
+{
+ FloatRelation compare = float32_compare(a, b, s);
+ return compare == float_relation_greater ||
+ compare == float_relation_equal;
+}
+
+static bool vmfge64(uint64_t a, uint64_t b, float_status *s)
+{
+ FloatRelation compare = float64_compare(a, b, s);
+ return compare == float_relation_greater ||
+ compare == float_relation_equal;
+}
+
+GEN_VEXT_CMP_VF(vmfge_vf_h, uint16_t, H2, vmfge16)
+GEN_VEXT_CMP_VF(vmfge_vf_w, uint32_t, H4, vmfge32)
+GEN_VEXT_CMP_VF(vmfge_vf_d, uint64_t, H8, vmfge64)
+
+GEN_VEXT_CMP_VV_ENV(vmford_vv_h, uint16_t, H2, !float16_unordered_quiet)
+GEN_VEXT_CMP_VV_ENV(vmford_vv_w, uint32_t, H4, !float32_unordered_quiet)
+GEN_VEXT_CMP_VV_ENV(vmford_vv_d, uint64_t, H8, !float64_unordered_quiet)
+GEN_VEXT_CMP_VF(vmford_vf_h, uint16_t, H2, !float16_unordered_quiet)
+GEN_VEXT_CMP_VF(vmford_vf_w, uint32_t, H4, !float32_unordered_quiet)
+GEN_VEXT_CMP_VF(vmford_vf_d, uint64_t, H8, !float64_unordered_quiet)
+
+/* Vector Floating-Point Classify Instruction */
+#define OPIVV1(NAME, TD, T2, TX2, HD, HS2, OP) \
+static void do_##NAME(void *vd, void *vs2, int i) \
+{ \
+ TX2 s2 = *((T2 *)vs2 + HS2(i)); \
+ *((TD *)vd + HD(i)) = OP(s2); \
+}
+
+#define GEN_VEXT_V(NAME, ESZ, DSZ, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t vlmax = vext_maxsz(desc) / ESZ; \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ do_##NAME(vd, vs2, i); \
+ } \
+ CLEAR_FN(vd, vl, vl * DSZ, vlmax * DSZ); \
+}
+
+target_ulong fclass_h(uint64_t frs1)
+{
+ float16 f = frs1;
+ bool sign = float16_is_neg(f);
+
+ if (float16_is_infinity(f)) {
+ return sign ? 1 << 0 : 1 << 7;
+ } else if (float16_is_zero(f)) {
+ return sign ? 1 << 3 : 1 << 4;
+ } else if (float16_is_zero_or_denormal(f)) {
+ return sign ? 1 << 2 : 1 << 5;
+ } else if (float16_is_any_nan(f)) {
+ float_status s = { }; /* for snan_bit_is_one */
+ return float16_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8;
+ } else {
+ return sign ? 1 << 1 : 1 << 6;
+ }
+}
+
+target_ulong fclass_s(uint64_t frs1)
+{
+ float32 f = frs1;
+ bool sign = float32_is_neg(f);
+
+ if (float32_is_infinity(f)) {
+ return sign ? 1 << 0 : 1 << 7;
+ } else if (float32_is_zero(f)) {
+ return sign ? 1 << 3 : 1 << 4;
+ } else if (float32_is_zero_or_denormal(f)) {
+ return sign ? 1 << 2 : 1 << 5;
+ } else if (float32_is_any_nan(f)) {
+ float_status s = { }; /* for snan_bit_is_one */
+ return float32_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8;
+ } else {
+ return sign ? 1 << 1 : 1 << 6;
+ }
+}
+
+target_ulong fclass_d(uint64_t frs1)
+{
+ float64 f = frs1;
+ bool sign = float64_is_neg(f);
+
+ if (float64_is_infinity(f)) {
+ return sign ? 1 << 0 : 1 << 7;
+ } else if (float64_is_zero(f)) {
+ return sign ? 1 << 3 : 1 << 4;
+ } else if (float64_is_zero_or_denormal(f)) {
+ return sign ? 1 << 2 : 1 << 5;
+ } else if (float64_is_any_nan(f)) {
+ float_status s = { }; /* for snan_bit_is_one */
+ return float64_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8;
+ } else {
+ return sign ? 1 << 1 : 1 << 6;
+ }
+}
+
+RVVCALL(OPIVV1, vfclass_v_h, OP_UU_H, H2, H2, fclass_h)
+RVVCALL(OPIVV1, vfclass_v_w, OP_UU_W, H4, H4, fclass_s)
+RVVCALL(OPIVV1, vfclass_v_d, OP_UU_D, H8, H8, fclass_d)
+GEN_VEXT_V(vfclass_v_h, 2, 2, clearh)
+GEN_VEXT_V(vfclass_v_w, 4, 4, clearl)
+GEN_VEXT_V(vfclass_v_d, 8, 8, clearq)
+
+/* Vector Floating-Point Merge Instruction */
+#define GEN_VFMERGE_VF(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t esz = sizeof(ETYPE); \
+ uint32_t vlmax = vext_maxsz(desc) / esz; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
+ *((ETYPE *)vd + H(i)) \
+ = (!vm && !vext_elem_mask(v0, mlen, i) ? s2 : s1); \
+ } \
+ CLEAR_FN(vd, vl, vl * esz, vlmax * esz); \
+}
+
+GEN_VFMERGE_VF(vfmerge_vfm_h, int16_t, H2, clearh)
+GEN_VFMERGE_VF(vfmerge_vfm_w, int32_t, H4, clearl)
+GEN_VFMERGE_VF(vfmerge_vfm_d, int64_t, H8, clearq)
+
+/* Single-Width Floating-Point/Integer Type-Convert Instructions */
+/* vfcvt.xu.f.v vd, vs2, vm # Convert float to unsigned integer. */
+RVVCALL(OPFVV1, vfcvt_xu_f_v_h, OP_UU_H, H2, H2, float16_to_uint16)
+RVVCALL(OPFVV1, vfcvt_xu_f_v_w, OP_UU_W, H4, H4, float32_to_uint32)
+RVVCALL(OPFVV1, vfcvt_xu_f_v_d, OP_UU_D, H8, H8, float64_to_uint64)
+GEN_VEXT_V_ENV(vfcvt_xu_f_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfcvt_xu_f_v_w, 4, 4, clearl)
+GEN_VEXT_V_ENV(vfcvt_xu_f_v_d, 8, 8, clearq)
+
+/* vfcvt.x.f.v vd, vs2, vm # Convert float to signed integer. */
+RVVCALL(OPFVV1, vfcvt_x_f_v_h, OP_UU_H, H2, H2, float16_to_int16)
+RVVCALL(OPFVV1, vfcvt_x_f_v_w, OP_UU_W, H4, H4, float32_to_int32)
+RVVCALL(OPFVV1, vfcvt_x_f_v_d, OP_UU_D, H8, H8, float64_to_int64)
+GEN_VEXT_V_ENV(vfcvt_x_f_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfcvt_x_f_v_w, 4, 4, clearl)
+GEN_VEXT_V_ENV(vfcvt_x_f_v_d, 8, 8, clearq)
+
+/* vfcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to float. */
+RVVCALL(OPFVV1, vfcvt_f_xu_v_h, OP_UU_H, H2, H2, uint16_to_float16)
+RVVCALL(OPFVV1, vfcvt_f_xu_v_w, OP_UU_W, H4, H4, uint32_to_float32)
+RVVCALL(OPFVV1, vfcvt_f_xu_v_d, OP_UU_D, H8, H8, uint64_to_float64)
+GEN_VEXT_V_ENV(vfcvt_f_xu_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfcvt_f_xu_v_w, 4, 4, clearl)
+GEN_VEXT_V_ENV(vfcvt_f_xu_v_d, 8, 8, clearq)
+
+/* vfcvt.f.x.v vd, vs2, vm # Convert integer to float. */
+RVVCALL(OPFVV1, vfcvt_f_x_v_h, OP_UU_H, H2, H2, int16_to_float16)
+RVVCALL(OPFVV1, vfcvt_f_x_v_w, OP_UU_W, H4, H4, int32_to_float32)
+RVVCALL(OPFVV1, vfcvt_f_x_v_d, OP_UU_D, H8, H8, int64_to_float64)
+GEN_VEXT_V_ENV(vfcvt_f_x_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfcvt_f_x_v_w, 4, 4, clearl)
+GEN_VEXT_V_ENV(vfcvt_f_x_v_d, 8, 8, clearq)
+
+/* Widening Floating-Point/Integer Type-Convert Instructions */
+/* (TD, T2, TX2) */
+#define WOP_UU_H uint32_t, uint16_t, uint16_t
+#define WOP_UU_W uint64_t, uint32_t, uint32_t
+/* vfwcvt.xu.f.v vd, vs2, vm # Convert float to double-width unsigned integer.*/
+RVVCALL(OPFVV1, vfwcvt_xu_f_v_h, WOP_UU_H, H4, H2, float16_to_uint32)
+RVVCALL(OPFVV1, vfwcvt_xu_f_v_w, WOP_UU_W, H8, H4, float32_to_uint64)
+GEN_VEXT_V_ENV(vfwcvt_xu_f_v_h, 2, 4, clearl)
+GEN_VEXT_V_ENV(vfwcvt_xu_f_v_w, 4, 8, clearq)
+
+/* vfwcvt.x.f.v vd, vs2, vm # Convert float to double-width signed integer. */
+RVVCALL(OPFVV1, vfwcvt_x_f_v_h, WOP_UU_H, H4, H2, float16_to_int32)
+RVVCALL(OPFVV1, vfwcvt_x_f_v_w, WOP_UU_W, H8, H4, float32_to_int64)
+GEN_VEXT_V_ENV(vfwcvt_x_f_v_h, 2, 4, clearl)
+GEN_VEXT_V_ENV(vfwcvt_x_f_v_w, 4, 8, clearq)
+
+/* vfwcvt.f.xu.v vd, vs2, vm # Convert unsigned integer to double-width float */
+RVVCALL(OPFVV1, vfwcvt_f_xu_v_h, WOP_UU_H, H4, H2, uint16_to_float32)
+RVVCALL(OPFVV1, vfwcvt_f_xu_v_w, WOP_UU_W, H8, H4, uint32_to_float64)
+GEN_VEXT_V_ENV(vfwcvt_f_xu_v_h, 2, 4, clearl)
+GEN_VEXT_V_ENV(vfwcvt_f_xu_v_w, 4, 8, clearq)
+
+/* vfwcvt.f.x.v vd, vs2, vm # Convert integer to double-width float. */
+RVVCALL(OPFVV1, vfwcvt_f_x_v_h, WOP_UU_H, H4, H2, int16_to_float32)
+RVVCALL(OPFVV1, vfwcvt_f_x_v_w, WOP_UU_W, H8, H4, int32_to_float64)
+GEN_VEXT_V_ENV(vfwcvt_f_x_v_h, 2, 4, clearl)
+GEN_VEXT_V_ENV(vfwcvt_f_x_v_w, 4, 8, clearq)
+
+/*
+ * vfwcvt.f.f.v vd, vs2, vm #
+ * Convert single-width float to double-width float.
+ */
+static uint32_t vfwcvtffv16(uint16_t a, float_status *s)
+{
+ return float16_to_float32(a, true, s);
+}
+
+RVVCALL(OPFVV1, vfwcvt_f_f_v_h, WOP_UU_H, H4, H2, vfwcvtffv16)
+RVVCALL(OPFVV1, vfwcvt_f_f_v_w, WOP_UU_W, H8, H4, float32_to_float64)
+GEN_VEXT_V_ENV(vfwcvt_f_f_v_h, 2, 4, clearl)
+GEN_VEXT_V_ENV(vfwcvt_f_f_v_w, 4, 8, clearq)
+
+/* Narrowing Floating-Point/Integer Type-Convert Instructions */
+/* (TD, T2, TX2) */
+#define NOP_UU_H uint16_t, uint32_t, uint32_t
+#define NOP_UU_W uint32_t, uint64_t, uint64_t
+/* vfncvt.xu.f.v vd, vs2, vm # Convert float to unsigned integer. */
+RVVCALL(OPFVV1, vfncvt_xu_f_v_h, NOP_UU_H, H2, H4, float32_to_uint16)
+RVVCALL(OPFVV1, vfncvt_xu_f_v_w, NOP_UU_W, H4, H8, float64_to_uint32)
+GEN_VEXT_V_ENV(vfncvt_xu_f_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfncvt_xu_f_v_w, 4, 4, clearl)
+
+/* vfncvt.x.f.v vd, vs2, vm # Convert double-width float to signed integer. */
+RVVCALL(OPFVV1, vfncvt_x_f_v_h, NOP_UU_H, H2, H4, float32_to_int16)
+RVVCALL(OPFVV1, vfncvt_x_f_v_w, NOP_UU_W, H4, H8, float64_to_int32)
+GEN_VEXT_V_ENV(vfncvt_x_f_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfncvt_x_f_v_w, 4, 4, clearl)
+
+/* vfncvt.f.xu.v vd, vs2, vm # Convert double-width unsigned integer to float */
+RVVCALL(OPFVV1, vfncvt_f_xu_v_h, NOP_UU_H, H2, H4, uint32_to_float16)
+RVVCALL(OPFVV1, vfncvt_f_xu_v_w, NOP_UU_W, H4, H8, uint64_to_float32)
+GEN_VEXT_V_ENV(vfncvt_f_xu_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfncvt_f_xu_v_w, 4, 4, clearl)
+
+/* vfncvt.f.x.v vd, vs2, vm # Convert double-width integer to float. */
+RVVCALL(OPFVV1, vfncvt_f_x_v_h, NOP_UU_H, H2, H4, int32_to_float16)
+RVVCALL(OPFVV1, vfncvt_f_x_v_w, NOP_UU_W, H4, H8, int64_to_float32)
+GEN_VEXT_V_ENV(vfncvt_f_x_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfncvt_f_x_v_w, 4, 4, clearl)
+
+/* vfncvt.f.f.v vd, vs2, vm # Convert double float to single-width float. */
+static uint16_t vfncvtffv16(uint32_t a, float_status *s)
+{
+ return float32_to_float16(a, true, s);
+}
+
+RVVCALL(OPFVV1, vfncvt_f_f_v_h, NOP_UU_H, H2, H4, vfncvtffv16)
+RVVCALL(OPFVV1, vfncvt_f_f_v_w, NOP_UU_W, H4, H8, float64_to_float32)
+GEN_VEXT_V_ENV(vfncvt_f_f_v_h, 2, 2, clearh)
+GEN_VEXT_V_ENV(vfncvt_f_f_v_w, 4, 4, clearl)
+
+/*
+ *** Vector Reduction Operations
+ */
+/* Vector Single-Width Integer Reduction Instructions */
+#define GEN_VEXT_RED(NAME, TD, TS2, HD, HS2, OP, CLEAR_FN)\
+void HELPER(NAME)(void *vd, void *v0, void *vs1, \
+ void *vs2, CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ uint32_t tot = env_archcpu(env)->cfg.vlen / 8; \
+ TD s1 = *((TD *)vs1 + HD(0)); \
+ \
+ for (i = 0; i < vl; i++) { \
+ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ s1 = OP(s1, (TD)s2); \
+ } \
+ *((TD *)vd + HD(0)) = s1; \
+ CLEAR_FN(vd, 1, sizeof(TD), tot); \
+}
+
+/* vd[0] = sum(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredsum_vs_b, int8_t, int8_t, H1, H1, DO_ADD, clearb)
+GEN_VEXT_RED(vredsum_vs_h, int16_t, int16_t, H2, H2, DO_ADD, clearh)
+GEN_VEXT_RED(vredsum_vs_w, int32_t, int32_t, H4, H4, DO_ADD, clearl)
+GEN_VEXT_RED(vredsum_vs_d, int64_t, int64_t, H8, H8, DO_ADD, clearq)
+
+/* vd[0] = maxu(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredmaxu_vs_b, uint8_t, uint8_t, H1, H1, DO_MAX, clearb)
+GEN_VEXT_RED(vredmaxu_vs_h, uint16_t, uint16_t, H2, H2, DO_MAX, clearh)
+GEN_VEXT_RED(vredmaxu_vs_w, uint32_t, uint32_t, H4, H4, DO_MAX, clearl)
+GEN_VEXT_RED(vredmaxu_vs_d, uint64_t, uint64_t, H8, H8, DO_MAX, clearq)
+
+/* vd[0] = max(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredmax_vs_b, int8_t, int8_t, H1, H1, DO_MAX, clearb)
+GEN_VEXT_RED(vredmax_vs_h, int16_t, int16_t, H2, H2, DO_MAX, clearh)
+GEN_VEXT_RED(vredmax_vs_w, int32_t, int32_t, H4, H4, DO_MAX, clearl)
+GEN_VEXT_RED(vredmax_vs_d, int64_t, int64_t, H8, H8, DO_MAX, clearq)
+
+/* vd[0] = minu(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredminu_vs_b, uint8_t, uint8_t, H1, H1, DO_MIN, clearb)
+GEN_VEXT_RED(vredminu_vs_h, uint16_t, uint16_t, H2, H2, DO_MIN, clearh)
+GEN_VEXT_RED(vredminu_vs_w, uint32_t, uint32_t, H4, H4, DO_MIN, clearl)
+GEN_VEXT_RED(vredminu_vs_d, uint64_t, uint64_t, H8, H8, DO_MIN, clearq)
+
+/* vd[0] = min(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredmin_vs_b, int8_t, int8_t, H1, H1, DO_MIN, clearb)
+GEN_VEXT_RED(vredmin_vs_h, int16_t, int16_t, H2, H2, DO_MIN, clearh)
+GEN_VEXT_RED(vredmin_vs_w, int32_t, int32_t, H4, H4, DO_MIN, clearl)
+GEN_VEXT_RED(vredmin_vs_d, int64_t, int64_t, H8, H8, DO_MIN, clearq)
+
+/* vd[0] = and(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredand_vs_b, int8_t, int8_t, H1, H1, DO_AND, clearb)
+GEN_VEXT_RED(vredand_vs_h, int16_t, int16_t, H2, H2, DO_AND, clearh)
+GEN_VEXT_RED(vredand_vs_w, int32_t, int32_t, H4, H4, DO_AND, clearl)
+GEN_VEXT_RED(vredand_vs_d, int64_t, int64_t, H8, H8, DO_AND, clearq)
+
+/* vd[0] = or(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredor_vs_b, int8_t, int8_t, H1, H1, DO_OR, clearb)
+GEN_VEXT_RED(vredor_vs_h, int16_t, int16_t, H2, H2, DO_OR, clearh)
+GEN_VEXT_RED(vredor_vs_w, int32_t, int32_t, H4, H4, DO_OR, clearl)
+GEN_VEXT_RED(vredor_vs_d, int64_t, int64_t, H8, H8, DO_OR, clearq)
+
+/* vd[0] = xor(vs1[0], vs2[*]) */
+GEN_VEXT_RED(vredxor_vs_b, int8_t, int8_t, H1, H1, DO_XOR, clearb)
+GEN_VEXT_RED(vredxor_vs_h, int16_t, int16_t, H2, H2, DO_XOR, clearh)
+GEN_VEXT_RED(vredxor_vs_w, int32_t, int32_t, H4, H4, DO_XOR, clearl)
+GEN_VEXT_RED(vredxor_vs_d, int64_t, int64_t, H8, H8, DO_XOR, clearq)
+
+/* Vector Widening Integer Reduction Instructions */
+/* signed sum reduction into double-width accumulator */
+GEN_VEXT_RED(vwredsum_vs_b, int16_t, int8_t, H2, H1, DO_ADD, clearh)
+GEN_VEXT_RED(vwredsum_vs_h, int32_t, int16_t, H4, H2, DO_ADD, clearl)
+GEN_VEXT_RED(vwredsum_vs_w, int64_t, int32_t, H8, H4, DO_ADD, clearq)
+
+/* Unsigned sum reduction into double-width accumulator */
+GEN_VEXT_RED(vwredsumu_vs_b, uint16_t, uint8_t, H2, H1, DO_ADD, clearh)
+GEN_VEXT_RED(vwredsumu_vs_h, uint32_t, uint16_t, H4, H2, DO_ADD, clearl)
+GEN_VEXT_RED(vwredsumu_vs_w, uint64_t, uint32_t, H8, H4, DO_ADD, clearq)
+
+/* Vector Single-Width Floating-Point Reduction Instructions */
+#define GEN_VEXT_FRED(NAME, TD, TS2, HD, HS2, OP, CLEAR_FN)\
+void HELPER(NAME)(void *vd, void *v0, void *vs1, \
+ void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ uint32_t tot = env_archcpu(env)->cfg.vlen / 8; \
+ TD s1 = *((TD *)vs1 + HD(0)); \
+ \
+ for (i = 0; i < vl; i++) { \
+ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ s1 = OP(s1, (TD)s2, &env->fp_status); \
+ } \
+ *((TD *)vd + HD(0)) = s1; \
+ CLEAR_FN(vd, 1, sizeof(TD), tot); \
+}
+
+/* Unordered sum */
+GEN_VEXT_FRED(vfredsum_vs_h, uint16_t, uint16_t, H2, H2, float16_add, clearh)
+GEN_VEXT_FRED(vfredsum_vs_w, uint32_t, uint32_t, H4, H4, float32_add, clearl)
+GEN_VEXT_FRED(vfredsum_vs_d, uint64_t, uint64_t, H8, H8, float64_add, clearq)
+
+/* Maximum value */
+GEN_VEXT_FRED(vfredmax_vs_h, uint16_t, uint16_t, H2, H2, float16_maxnum, clearh)
+GEN_VEXT_FRED(vfredmax_vs_w, uint32_t, uint32_t, H4, H4, float32_maxnum, clearl)
+GEN_VEXT_FRED(vfredmax_vs_d, uint64_t, uint64_t, H8, H8, float64_maxnum, clearq)
+
+/* Minimum value */
+GEN_VEXT_FRED(vfredmin_vs_h, uint16_t, uint16_t, H2, H2, float16_minnum, clearh)
+GEN_VEXT_FRED(vfredmin_vs_w, uint32_t, uint32_t, H4, H4, float32_minnum, clearl)
+GEN_VEXT_FRED(vfredmin_vs_d, uint64_t, uint64_t, H8, H8, float64_minnum, clearq)
+
+/* Vector Widening Floating-Point Reduction Instructions */
+/* Unordered reduce 2*SEW = 2*SEW + sum(promote(SEW)) */
+void HELPER(vfwredsum_vs_h)(void *vd, void *v0, void *vs1,
+ void *vs2, CPURISCVState *env, uint32_t desc)
+{
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ uint32_t i;
+ uint32_t tot = env_archcpu(env)->cfg.vlen / 8;
+ uint32_t s1 = *((uint32_t *)vs1 + H4(0));
+
+ for (i = 0; i < vl; i++) {
+ uint16_t s2 = *((uint16_t *)vs2 + H2(i));
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ s1 = float32_add(s1, float16_to_float32(s2, true, &env->fp_status),
+ &env->fp_status);
+ }
+ *((uint32_t *)vd + H4(0)) = s1;
+ clearl(vd, 1, sizeof(uint32_t), tot);
+}
+
+void HELPER(vfwredsum_vs_w)(void *vd, void *v0, void *vs1,
+ void *vs2, CPURISCVState *env, uint32_t desc)
+{
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ uint32_t i;
+ uint32_t tot = env_archcpu(env)->cfg.vlen / 8;
+ uint64_t s1 = *((uint64_t *)vs1);
+
+ for (i = 0; i < vl; i++) {
+ uint32_t s2 = *((uint32_t *)vs2 + H4(i));
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ s1 = float64_add(s1, float32_to_float64(s2, &env->fp_status),
+ &env->fp_status);
+ }
+ *((uint64_t *)vd) = s1;
+ clearq(vd, 1, sizeof(uint64_t), tot);
+}
+
+/*
+ *** Vector Mask Operations
+ */
+/* Vector Mask-Register Logical Instructions */
+#define GEN_VEXT_MASK_VV(NAME, OP) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, \
+ void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ int a, b; \
+ \
+ for (i = 0; i < vl; i++) { \
+ a = vext_elem_mask(vs1, mlen, i); \
+ b = vext_elem_mask(vs2, mlen, i); \
+ vext_set_elem_mask(vd, mlen, i, OP(b, a)); \
+ } \
+ for (; i < vlmax; i++) { \
+ vext_set_elem_mask(vd, mlen, i, 0); \
+ } \
+}
+
+#define DO_NAND(N, M) (!(N & M))
+#define DO_ANDNOT(N, M) (N & !M)
+#define DO_NOR(N, M) (!(N | M))
+#define DO_ORNOT(N, M) (N | !M)
+#define DO_XNOR(N, M) (!(N ^ M))
+
+GEN_VEXT_MASK_VV(vmand_mm, DO_AND)
+GEN_VEXT_MASK_VV(vmnand_mm, DO_NAND)
+GEN_VEXT_MASK_VV(vmandnot_mm, DO_ANDNOT)
+GEN_VEXT_MASK_VV(vmxor_mm, DO_XOR)
+GEN_VEXT_MASK_VV(vmor_mm, DO_OR)
+GEN_VEXT_MASK_VV(vmnor_mm, DO_NOR)
+GEN_VEXT_MASK_VV(vmornot_mm, DO_ORNOT)
+GEN_VEXT_MASK_VV(vmxnor_mm, DO_XNOR)
+
+/* Vector mask population count vmpopc */
+target_ulong HELPER(vmpopc_m)(void *v0, void *vs2, CPURISCVState *env,
+ uint32_t desc)
+{
+ target_ulong cnt = 0;
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ int i;
+
+ for (i = 0; i < vl; i++) {
+ if (vm || vext_elem_mask(v0, mlen, i)) {
+ if (vext_elem_mask(vs2, mlen, i)) {
+ cnt++;
+ }
+ }
+ }
+ return cnt;
+}
+
+/* vmfirst find-first-set mask bit*/
+target_ulong HELPER(vmfirst_m)(void *v0, void *vs2, CPURISCVState *env,
+ uint32_t desc)
+{
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ int i;
+
+ for (i = 0; i < vl; i++) {
+ if (vm || vext_elem_mask(v0, mlen, i)) {
+ if (vext_elem_mask(vs2, mlen, i)) {
+ return i;
+ }
+ }
+ }
+ return -1LL;
+}
+
+enum set_mask_type {
+ ONLY_FIRST = 1,
+ INCLUDE_FIRST,
+ BEFORE_FIRST,
+};
+
+static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env,
+ uint32_t desc, enum set_mask_type type)
+{
+ uint32_t mlen = vext_mlen(desc);
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen;
+ uint32_t vm = vext_vm(desc);
+ uint32_t vl = env->vl;
+ int i;
+ bool first_mask_bit = false;
+
+ for (i = 0; i < vl; i++) {
+ if (!vm && !vext_elem_mask(v0, mlen, i)) {
+ continue;
+ }
+ /* write a zero to all following active elements */
+ if (first_mask_bit) {
+ vext_set_elem_mask(vd, mlen, i, 0);
+ continue;
+ }
+ if (vext_elem_mask(vs2, mlen, i)) {
+ first_mask_bit = true;
+ if (type == BEFORE_FIRST) {
+ vext_set_elem_mask(vd, mlen, i, 0);
+ } else {
+ vext_set_elem_mask(vd, mlen, i, 1);
+ }
+ } else {
+ if (type == ONLY_FIRST) {
+ vext_set_elem_mask(vd, mlen, i, 0);
+ } else {
+ vext_set_elem_mask(vd, mlen, i, 1);
+ }
+ }
+ }
+ for (; i < vlmax; i++) {
+ vext_set_elem_mask(vd, mlen, i, 0);
+ }
+}
+
+void HELPER(vmsbf_m)(void *vd, void *v0, void *vs2, CPURISCVState *env,
+ uint32_t desc)
+{
+ vmsetm(vd, v0, vs2, env, desc, BEFORE_FIRST);
+}
+
+void HELPER(vmsif_m)(void *vd, void *v0, void *vs2, CPURISCVState *env,
+ uint32_t desc)
+{
+ vmsetm(vd, v0, vs2, env, desc, INCLUDE_FIRST);
+}
+
+void HELPER(vmsof_m)(void *vd, void *v0, void *vs2, CPURISCVState *env,
+ uint32_t desc)
+{
+ vmsetm(vd, v0, vs2, env, desc, ONLY_FIRST);
+}
+
+/* Vector Iota Instruction */
+#define GEN_VEXT_VIOTA_M(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \
+ uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t sum = 0; \
+ int i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ *((ETYPE *)vd + H(i)) = sum; \
+ if (vext_elem_mask(vs2, mlen, i)) { \
+ sum++; \
+ } \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+GEN_VEXT_VIOTA_M(viota_m_b, uint8_t, H1, clearb)
+GEN_VEXT_VIOTA_M(viota_m_h, uint16_t, H2, clearh)
+GEN_VEXT_VIOTA_M(viota_m_w, uint32_t, H4, clearl)
+GEN_VEXT_VIOTA_M(viota_m_d, uint64_t, H8, clearq)
+
+/* Vector Element Index Instruction */
+#define GEN_VEXT_VID_V(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ int i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ *((ETYPE *)vd + H(i)) = i; \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+GEN_VEXT_VID_V(vid_v_b, uint8_t, H1, clearb)
+GEN_VEXT_VID_V(vid_v_h, uint16_t, H2, clearh)
+GEN_VEXT_VID_V(vid_v_w, uint32_t, H4, clearl)
+GEN_VEXT_VID_V(vid_v_d, uint64_t, H8, clearq)
+
+/*
+ *** Vector Permutation Instructions
+ */
+
+/* Vector Slide Instructions */
+#define GEN_VEXT_VSLIDEUP_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ target_ulong offset = s1, i; \
+ \
+ for (i = offset; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - offset)); \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* vslideup.vx vd, vs2, rs1, vm # vd[i+rs1] = vs2[i] */
+GEN_VEXT_VSLIDEUP_VX(vslideup_vx_b, uint8_t, H1, clearb)
+GEN_VEXT_VSLIDEUP_VX(vslideup_vx_h, uint16_t, H2, clearh)
+GEN_VEXT_VSLIDEUP_VX(vslideup_vx_w, uint32_t, H4, clearl)
+GEN_VEXT_VSLIDEUP_VX(vslideup_vx_d, uint64_t, H8, clearq)
+
+#define GEN_VEXT_VSLIDEDOWN_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ target_ulong offset = s1, i; \
+ \
+ for (i = 0; i < vl; ++i) { \
+ target_ulong j = i + offset; \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ *((ETYPE *)vd + H(i)) = j >= vlmax ? 0 : *((ETYPE *)vs2 + H(j)); \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* vslidedown.vx vd, vs2, rs1, vm # vd[i] = vs2[i+rs1] */
+GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_b, uint8_t, H1, clearb)
+GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_h, uint16_t, H2, clearh)
+GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_w, uint32_t, H4, clearl)
+GEN_VEXT_VSLIDEDOWN_VX(vslidedown_vx_d, uint64_t, H8, clearq)
+
+#define GEN_VEXT_VSLIDE1UP_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ if (i == 0) { \
+ *((ETYPE *)vd + H(i)) = s1; \
+ } else { \
+ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i - 1)); \
+ } \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* vslide1up.vx vd, vs2, rs1, vm # vd[0]=x[rs1], vd[i+1] = vs2[i] */
+GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_b, uint8_t, H1, clearb)
+GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_h, uint16_t, H2, clearh)
+GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_w, uint32_t, H4, clearl)
+GEN_VEXT_VSLIDE1UP_VX(vslide1up_vx_d, uint64_t, H8, clearq)
+
+#define GEN_VEXT_VSLIDE1DOWN_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ if (i == vl - 1) { \
+ *((ETYPE *)vd + H(i)) = s1; \
+ } else { \
+ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(i + 1)); \
+ } \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* vslide1down.vx vd, vs2, rs1, vm # vd[i] = vs2[i+1], vd[vl-1]=x[rs1] */
+GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_b, uint8_t, H1, clearb)
+GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_h, uint16_t, H2, clearh)
+GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_w, uint32_t, H4, clearl)
+GEN_VEXT_VSLIDE1DOWN_VX(vslide1down_vx_d, uint64_t, H8, clearq)
+
+/* Vector Register Gather Instruction */
+#define GEN_VEXT_VRGATHER_VV(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint64_t index; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ index = *((ETYPE *)vs1 + H(i)); \
+ if (index >= vlmax) { \
+ *((ETYPE *)vd + H(i)) = 0; \
+ } else { \
+ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(index)); \
+ } \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* vd[i] = (vs1[i] >= VLMAX) ? 0 : vs2[vs1[i]]; */
+GEN_VEXT_VRGATHER_VV(vrgather_vv_b, uint8_t, H1, clearb)
+GEN_VEXT_VRGATHER_VV(vrgather_vv_h, uint16_t, H2, clearh)
+GEN_VEXT_VRGATHER_VV(vrgather_vv_w, uint32_t, H4, clearl)
+GEN_VEXT_VRGATHER_VV(vrgather_vv_d, uint64_t, H8, clearq)
+
+#define GEN_VEXT_VRGATHER_VX(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vm = vext_vm(desc); \
+ uint32_t vl = env->vl; \
+ uint64_t index = s1; \
+ uint32_t i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vm && !vext_elem_mask(v0, mlen, i)) { \
+ continue; \
+ } \
+ if (index >= vlmax) { \
+ *((ETYPE *)vd + H(i)) = 0; \
+ } else { \
+ *((ETYPE *)vd + H(i)) = *((ETYPE *)vs2 + H(index)); \
+ } \
+ } \
+ CLEAR_FN(vd, vl, vl * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
+GEN_VEXT_VRGATHER_VX(vrgather_vx_b, uint8_t, H1, clearb)
+GEN_VEXT_VRGATHER_VX(vrgather_vx_h, uint16_t, H2, clearh)
+GEN_VEXT_VRGATHER_VX(vrgather_vx_w, uint32_t, H4, clearl)
+GEN_VEXT_VRGATHER_VX(vrgather_vx_d, uint64_t, H8, clearq)
+
+/* Vector Compress Instruction */
+#define GEN_VEXT_VCOMPRESS_VM(NAME, ETYPE, H, CLEAR_FN) \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
+ CPURISCVState *env, uint32_t desc) \
+{ \
+ uint32_t mlen = vext_mlen(desc); \
+ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
+ uint32_t vl = env->vl; \
+ uint32_t num = 0, i; \
+ \
+ for (i = 0; i < vl; i++) { \
+ if (!vext_elem_mask(vs1, mlen, i)) { \
+ continue; \
+ } \
+ *((ETYPE *)vd + H(num)) = *((ETYPE *)vs2 + H(i)); \
+ num++; \
+ } \
+ CLEAR_FN(vd, num, num * sizeof(ETYPE), vlmax * sizeof(ETYPE)); \
+}
+
+/* Compress into vd elements of vs2 where vs1 is enabled */
+GEN_VEXT_VCOMPRESS_VM(vcompress_vm_b, uint8_t, H1, clearb)
+GEN_VEXT_VCOMPRESS_VM(vcompress_vm_h, uint16_t, H2, clearh)
+GEN_VEXT_VCOMPRESS_VM(vcompress_vm_w, uint32_t, H4, clearl)
+GEN_VEXT_VCOMPRESS_VM(vcompress_vm_d, uint64_t, H8, clearq)