aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--block/vvfat.c67
-rw-r--r--chardev/char-socket.c9
-rwxr-xr-xconfigure6
-rw-r--r--docs/system/deprecated.rst11
-rw-r--r--docs/tools/virtiofsd.rst5
-rw-r--r--hw/9pfs/9p.c6
-rw-r--r--hw/acpi/pcihp.c3
-rw-r--r--hw/acpi/piix4.c2
-rw-r--r--hw/arm/armsse.c61
-rw-r--r--hw/arm/armv7m.c7
-rw-r--r--hw/arm/aspeed_ast2600.c35
-rw-r--r--hw/arm/aspeed_soc.c29
-rw-r--r--hw/arm/bcm2835_peripherals.c12
-rw-r--r--hw/arm/fsl-imx25.c12
-rw-r--r--hw/arm/fsl-imx6.c12
-rw-r--r--hw/arm/fsl-imx6ul.c10
-rw-r--r--hw/arm/mcimx6ul-evk.c2
-rw-r--r--hw/arm/nrf51_soc.c6
-rw-r--r--hw/arm/pxa2xx_pic.c9
-rw-r--r--hw/arm/spitz.c505
-rw-r--r--hw/arm/stm32f205_soc.c2
-rw-r--r--hw/arm/stm32f405_soc.c2
-rw-r--r--hw/arm/virt-acpi-build.c5
-rw-r--r--hw/arm/virt.c37
-rw-r--r--hw/arm/z2.c11
-rw-r--r--hw/char/virtio-serial-bus.c4
-rw-r--r--hw/core/bus.c8
-rw-r--r--hw/core/qdev-properties.c89
-rw-r--r--hw/display/ads7846.c9
-rw-r--r--hw/display/ati.c92
-rw-r--r--hw/display/ati_dbg.c1
-rw-r--r--hw/display/ati_regs.h1
-rw-r--r--hw/display/bcm2835_fb.c4
-rw-r--r--hw/display/sm501.c157
-rw-r--r--hw/display/ssd0323.c10
-rw-r--r--hw/display/trace-events12
-rw-r--r--hw/display/virtio-gpu-pci.c2
-rw-r--r--hw/display/virtio-vga.c2
-rw-r--r--hw/dma/sparc32_dma.c6
-rw-r--r--hw/dma/xilinx_axidma.c12
-rw-r--r--hw/gpio/zaurus.c12
-rw-r--r--hw/i386/amd_iommu.c6
-rw-r--r--hw/i386/x86.c8
-rw-r--r--hw/mips/cps.c35
-rw-r--r--hw/misc/macio/macio.c3
-rw-r--r--hw/misc/max111x.c86
-rw-r--r--hw/misc/pca9552.c1
-rw-r--r--hw/net/imx_fec.c24
-rw-r--r--hw/net/trace-events4
-rw-r--r--hw/net/virtio-net.c2
-rw-r--r--hw/net/xilinx_axienet.c12
-rw-r--r--hw/pci/pci.c3
-rw-r--r--hw/pci/pcie.c2
-rw-r--r--hw/pci/shpc.c2
-rw-r--r--hw/ppc/spapr.c4
-rw-r--r--hw/ppc/spapr_drc.c4
-rw-r--r--hw/ppc/spapr_pci.c4
-rw-r--r--hw/riscv/riscv_hart.c14
-rw-r--r--hw/riscv/sifive_clint.c2
-rw-r--r--hw/riscv/sifive_plic.c20
-rw-r--r--hw/riscv/sifive_u.c12
-rw-r--r--hw/s390x/ap-bridge.c2
-rw-r--r--hw/s390x/css-bridge.c2
-rw-r--r--hw/s390x/s390-pci-bus.c30
-rw-r--r--hw/s390x/virtio-ccw.c18
-rw-r--r--hw/scsi/scsi-bus.c2
-rw-r--r--hw/scsi/virtio-scsi.c4
-rw-r--r--hw/scsi/vmw_pvscsi.c2
-rw-r--r--hw/sd/milkymist-memcard.c5
-rw-r--r--hw/sd/ssi-sd.c4
-rw-r--r--hw/ssi/ssi.c7
-rw-r--r--hw/usb/bus.c2
-rw-r--r--hw/usb/dev-mtp.c2
-rw-r--r--hw/usb/dev-smartcard-reader.c2
-rw-r--r--hw/virtio/trace-events1
-rw-r--r--hw/virtio/virtio-iommu-pci.c15
-rw-r--r--hw/virtio/virtio-iommu.c114
-rw-r--r--hw/xen/xen-bus.c2
-rw-r--r--hw/xen/xen-legacy-backend.c2
-rw-r--r--include/exec/memory.h6
-rw-r--r--include/exec/ram_addr.h5
-rw-r--r--include/hw/arm/fsl-imx6ul.h2
-rw-r--r--include/hw/arm/pxa.h1
-rw-r--r--include/hw/arm/sharpsl.h3
-rw-r--r--include/hw/arm/virt.h8
-rw-r--r--include/hw/misc/max111x.h56
-rw-r--r--include/hw/net/imx_fec.h1
-rw-r--r--include/hw/qdev-core.h5
-rw-r--r--include/hw/qdev-properties.h3
-rw-r--r--include/hw/ssi/ssi.h31
-rw-r--r--include/hw/virtio/virtio-iommu.h2
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--migration/postcopy-ram.c2
-rw-r--r--migration/ram.c8
-rw-r--r--migration/rdma.c19
-rw-r--r--pc-bios/bios-256k.binbin262144 -> 262144 bytes
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--pc-bios/s390-ccw.imgbin42608 -> 42608 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile3
-rw-r--r--pc-bios/s390-ccw/bootmap.c4
-rw-r--r--pc-bios/s390-ccw/cio.c40
-rw-r--r--pc-bios/s390-ccw/cio.h17
-rw-r--r--pc-bios/s390-ccw/helper.h19
-rw-r--r--pc-bios/s390-ccw/jump2ipl.c10
-rw-r--r--pc-bios/s390-ccw/main.c15
-rw-r--r--pc-bios/s390-ccw/menu.c1
-rw-r--r--pc-bios/s390-ccw/netboot.mak13
-rw-r--r--pc-bios/s390-ccw/netmain.c23
-rw-r--r--pc-bios/s390-ccw/s390-arch.h4
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h27
-rw-r--r--pc-bios/s390-ccw/s390-time.h23
-rw-r--r--pc-bios/s390-ccw/start.S5
-rw-r--r--pc-bios/s390-ccw/virtio-net.c2
-rw-r--r--pc-bios/s390-ccw/virtio-scsi.c2
-rw-r--r--pc-bios/s390-ccw/virtio.c18
-rw-r--r--pc-bios/s390-netboot.imgbin67232 -> 67232 bytes
-rw-r--r--pc-bios/vgabios-ati.binbin39424 -> 39424 bytes
-rw-r--r--pc-bios/vgabios-bochs-display.binbin28672 -> 28672 bytes
-rw-r--r--pc-bios/vgabios-cirrus.binbin38912 -> 38912 bytes
-rw-r--r--pc-bios/vgabios-qxl.binbin39424 -> 39424 bytes
-rw-r--r--pc-bios/vgabios-ramfb.binbin28672 -> 28672 bytes
-rw-r--r--pc-bios/vgabios-stdvga.binbin39424 -> 39424 bytes
-rw-r--r--pc-bios/vgabios-virtio.binbin39424 -> 39424 bytes
-rw-r--r--pc-bios/vgabios-vmware.binbin39424 -> 39424 bytes
-rw-r--r--pc-bios/vgabios.binbin38912 -> 38912 bytes
-rw-r--r--qemu-img.c9
-rw-r--r--qemu-storage-daemon.c5
-rw-r--r--qga/commands-posix.c1
-rw-r--r--roms/config.seabios-128k3
m---------roms/seabios0
-rw-r--r--target/arm/cpu.h2
-rw-r--r--target/arm/kvm.c80
-rw-r--r--target/arm/kvm32.c34
-rw-r--r--target/arm/kvm64.c49
-rw-r--r--target/arm/kvm_arm.h10
-rw-r--r--target/arm/translate-a64.c6
-rw-r--r--target/arm/translate-a64.h1
-rw-r--r--target/arm/translate-sve.c8
-rw-r--r--target/riscv/Makefile.objs2
-rw-r--r--target/riscv/cpu.c50
-rw-r--r--target/riscv/cpu.h82
-rw-r--r--target/riscv/cpu_bits.h15
-rw-r--r--target/riscv/csr.c75
-rw-r--r--target/riscv/fpu_helper.c33
-rw-r--r--target/riscv/helper.h1069
-rw-r--r--target/riscv/insn32-64.decode11
-rw-r--r--target/riscv/insn32.decode372
-rw-r--r--target/riscv/insn_trans/trans_rvv.inc.c2888
-rw-r--r--target/riscv/internals.h41
-rw-r--r--target/riscv/translate.c27
-rw-r--r--target/riscv/vector_helper.c4899
-rw-r--r--target/s390x/insn-data.def2
-rw-r--r--tests/check-block-qdict.c24
-rw-r--r--tests/check-qobject.c5
-rw-r--r--tests/check-qom-proplist.c14
-rw-r--r--tests/data/acpi/virt/DSDTbin5307 -> 5205 bytes
-rw-r--r--tests/data/acpi/virt/DSDT.memhpbin6668 -> 6566 bytes
-rw-r--r--tests/data/acpi/virt/DSDT.numamembin5307 -> 5205 bytes
-rw-r--r--tests/qemu-iotests/051.pc.out4
-rwxr-xr-xtests/qemu-iotests/2914
-rw-r--r--tests/qemu-iotests/291.out33
-rw-r--r--tests/qemu-iotests/iotests.py34
-rw-r--r--tests/qtest/bios-tables-test-allowed-diff.h18
-rw-r--r--tests/test-base64.c3
-rw-r--r--tests/test-bdrv-graph-mod.c4
-rw-r--r--tests/test-block-iothread.c3
-rw-r--r--tests/test-crypto-cipher.c8
-rw-r--r--tests/test-io-task.c4
-rw-r--r--tests/test-logging.c12
-rw-r--r--tests/test-qemu-opts.c22
-rw-r--r--tests/test-replication.c109
-rw-r--r--tests/test-string-input-visitor.c33
-rw-r--r--tests/test-string-output-visitor.c16
-rw-r--r--tests/test-util-filemonitor.c1
-rw-r--r--tools/virtiofsd/helper.c2
-rw-r--r--tools/virtiofsd/passthrough_ll.c71
-rw-r--r--ui/vnc.c6
178 files changed, 11179 insertions, 1156 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 29a23b6d3a..b6602dcde2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -787,6 +787,7 @@ F: hw/gpio/max7310.c
F: hw/gpio/zaurus.c
F: hw/misc/mst_fpga.c
F: hw/misc/max111x.c
+F: include/hw/misc/max111x.h
F: include/hw/arm/pxa.h
F: include/hw/arm/sharpsl.h
F: include/hw/display/tc6393xb.h
diff --git a/block/vvfat.c b/block/vvfat.c
index c65a98e3ee..2eb8cbb19f 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -140,48 +140,16 @@ static inline void* array_insert(array_t* array,unsigned int index,unsigned int
return array->pointer+index*array->item_size;
}
-/* this performs a "roll", so that the element which was at index_from becomes
- * index_to, but the order of all other elements is preserved. */
-static inline int array_roll(array_t* array,int index_to,int index_from,int count)
-{
- char* buf;
- char* from;
- char* to;
- int is;
-
- if(!array ||
- index_to<0 || index_to>=array->next ||
- index_from<0 || index_from>=array->next)
- return -1;
-
- if(index_to==index_from)
- return 0;
-
- is=array->item_size;
- from=array->pointer+index_from*is;
- to=array->pointer+index_to*is;
- buf=g_malloc(is*count);
- memcpy(buf,from,is*count);
-
- if(index_to<index_from)
- memmove(to+is*count,to,from-to);
- else
- memmove(from,from+is*count,to-from);
-
- memcpy(to,buf,is*count);
-
- g_free(buf);
-
- return 0;
-}
-
static inline int array_remove_slice(array_t* array,int index, int count)
{
assert(index >=0);
assert(count > 0);
assert(index + count <= array->next);
- if(array_roll(array,array->next-1,index,count))
- return -1;
+
+ memmove(array->pointer + index * array->item_size,
+ array->pointer + (index + count) * array->item_size,
+ (array->next - index - count) * array->item_size);
+
array->next -= count;
return 0;
}
@@ -520,12 +488,31 @@ static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
}
+static bool valid_filename(const unsigned char *name)
+{
+ unsigned char c;
+ if (!strcmp((const char*)name, ".") || !strcmp((const char*)name, "..")) {
+ return false;
+ }
+ for (; (c = *name); name++) {
+ if (!((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ c > 127 ||
+ strchr("$%'-_@~`!(){}^#&.+,;=[]", c) != NULL))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
static uint8_t to_valid_short_char(gunichar c)
{
c = g_unichar_toupper(c);
if ((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
- strchr("$%'-_@~`!(){}^#&", c) != 0) {
+ strchr("$%'-_@~`!(){}^#&", c) != NULL) {
return c;
} else {
return 0;
@@ -2098,6 +2085,10 @@ DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i))
}
lfn.checksum = 0x100; /* cannot use long name twice */
+ if (!valid_filename(lfn.name)) {
+ fprintf(stderr, "Invalid file name\n");
+ goto fail;
+ }
if (path_len + 1 + lfn.len >= PATH_MAX) {
fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
goto fail;
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index afebeec5c3..5758d9900f 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -142,6 +142,8 @@ static void check_report_connect_error(Chardev *chr,
"Unable to connect character device %s: ",
chr->label);
s->connect_err_reported = true;
+ } else {
+ error_free(err);
}
qemu_chr_socket_restart_timer(chr);
}
@@ -815,22 +817,20 @@ static void tcp_chr_tls_init(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelTLS *tioc;
- Error *err = NULL;
gchar *name;
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
s->tls_authz,
- &err);
+ NULL);
} else {
tioc = qio_channel_tls_new_client(
s->ioc, s->tls_creds,
s->addr->u.inet.host,
- &err);
+ NULL);
}
if (tioc == NULL) {
- error_free(err);
tcp_chr_disconnect(chr);
return;
}
@@ -1086,7 +1086,6 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
if (qio_task_propagate_error(task, &err)) {
tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
check_report_connect_error(chr, err);
- error_free(err);
goto cleanup;
}
diff --git a/configure b/configure
index 2014c72b67..c220ab4d80 100755
--- a/configure
+++ b/configure
@@ -8496,14 +8496,14 @@ DIRS="tests tests/tcg tests/tcg/lm32 tests/qapi-schema tests/qtest/libqos"
DIRS="$DIRS tests/qtest tests/qemu-iotests tests/vm tests/fp tests/qgraph"
DIRS="$DIRS docs docs/interop fsdev scsi"
DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
-DIRS="$DIRS roms/seabios roms/vgabios"
+DIRS="$DIRS roms/seabios"
LINKS="Makefile"
LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile"
LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile"
LINKS="$LINKS tests/plugin/Makefile"
LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps"
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
-LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile"
+LINKS="$LINKS roms/seabios/Makefile"
LINKS="$LINKS pc-bios/qemu-icon.bmp"
LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit
LINKS="$LINKS tests/acceptance tests/data"
@@ -8536,7 +8536,7 @@ export target_list source_path use_containers
$source_path/tests/tcg/configure.sh)
# temporary config to build submodules
-for rom in seabios vgabios ; do
+for rom in seabios; do
config_mak=roms/$rom/config.mak
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 843ae71fc6..47f84be8e0 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -404,6 +404,17 @@ The above, converted to the current supported format::
json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"}
+linux-user mode CPUs
+--------------------
+
+``tilegx`` CPUs (since 5.1.0)
+'''''''''''''''''''''''''''''
+
+The ``tilegx`` guest CPU support (which was only implemented in
+linux-user mode) is deprecated and will be removed in a future version
+of QEMU. Support for this CPU was removed from the upstream Linux
+kernel in 2018, and has also been dropped from glibc.
+
Related binaries
----------------
diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst
index 378594c422..824e713491 100644
--- a/docs/tools/virtiofsd.rst
+++ b/docs/tools/virtiofsd.rst
@@ -54,6 +54,11 @@ Options
* flock|no_flock -
Enable/disable flock. The default is ``no_flock``.
+ * modcaps=CAPLIST
+ Modify the list of capabilities allowed; CAPLIST is a colon separated
+ list of capabilities, each preceded by either + or -, e.g.
+ ''+sys_admin:-chown''.
+
* log_level=LEVEL -
Print only log messages matching LEVEL or more severe. LEVEL is one of
``err``, ``warn``, ``info``, or ``debug``. The default is ``info``.
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 45a788f6e6..9755fba9a9 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1399,7 +1399,6 @@ static void coroutine_fn v9fs_attach(void *opaque)
size_t offset = 7;
V9fsQID qid;
ssize_t err;
- Error *local_err = NULL;
v9fs_string_init(&uname);
v9fs_string_init(&aname);
@@ -1437,9 +1436,8 @@ static void coroutine_fn v9fs_attach(void *opaque)
error_setg(&s->migration_blocker,
"Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
- err = migrate_add_blocker(s->migration_blocker, &local_err);
- if (local_err) {
- error_free(local_err);
+ err = migrate_add_blocker(s->migration_blocker, NULL);
+ if (err < 0) {
error_free(s->migration_blocker);
s->migration_blocker = NULL;
clunk_fid(s, fid);
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 33ea2b76ae..9e31ab2da4 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -246,8 +246,7 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
- qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev),
- &error_abort);
+ qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev));
/* We don't have to overwrite any other hotplug handler yet */
assert(QLIST_EMPTY(&sec->child));
}
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 630ca6ec87..283422e0d3 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -506,7 +506,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
pci_get_bus(dev), s);
- qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s), &error_abort);
+ qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s));
piix4_pm_add_propeties(s);
}
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 9ddde339ec..2fbd970b4f 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -563,16 +563,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
&s->container, -1);
}
object_property_set_link(cpuobj, OBJECT(&s->cpu_container[i]),
- "memory", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- object_property_set_link(cpuobj, OBJECT(s), "idau", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ "memory", &error_abort);
+ object_property_set_link(cpuobj, OBJECT(s), "idau", &error_abort);
sysbus_realize(SYS_BUS_DEVICE(cpuobj), &err);
if (err) {
error_propagate(errp, err);
@@ -699,11 +691,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
return;
}
object_property_set_link(OBJECT(&s->mpc[i]), OBJECT(&s->sram[i]),
- "downstream", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ "downstream", &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->mpc[i]), &err);
if (err) {
error_propagate(errp, err);
@@ -754,11 +742,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0,
armsse_get_common_irq_in(s, 3));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]",
+ &error_abort);
qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq);
sysbus_realize(SYS_BUS_DEVICE(&s->timer1), &err);
@@ -769,12 +754,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0,
armsse_get_common_irq_in(s, 4));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
+ object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]",
+ &error_abort);
qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), &err);
@@ -785,11 +766,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
armsse_get_common_irq_in(s, 5));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
- object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]",
+ &error_abort);
if (info->has_mhus) {
/*
@@ -814,12 +792,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
port = g_strdup_printf("port[%d]", i + 3);
mr = sysbus_mmio_get_region(mhu_sbd, 0);
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr),
- port, &err);
+ port, &error_abort);
g_free(port);
- if (err) {
- error_propagate(errp, err);
- return;
- }
/*
* Each MHU has an irq line for each CPU:
@@ -966,11 +940,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
armsse_get_common_irq_in(s, 2));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
- object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->apb_ppc1), &err);
if (err) {
@@ -1019,13 +990,13 @@ static void armsse_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
/* System control registers */
object_property_set_int(OBJECT(&s->sysctl), info->sys_version,
- "SYS_VERSION", &err);
+ "SYS_VERSION", &error_abort);
object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst,
- "CPUWAIT_RST", &err);
+ "CPUWAIT_RST", &error_abort);
object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
- "INITSVTOR0_RST", &err);
+ "INITSVTOR0_RST", &error_abort);
object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
- "INITSVTOR1_RST", &err);
+ "INITSVTOR1_RST", &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->sysctl), &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index ce83586e03..3308211e9c 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -170,11 +170,8 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
object_property_set_link(OBJECT(s->cpu), OBJECT(&s->container), "memory",
&error_abort);
if (object_property_find(OBJECT(s->cpu), "idau", NULL)) {
- object_property_set_link(OBJECT(s->cpu), s->idau, "idau", &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(s->cpu), s->idau, "idau",
+ &error_abort);
}
if (object_property_find(OBJECT(s->cpu), "init-svtor", NULL)) {
object_property_set_uint(OBJECT(s->cpu), s->init_svtor,
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 6da687299f..59a7a1370b 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -228,7 +228,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
int i;
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
- Error *err = NULL, *local_err = NULL;
+ Error *err = NULL;
qemu_irq irq;
/* IO space */
@@ -341,11 +341,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
}
/* I2C */
- object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err);
if (err) {
error_propagate(errp, err);
@@ -363,11 +360,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
}
/* FMC, The number of CS is set at the board level */
- object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram",
+ &error_abort);
object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM],
"sdram-base", &err);
if (err) {
@@ -388,14 +382,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
/* SPI */
for (i = 0; i < sc->spis_num; i++) {
object_property_set_link(OBJECT(&s->spi[i]), OBJECT(s->dram_mr),
- "dram", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err);
- sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err);
- error_propagate(&err, local_err);
+ "dram", &error_abort);
+ object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs",
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err);
if (err) {
error_propagate(errp, err);
return;
@@ -445,12 +435,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
/* Net */
for (i = 0; i < sc->macs_num; i++) {
object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
- &err);
- sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &local_err);
- error_propagate(&err, local_err);
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err);
if (err) {
error_propagate(errp, err);
- return;
+ return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
sc->memmap[ASPEED_ETH1 + i]);
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 810cf9b6cc..311458aa76 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -218,7 +218,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
int i;
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
- Error *err = NULL, *local_err = NULL;
+ Error *err = NULL;
/* IO space */
create_unimplemented_device("aspeed_soc.io", sc->memmap[ASPEED_IOMEM],
@@ -300,11 +300,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
}
/* I2C */
- object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->i2c), &err);
if (err) {
error_propagate(errp, err);
@@ -315,11 +312,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_I2C));
/* FMC, The number of CS is set at the board level */
- object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram",
+ &error_abort);
object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM],
"sdram-base", &err);
if (err) {
@@ -339,9 +333,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
/* SPI */
for (i = 0; i < sc->spis_num; i++) {
- object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err);
- sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &local_err);
- error_propagate(&err, local_err);
+ object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs",
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), &err);
if (err) {
error_propagate(errp, err);
return;
@@ -391,12 +385,11 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
/* Net */
for (i = 0; i < sc->macs_num; i++) {
object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
- &err);
- sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &local_err);
- error_propagate(&err, local_err);
+ &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), &err);
if (err) {
error_propagate(errp, err);
- return;
+ return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
sc->memmap[ASPEED_ETH1 + i]);
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 1e975d7eec..7ffdf62067 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -283,16 +283,12 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
* For the exact details please refer to the Arasan documentation:
* SD3.0_Host_AHB_eMMC4.4_Usersguide_ver5.9_jan11_10.pdf
*/
- object_property_set_uint(OBJECT(&s->sdhci), 3, "sd-spec-version", &err);
+ object_property_set_uint(OBJECT(&s->sdhci), 3, "sd-spec-version",
+ &error_abort);
object_property_set_uint(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg",
- &err);
+ &error_abort);
object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index f32f9bce0f..7ab5c98fbe 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -260,15 +260,13 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
};
object_property_set_uint(OBJECT(&s->esdhc[i]), 2, "sd-spec-version",
- &err);
+ &error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), IMX25_ESDHC_CAPABILITIES,
- "capareg", &err);
+ "capareg",
+ &error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX,
- "vendor", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ "vendor",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index d4bc4fae93..4ae3c3efc2 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -336,15 +336,13 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
/* UHS-I SDIO3.0 SDR104 1.8V ADMA */
object_property_set_uint(OBJECT(&s->esdhc[i]), 3, "sd-spec-version",
- &err);
+ &error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), IMX6_ESDHC_CAPABILITIES,
- "capareg", &err);
+ "capareg",
+ &error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), SDHCI_VENDOR_IMX,
- "vendor", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ "vendor",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
index 6446034711..51b2f256ec 100644
--- a/hw/arm/fsl-imx6ul.c
+++ b/hw/arm/fsl-imx6ul.c
@@ -428,6 +428,9 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
};
object_property_set_uint(OBJECT(&s->eth[i]),
+ s->phy_num[i],
+ "phy-num", &error_abort);
+ object_property_set_uint(OBJECT(&s->eth[i]),
FSL_IMX6UL_ETH_NUM_TX_RINGS,
"tx-ring-num", &error_abort);
qdev_set_nic_properties(DEVICE(&s->eth[i]), &nd_table[i]);
@@ -607,10 +610,17 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_OCRAM_ALIAS_ADDR, &s->ocram_alias);
}
+static Property fsl_imx6ul_properties[] = {
+ DEFINE_PROP_UINT32("fec1-phy-num", FslIMX6ULState, phy_num[0], 0),
+ DEFINE_PROP_UINT32("fec2-phy-num", FslIMX6ULState, phy_num[1], 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void fsl_imx6ul_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
+ device_class_set_props(dc, fsl_imx6ul_properties);
dc->realize = fsl_imx6ul_realize;
dc->desc = "i.MX6UL SOC";
/* Reason: Uses serial_hds and nd_table in realize() directly */
diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
index 2f845cedfc..9033d3f8f3 100644
--- a/hw/arm/mcimx6ul-evk.c
+++ b/hw/arm/mcimx6ul-evk.c
@@ -40,6 +40,8 @@ static void mcimx6ul_evk_init(MachineState *machine)
s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL));
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
+ object_property_set_uint(OBJECT(s), 2, "fec1-phy-num", &error_fatal);
+ object_property_set_uint(OBJECT(s), 1, "fec2-phy-num", &error_fatal);
qdev_realize(DEVICE(s), NULL, &error_fatal);
memory_region_add_subregion(get_system_memory(), FSL_IMX6UL_MMDC_ADDR,
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index 5a8961ddbb..20dd8b5897 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -66,11 +66,7 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
}
object_property_set_link(OBJECT(&s->cpu), OBJECT(&s->container), "memory",
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->cpu), &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
index 105c5e63f2..ceee6aa48d 100644
--- a/hw/arm/pxa2xx_pic.c
+++ b/hw/arm/pxa2xx_pic.c
@@ -11,6 +11,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "hw/arm/pxa.h"
#include "hw/sysbus.h"
@@ -166,7 +167,9 @@ static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset,
case ICHP: /* Highest Priority register */
return pxa2xx_pic_highest(s);
default:
- printf("%s: Bad register offset " REG_FMT "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pxa2xx_pic_mem_read: bad register offset 0x%" HWADDR_PRIx
+ "\n", offset);
return 0;
}
}
@@ -199,7 +202,9 @@ static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset,
s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
break;
default:
- printf("%s: Bad register offset " REG_FMT "\n", __func__, offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pxa2xx_pic_mem_write: bad register offset 0x%"
+ HWADDR_PRIx "\n", offset);
return;
}
pxa2xx_pic_update(opaque);
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index fc18212e68..f020aff974 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -23,36 +23,66 @@
#include "hw/ssi/ssi.h"
#include "hw/block/flash.h"
#include "qemu/timer.h"
+#include "qemu/log.h"
#include "hw/arm/sharpsl.h"
#include "ui/console.h"
#include "hw/audio/wm8750.h"
#include "audio/audio.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
+#include "hw/misc/max111x.h"
#include "migration/vmstate.h"
#include "exec/address-spaces.h"
#include "cpu.h"
-#undef REG_FMT
-#define REG_FMT "0x%02lx"
+enum spitz_model_e { spitz, akita, borzoi, terrier };
+
+typedef struct {
+ MachineClass parent;
+ enum spitz_model_e model;
+ int arm_id;
+} SpitzMachineClass;
+
+typedef struct {
+ MachineState parent;
+ PXA2xxState *mpu;
+ DeviceState *mux;
+ DeviceState *lcdtg;
+ DeviceState *ads7846;
+ DeviceState *max1111;
+ DeviceState *scp0;
+ DeviceState *scp1;
+ DeviceState *misc_gpio;
+} SpitzMachineState;
+
+#define TYPE_SPITZ_MACHINE "spitz-common"
+#define SPITZ_MACHINE(obj) \
+ OBJECT_CHECK(SpitzMachineState, obj, TYPE_SPITZ_MACHINE)
+#define SPITZ_MACHINE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SpitzMachineClass, obj, TYPE_SPITZ_MACHINE)
+#define SPITZ_MACHINE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SpitzMachineClass, klass, TYPE_SPITZ_MACHINE)
+
+#define zaurus_printf(format, ...) \
+ fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__)
/* Spitz Flash */
-#define FLASH_BASE 0x0c000000
-#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */
-#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */
-#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */
-#define FLASH_ECCCNTR 0x0c /* ECC byte counter */
-#define FLASH_ECCCLRR 0x10 /* Clear ECC */
-#define FLASH_FLASHIO 0x14 /* Flash I/O */
-#define FLASH_FLASHCTL 0x18 /* Flash Control */
-
-#define FLASHCTL_CE0 (1 << 0)
-#define FLASHCTL_CLE (1 << 1)
-#define FLASHCTL_ALE (1 << 2)
-#define FLASHCTL_WP (1 << 3)
-#define FLASHCTL_CE1 (1 << 4)
-#define FLASHCTL_RYBY (1 << 5)
-#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
+#define FLASH_BASE 0x0c000000
+#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */
+#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */
+#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */
+#define FLASH_ECCCNTR 0x0c /* ECC byte counter */
+#define FLASH_ECCCLRR 0x10 /* Clear ECC */
+#define FLASH_FLASHIO 0x14 /* Flash I/O */
+#define FLASH_FLASHCTL 0x18 /* Flash Control */
+
+#define FLASHCTL_CE0 (1 << 0)
+#define FLASHCTL_CLE (1 << 1)
+#define FLASHCTL_ALE (1 << 2)
+#define FLASHCTL_WP (1 << 3)
+#define FLASHCTL_CE1 (1 << 4)
+#define FLASHCTL_RYBY (1 << 5)
+#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
#define TYPE_SL_NAND "sl-nand"
#define SL_NAND(obj) OBJECT_CHECK(SLNANDState, (obj), TYPE_SL_NAND)
@@ -74,12 +104,12 @@ static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
int ryby;
switch (addr) {
-#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
+#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
case FLASH_ECCLPLB:
return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
-#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to))
+#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to))
case FLASH_ECCLPUB:
return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
@@ -105,7 +135,9 @@ static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
return ecc_digest(&s->ecc, nand_getio(s->nand));
default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sl_read: bad register offset 0x%02" HWADDR_PRIx "\n",
+ addr);
}
return 0;
}
@@ -136,7 +168,9 @@ static void sl_write(void *opaque, hwaddr addr,
break;
default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sl_write: bad register offset 0x%02" HWADDR_PRIx "\n",
+ addr);
}
}
@@ -191,8 +225,8 @@ static void sl_nand_realize(DeviceState *dev, Error **errp)
/* Spitz Keyboard */
-#define SPITZ_KEY_STROBE_NUM 11
-#define SPITZ_KEY_SENSE_NUM 7
+#define SPITZ_KEY_STROBE_NUM 11
+#define SPITZ_KEY_SENSE_NUM 7
static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
12, 17, 91, 34, 36, 38, 39
@@ -214,11 +248,11 @@ static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
{ 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 },
};
-#define SPITZ_GPIO_AK_INT 13 /* Remote control */
-#define SPITZ_GPIO_SYNC 16 /* Sync button */
-#define SPITZ_GPIO_ON_KEY 95 /* Power button */
-#define SPITZ_GPIO_SWA 97 /* Lid */
-#define SPITZ_GPIO_SWB 96 /* Tablet mode */
+#define SPITZ_GPIO_AK_INT 13 /* Remote control */
+#define SPITZ_GPIO_SYNC 16 /* Sync button */
+#define SPITZ_GPIO_ON_KEY 95 /* Power button */
+#define SPITZ_GPIO_SWA 97 /* Lid */
+#define SPITZ_GPIO_SWB 96 /* Tablet mode */
/* The special buttons are mapped to unused keys */
static const int spitz_gpiomap[5] = {
@@ -300,7 +334,7 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
#define SPITZ_MOD_CTRL (1 << 8)
#define SPITZ_MOD_FN (1 << 9)
-#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
+#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
static void spitz_keyboard_handler(void *opaque, int keycode)
{
@@ -308,25 +342,25 @@ static void spitz_keyboard_handler(void *opaque, int keycode)
uint16_t code;
int mapcode;
switch (keycode) {
- case 0x2a: /* Left Shift */
+ case 0x2a: /* Left Shift */
s->modifiers |= 1;
break;
case 0xaa:
s->modifiers &= ~1;
break;
- case 0x36: /* Right Shift */
+ case 0x36: /* Right Shift */
s->modifiers |= 2;
break;
case 0xb6:
s->modifiers &= ~2;
break;
- case 0x1d: /* Control */
+ case 0x1d: /* Control */
s->modifiers |= 4;
break;
case 0x9d:
s->modifiers &= ~4;
break;
- case 0x38: /* Alt */
+ case 0x38: /* Alt */
s->modifiers |= 8;
break;
case 0xb8:
@@ -536,14 +570,17 @@ static void spitz_keyboard_realize(DeviceState *dev, Error **errp)
/* LCD backlight controller */
-#define LCDTG_RESCTL 0x00
-#define LCDTG_PHACTRL 0x01
-#define LCDTG_DUTYCTRL 0x02
-#define LCDTG_POWERREG0 0x03
-#define LCDTG_POWERREG1 0x04
-#define LCDTG_GPOR3 0x05
-#define LCDTG_PICTRL 0x06
-#define LCDTG_POLCTRL 0x07
+#define LCDTG_RESCTL 0x00
+#define LCDTG_PHACTRL 0x01
+#define LCDTG_DUTYCTRL 0x02
+#define LCDTG_POWERREG0 0x03
+#define LCDTG_POWERREG1 0x04
+#define LCDTG_GPOR3 0x05
+#define LCDTG_PICTRL 0x06
+#define LCDTG_POLCTRL 0x07
+
+#define TYPE_SPITZ_LCDTG "spitz-lcdtg"
+#define SPITZ_LCDTG(obj) OBJECT_CHECK(SpitzLCDTG, (obj), TYPE_SPITZ_LCDTG)
typedef struct {
SSISlave ssidev;
@@ -559,12 +596,9 @@ static void spitz_bl_update(SpitzLCDTG *s)
zaurus_printf("LCD Backlight now off\n");
}
-/* FIXME: Implement GPIO properly and remove this hack. */
-static SpitzLCDTG *spitz_lcdtg;
-
static inline void spitz_bl_bit5(void *opaque, int line, int level)
{
- SpitzLCDTG *s = spitz_lcdtg;
+ SpitzLCDTG *s = opaque;
int prev = s->bl_intensity;
if (level)
@@ -578,14 +612,14 @@ static inline void spitz_bl_bit5(void *opaque, int line, int level)
static inline void spitz_bl_power(void *opaque, int line, int level)
{
- SpitzLCDTG *s = spitz_lcdtg;
+ SpitzLCDTG *s = opaque;
s->bl_power = !!level;
spitz_bl_update(s);
}
static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
{
- SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
+ SpitzLCDTG *s = SPITZ_LCDTG(dev);
int addr;
addr = value >> 5;
value &= 0x1f;
@@ -612,25 +646,29 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
return 0;
}
-static void spitz_lcdtg_realize(SSISlave *dev, Error **errp)
+static void spitz_lcdtg_realize(SSISlave *ssi, Error **errp)
{
- SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
+ SpitzLCDTG *s = SPITZ_LCDTG(ssi);
+ DeviceState *dev = DEVICE(s);
- spitz_lcdtg = s;
s->bl_power = 0;
s->bl_intensity = 0x20;
+
+ qdev_init_gpio_in_named(dev, spitz_bl_bit5, "bl_bit5", 1);
+ qdev_init_gpio_in_named(dev, spitz_bl_power, "bl_power", 1);
}
/* SSP devices */
-#define CORGI_SSP_PORT 2
+#define CORGI_SSP_PORT 2
-#define SPITZ_GPIO_LCDCON_CS 53
-#define SPITZ_GPIO_ADS7846_CS 14
-#define SPITZ_GPIO_MAX1111_CS 20
-#define SPITZ_GPIO_TP_INT 11
+#define SPITZ_GPIO_LCDCON_CS 53
+#define SPITZ_GPIO_ADS7846_CS 14
+#define SPITZ_GPIO_MAX1111_CS 20
+#define SPITZ_GPIO_TP_INT 11
-static DeviceState *max1111;
+#define TYPE_CORGI_SSP "corgi-ssp"
+#define CORGI_SSP(obj) OBJECT_CHECK(CorgiSSPState, (obj), TYPE_CORGI_SSP)
/* "Demux" the signal based on current chipselect */
typedef struct {
@@ -641,7 +679,7 @@ typedef struct {
static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
{
- CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
+ CorgiSSPState *s = CORGI_SSP(dev);
int i;
for (i = 0; i < 3; i++) {
@@ -659,29 +697,18 @@ static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
s->enable[line] = !level;
}
-#define MAX1111_BATT_VOLT 1
-#define MAX1111_BATT_TEMP 2
-#define MAX1111_ACIN_VOLT 3
-
-#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */
-#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */
-#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */
+#define MAX1111_BATT_VOLT 1
+#define MAX1111_BATT_TEMP 2
+#define MAX1111_ACIN_VOLT 3
-static void spitz_adc_temp_on(void *opaque, int line, int level)
-{
- if (!max1111)
- return;
-
- if (level)
- max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP);
- else
- max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
-}
+#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */
+#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */
+#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */
static void corgi_ssp_realize(SSISlave *d, Error **errp)
{
DeviceState *dev = DEVICE(d);
- CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d);
+ CorgiSSPState *s = CORGI_SSP(d);
qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3);
s->bus[0] = ssi_create_bus(dev, "ssi0");
@@ -689,34 +716,36 @@ static void corgi_ssp_realize(SSISlave *d, Error **errp)
s->bus[2] = ssi_create_bus(dev, "ssi2");
}
-static void spitz_ssp_attach(PXA2xxState *cpu)
+static void spitz_ssp_attach(SpitzMachineState *sms)
{
- DeviceState *mux;
- DeviceState *dev;
void *bus;
- mux = ssi_create_slave(cpu->ssp[CORGI_SSP_PORT - 1], "corgi-ssp");
-
- bus = qdev_get_child_bus(mux, "ssi0");
- ssi_create_slave(bus, "spitz-lcdtg");
-
- bus = qdev_get_child_bus(mux, "ssi1");
- dev = ssi_create_slave(bus, "ads7846");
- qdev_connect_gpio_out(dev, 0,
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
-
- bus = qdev_get_child_bus(mux, "ssi2");
- max1111 = ssi_create_slave(bus, "max1111");
- max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
- max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
- max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
-
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
- qdev_get_gpio_in(mux, 0));
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
- qdev_get_gpio_in(mux, 1));
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
- qdev_get_gpio_in(mux, 2));
+ sms->mux = ssi_create_slave(sms->mpu->ssp[CORGI_SSP_PORT - 1],
+ TYPE_CORGI_SSP);
+
+ bus = qdev_get_child_bus(sms->mux, "ssi0");
+ sms->lcdtg = ssi_create_slave(bus, TYPE_SPITZ_LCDTG);
+
+ bus = qdev_get_child_bus(sms->mux, "ssi1");
+ sms->ads7846 = ssi_create_slave(bus, "ads7846");
+ qdev_connect_gpio_out(sms->ads7846, 0,
+ qdev_get_gpio_in(sms->mpu->gpio, SPITZ_GPIO_TP_INT));
+
+ bus = qdev_get_child_bus(sms->mux, "ssi2");
+ sms->max1111 = qdev_new(TYPE_MAX_1111);
+ qdev_prop_set_uint8(sms->max1111, "input1" /* BATT_VOLT */,
+ SPITZ_BATTERY_VOLT);
+ qdev_prop_set_uint8(sms->max1111, "input2" /* BATT_TEMP */, 0);
+ qdev_prop_set_uint8(sms->max1111, "input3" /* ACIN_VOLT */,
+ SPITZ_CHARGEON_ACIN);
+ ssi_realize_and_unref(sms->max1111, bus, &error_fatal);
+
+ qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_LCDCON_CS,
+ qdev_get_gpio_in(sms->mux, 0));
+ qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_ADS7846_CS,
+ qdev_get_gpio_in(sms->mux, 1));
+ qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_MAX1111_CS,
+ qdev_get_gpio_in(sms->mux, 2));
}
/* CF Microdrive */
@@ -735,11 +764,11 @@ static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
/* Wm8750 and Max7310 on I2C */
-#define AKITA_MAX_ADDR 0x18
-#define SPITZ_WM_ADDRL 0x1b
-#define SPITZ_WM_ADDRH 0x1a
+#define AKITA_MAX_ADDR 0x18
+#define SPITZ_WM_ADDRL 0x1b
+#define SPITZ_WM_ADDRH 0x1a
-#define SPITZ_GPIO_WM 5
+#define SPITZ_GPIO_WM 5
static void spitz_wm8750_addr(void *opaque, int line, int level)
{
@@ -779,75 +808,119 @@ static void spitz_akita_i2c_setup(PXA2xxState *cpu)
/* Other peripherals */
-static void spitz_out_switch(void *opaque, int line, int level)
+/*
+ * Encapsulation of some miscellaneous GPIO line behaviour for the Spitz boards.
+ *
+ * QEMU interface:
+ * + named GPIO inputs "green-led", "orange-led", "charging", "discharging":
+ * these currently just print messages that the line has been signalled
+ * + named GPIO input "adc-temp-on": set to cause the battery-temperature
+ * value to be passed to the max111x ADC
+ * + named GPIO output "adc-temp": the ADC value, to be wired up to the max111x
+ */
+#define TYPE_SPITZ_MISC_GPIO "spitz-misc-gpio"
+#define SPITZ_MISC_GPIO(obj) \
+ OBJECT_CHECK(SpitzMiscGPIOState, (obj), TYPE_SPITZ_MISC_GPIO)
+
+typedef struct SpitzMiscGPIOState {
+ SysBusDevice parent_obj;
+
+ qemu_irq adc_value;
+} SpitzMiscGPIOState;
+
+static void spitz_misc_charging(void *opaque, int n, int level)
{
- switch (line) {
- case 0:
- zaurus_printf("Charging %s.\n", level ? "off" : "on");
- break;
- case 1:
- zaurus_printf("Discharging %s.\n", level ? "on" : "off");
- break;
- case 2:
- zaurus_printf("Green LED %s.\n", level ? "on" : "off");
- break;
- case 3:
- zaurus_printf("Orange LED %s.\n", level ? "on" : "off");
- break;
- case 4:
- spitz_bl_bit5(opaque, line, level);
- break;
- case 5:
- spitz_bl_power(opaque, line, level);
- break;
- case 6:
- spitz_adc_temp_on(opaque, line, level);
- break;
- }
+ zaurus_printf("Charging %s.\n", level ? "off" : "on");
}
-#define SPITZ_SCP_LED_GREEN 1
-#define SPITZ_SCP_JK_B 2
-#define SPITZ_SCP_CHRG_ON 3
-#define SPITZ_SCP_MUTE_L 4
-#define SPITZ_SCP_MUTE_R 5
-#define SPITZ_SCP_CF_POWER 6
-#define SPITZ_SCP_LED_ORANGE 7
-#define SPITZ_SCP_JK_A 8
-#define SPITZ_SCP_ADC_TEMP_ON 9
-#define SPITZ_SCP2_IR_ON 1
-#define SPITZ_SCP2_AKIN_PULLUP 2
-#define SPITZ_SCP2_BACKLIGHT_CONT 7
-#define SPITZ_SCP2_BACKLIGHT_ON 8
-#define SPITZ_SCP2_MIC_BIAS 9
-
-static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
- DeviceState *scp0, DeviceState *scp1)
+static void spitz_misc_discharging(void *opaque, int n, int level)
{
- qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
+ zaurus_printf("Discharging %s.\n", level ? "off" : "on");
+}
- qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
- qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
- qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
- qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
+static void spitz_misc_green_led(void *opaque, int n, int level)
+{
+ zaurus_printf("Green LED %s.\n", level ? "off" : "on");
+}
- if (scp1) {
- qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
- qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
- }
+static void spitz_misc_orange_led(void *opaque, int n, int level)
+{
+ zaurus_printf("Orange LED %s.\n", level ? "off" : "on");
+}
+
+static void spitz_misc_adc_temp(void *opaque, int n, int level)
+{
+ SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(opaque);
+ int batt_temp = level ? SPITZ_BATTERY_TEMP : 0;
- qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
+ qemu_set_irq(s->adc_value, batt_temp);
}
-#define SPITZ_GPIO_HSYNC 22
-#define SPITZ_GPIO_SD_DETECT 9
-#define SPITZ_GPIO_SD_WP 81
-#define SPITZ_GPIO_ON_RESET 89
-#define SPITZ_GPIO_BAT_COVER 90
-#define SPITZ_GPIO_CF1_IRQ 105
-#define SPITZ_GPIO_CF1_CD 94
-#define SPITZ_GPIO_CF2_IRQ 106
-#define SPITZ_GPIO_CF2_CD 93
+static void spitz_misc_gpio_init(Object *obj)
+{
+ SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(obj);
+ DeviceState *dev = DEVICE(obj);
+
+ qdev_init_gpio_in_named(dev, spitz_misc_charging, "charging", 1);
+ qdev_init_gpio_in_named(dev, spitz_misc_discharging, "discharging", 1);
+ qdev_init_gpio_in_named(dev, spitz_misc_green_led, "green-led", 1);
+ qdev_init_gpio_in_named(dev, spitz_misc_orange_led, "orange-led", 1);
+ qdev_init_gpio_in_named(dev, spitz_misc_adc_temp, "adc-temp-on", 1);
+
+ qdev_init_gpio_out_named(dev, &s->adc_value, "adc-temp", 1);
+}
+
+#define SPITZ_SCP_LED_GREEN 1
+#define SPITZ_SCP_JK_B 2
+#define SPITZ_SCP_CHRG_ON 3
+#define SPITZ_SCP_MUTE_L 4
+#define SPITZ_SCP_MUTE_R 5
+#define SPITZ_SCP_CF_POWER 6
+#define SPITZ_SCP_LED_ORANGE 7
+#define SPITZ_SCP_JK_A 8
+#define SPITZ_SCP_ADC_TEMP_ON 9
+#define SPITZ_SCP2_IR_ON 1
+#define SPITZ_SCP2_AKIN_PULLUP 2
+#define SPITZ_SCP2_BACKLIGHT_CONT 7
+#define SPITZ_SCP2_BACKLIGHT_ON 8
+#define SPITZ_SCP2_MIC_BIAS 9
+
+static void spitz_scoop_gpio_setup(SpitzMachineState *sms)
+{
+ DeviceState *miscdev = sysbus_create_simple(TYPE_SPITZ_MISC_GPIO, -1, NULL);
+
+ sms->misc_gpio = miscdev;
+
+ qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_CHRG_ON,
+ qdev_get_gpio_in_named(miscdev, "charging", 0));
+ qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_JK_B,
+ qdev_get_gpio_in_named(miscdev, "discharging", 0));
+ qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_GREEN,
+ qdev_get_gpio_in_named(miscdev, "green-led", 0));
+ qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_ORANGE,
+ qdev_get_gpio_in_named(miscdev, "orange-led", 0));
+ qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON,
+ qdev_get_gpio_in_named(miscdev, "adc-temp-on", 0));
+ qdev_connect_gpio_out_named(miscdev, "adc-temp", 0,
+ qdev_get_gpio_in(sms->max1111, MAX1111_BATT_TEMP));
+
+ if (sms->scp1) {
+ qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_CONT,
+ qdev_get_gpio_in_named(sms->lcdtg, "bl_bit5", 0));
+ qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_ON,
+ qdev_get_gpio_in_named(sms->lcdtg, "bl_power", 0));
+ }
+}
+
+#define SPITZ_GPIO_HSYNC 22
+#define SPITZ_GPIO_SD_DETECT 9
+#define SPITZ_GPIO_SD_WP 81
+#define SPITZ_GPIO_ON_RESET 89
+#define SPITZ_GPIO_BAT_COVER 90
+#define SPITZ_GPIO_CF1_IRQ 105
+#define SPITZ_GPIO_CF1_CD 94
+#define SPITZ_GPIO_CF2_IRQ 106
+#define SPITZ_GPIO_CF2_CD 93
static int spitz_hsync;
@@ -905,27 +978,27 @@ static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
}
/* Board init. */
-enum spitz_model_e { spitz, akita, borzoi, terrier };
-
-#define SPITZ_RAM 0x04000000
-#define SPITZ_ROM 0x00800000
+#define SPITZ_RAM 0x04000000
+#define SPITZ_ROM 0x00800000
static struct arm_boot_info spitz_binfo = {
.loader_start = PXA2XX_SDRAM_BASE,
.ram_size = 0x04000000,
};
-static void spitz_common_init(MachineState *machine,
- enum spitz_model_e model, int arm_id)
+static void spitz_common_init(MachineState *machine)
{
+ SpitzMachineClass *smc = SPITZ_MACHINE_GET_CLASS(machine);
+ SpitzMachineState *sms = SPITZ_MACHINE(machine);
+ enum spitz_model_e model = smc->model;
PXA2xxState *mpu;
- DeviceState *scp0, *scp1 = NULL;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *rom = g_new(MemoryRegion, 1);
/* Setup CPU & memory */
mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size,
machine->cpu_type);
+ sms->mpu = mpu;
sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
@@ -935,14 +1008,16 @@ static void spitz_common_init(MachineState *machine,
/* Setup peripherals */
spitz_keyboard_register(mpu);
- spitz_ssp_attach(mpu);
+ spitz_ssp_attach(sms);
- scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
+ sms->scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
if (model != akita) {
- scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
+ sms->scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
+ } else {
+ sms->scp1 = NULL;
}
- spitz_scoop_gpio_setup(mpu, scp0, scp1);
+ spitz_scoop_gpio_setup(sms);
spitz_gpio_setup(mpu, (model == akita) ? 1 : 2);
@@ -958,100 +1033,100 @@ static void spitz_common_init(MachineState *machine,
/* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
spitz_microdrive_attach(mpu, 0);
- spitz_binfo.board_id = arm_id;
+ spitz_binfo.board_id = smc->arm_id;
arm_load_kernel(mpu->cpu, machine, &spitz_binfo);
sl_bootparam_write(SL_PXA_PARAM_BASE);
}
-static void spitz_init(MachineState *machine)
-{
- spitz_common_init(machine, spitz, 0x2c9);
-}
-
-static void borzoi_init(MachineState *machine)
+static void spitz_common_class_init(ObjectClass *oc, void *data)
{
- spitz_common_init(machine, borzoi, 0x33f);
-}
+ MachineClass *mc = MACHINE_CLASS(oc);
-static void akita_init(MachineState *machine)
-{
- spitz_common_init(machine, akita, 0x2e8);
+ mc->block_default_type = IF_IDE;
+ mc->ignore_memory_transaction_failures = true;
+ mc->init = spitz_common_init;
}
-static void terrier_init(MachineState *machine)
-{
- spitz_common_init(machine, terrier, 0x33f);
-}
+static const TypeInfo spitz_common_info = {
+ .name = TYPE_SPITZ_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(SpitzMachineState),
+ .class_size = sizeof(SpitzMachineClass),
+ .class_init = spitz_common_class_init,
+};
static void akitapda_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
- mc->init = akita_init;
- mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
+ smc->model = akita;
+ smc->arm_id = 0x2e8;
}
static const TypeInfo akitapda_type = {
.name = MACHINE_TYPE_NAME("akita"),
- .parent = TYPE_MACHINE,
+ .parent = TYPE_SPITZ_MACHINE,
.class_init = akitapda_class_init,
};
static void spitzpda_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
- mc->init = spitz_init;
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
+ smc->model = spitz;
+ smc->arm_id = 0x2c9;
}
static const TypeInfo spitzpda_type = {
.name = MACHINE_TYPE_NAME("spitz"),
- .parent = TYPE_MACHINE,
+ .parent = TYPE_SPITZ_MACHINE,
.class_init = spitzpda_class_init,
};
static void borzoipda_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
- mc->init = borzoi_init;
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
+ smc->model = borzoi;
+ smc->arm_id = 0x33f;
}
static const TypeInfo borzoipda_type = {
.name = MACHINE_TYPE_NAME("borzoi"),
- .parent = TYPE_MACHINE,
+ .parent = TYPE_SPITZ_MACHINE,
.class_init = borzoipda_class_init,
};
static void terrierpda_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
- mc->init = terrier_init;
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
+ smc->model = terrier;
+ smc->arm_id = 0x33f;
}
static const TypeInfo terrierpda_type = {
.name = MACHINE_TYPE_NAME("terrier"),
- .parent = TYPE_MACHINE,
+ .parent = TYPE_SPITZ_MACHINE,
.class_init = terrierpda_class_init,
};
static void spitz_machine_init(void)
{
+ type_register_static(&spitz_common_info);
type_register_static(&akitapda_type);
type_register_static(&spitzpda_type);
type_register_static(&borzoipda_type);
@@ -1152,7 +1227,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo corgi_ssp_info = {
- .name = "corgi-ssp",
+ .name = TYPE_CORGI_SSP,
.parent = TYPE_SSI_SLAVE,
.instance_size = sizeof(CorgiSSPState),
.class_init = corgi_ssp_class_init,
@@ -1181,18 +1256,30 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo spitz_lcdtg_info = {
- .name = "spitz-lcdtg",
+ .name = TYPE_SPITZ_LCDTG,
.parent = TYPE_SSI_SLAVE,
.instance_size = sizeof(SpitzLCDTG),
.class_init = spitz_lcdtg_class_init,
};
+static const TypeInfo spitz_misc_gpio_info = {
+ .name = TYPE_SPITZ_MISC_GPIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SpitzMiscGPIOState),
+ .instance_init = spitz_misc_gpio_init,
+ /*
+ * No class_init required: device has no internal state so does not
+ * need to set up reset or vmstate, and does not have a realize method.
+ */
+};
+
static void spitz_register_types(void)
{
type_register_static(&corgi_ssp_info);
type_register_static(&spitz_lcdtg_info);
type_register_static(&spitz_keyboard_info);
type_register_static(&sl_nand_info);
+ type_register_static(&spitz_misc_gpio_info);
}
type_init(spitz_register_types)
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index 19487544f0..56aef686c9 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -154,7 +154,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
/* ADC 1 to 3 */
object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS,
- "num-lines", &err);
+ "num-lines", &error_abort);
qdev_realize(DEVICE(s->adc_irqs), NULL, &err);
if (err != NULL) {
error_propagate(errp, err);
diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c
index c12d9f999d..cf9228d8e7 100644
--- a/hw/arm/stm32f405_soc.c
+++ b/hw/arm/stm32f405_soc.c
@@ -172,7 +172,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
object_property_set_int(OBJECT(&s->adc_irqs), STM_NUM_ADCS,
- "num-lines", &err);
+ "num-lines", &error_abort);
qdev_realize(DEVICE(&s->adc_irqs), NULL, &err);
if (err != NULL) {
error_propagate(errp, err);
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 1384a2cf2a..91f0df7b13 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -749,6 +749,7 @@ static void build_fadt_rev5(GArray *table_data, BIOSLinker *linker,
static void
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
Aml *scope, *dsdt;
MachineState *ms = MACHINE(vms);
const MemMapEntry *memmap = vms->memmap;
@@ -767,7 +768,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
acpi_dsdt_add_cpus(scope, vms->smp_cpus);
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
- acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
+ if (vmc->acpi_expose_flash) {
+ acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
+ }
acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]);
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index cd0834ce7f..c78972fb79 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -217,11 +217,9 @@ static bool cpu_type_valid(const char *cpu)
static void create_kaslr_seed(VirtMachineState *vms, const char *node)
{
- Error *err = NULL;
uint64_t seed;
- if (qemu_guest_getrandom(&seed, sizeof(seed), &err)) {
- error_free(err);
+ if (qemu_guest_getrandom(&seed, sizeof(seed), NULL)) {
return;
}
qemu_fdt_setprop_u64(vms->fdt, node, "kaslr-seed", seed);
@@ -602,6 +600,7 @@ static void create_its(VirtMachineState *vms)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base);
fdt_add_its_gic_node(vms);
+ vms->msi_controller = VIRT_MSI_CTRL_ITS;
}
static void create_v2m(VirtMachineState *vms)
@@ -622,6 +621,7 @@ static void create_v2m(VirtMachineState *vms)
}
fdt_add_v2m_gic_node(vms);
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
}
static void create_gic(VirtMachineState *vms)
@@ -2200,8 +2200,36 @@ out:
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
+ hwaddr db_start = 0, db_end = 0;
+ char *resv_prop_str;
+
+ switch (vms->msi_controller) {
+ case VIRT_MSI_CTRL_NONE:
+ return;
+ case VIRT_MSI_CTRL_ITS:
+ /* GITS_TRANSLATER page */
+ db_start = base_memmap[VIRT_GIC_ITS].base + 0x10000;
+ db_end = base_memmap[VIRT_GIC_ITS].base +
+ base_memmap[VIRT_GIC_ITS].size - 1;
+ break;
+ case VIRT_MSI_CTRL_GICV2M:
+ /* MSI_SETSPI_NS page */
+ db_start = base_memmap[VIRT_GIC_V2M].base;
+ db_end = db_start + base_memmap[VIRT_GIC_V2M].size - 1;
+ break;
+ }
+ resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u",
+ db_start, db_end,
+ VIRTIO_IOMMU_RESV_MEM_T_MSI);
+
+ qdev_prop_set_uint32(dev, "len-reserved-regions", 1);
+ qdev_prop_set_string(dev, "reserved-regions[0]", resv_prop_str);
+ g_free(resv_prop_str);
}
}
@@ -2482,9 +2510,12 @@ DEFINE_VIRT_MACHINE_AS_LATEST(5, 1)
static void virt_machine_5_0_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
virt_machine_5_1_options(mc);
compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
mc->numa_mem_supported = true;
+ vmc->acpi_expose_flash = true;
}
DEFINE_VIRT_MACHINE(5, 0)
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index a0f4095990..e1f22f5868 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -111,9 +111,12 @@ typedef struct {
int pos;
} ZipitLCD;
+#define TYPE_ZIPIT_LCD "zipit-lcd"
+#define ZIPIT_LCD(obj) OBJECT_CHECK(ZipitLCD, (obj), TYPE_ZIPIT_LCD)
+
static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value)
{
- ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+ ZipitLCD *z = ZIPIT_LCD(dev);
uint16_t val;
if (z->selected) {
z->buf[z->pos] = value & 0xff;
@@ -153,7 +156,7 @@ static void z2_lcd_cs(void *opaque, int line, int level)
static void zipit_lcd_realize(SSISlave *dev, Error **errp)
{
- ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+ ZipitLCD *z = ZIPIT_LCD(dev);
z->selected = 0;
z->enabled = 0;
z->pos = 0;
@@ -185,7 +188,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo zipit_lcd_info = {
- .name = "zipit-lcd",
+ .name = TYPE_ZIPIT_LCD,
.parent = TYPE_SSI_SLAVE,
.instance_size = sizeof(ZipitLCD),
.class_init = zipit_lcd_class_init,
@@ -325,7 +328,7 @@ static void z2_init(MachineState *machine)
type_register_static(&zipit_lcd_info);
type_register_static(&aer915_info);
- z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd");
+ z2_lcd = ssi_create_slave(mpu->ssp[1], TYPE_ZIPIT_LCD);
bus = pxa2xx_i2c_bus(mpu->i2c[0]);
i2c_create_slave(bus, TYPE_AER915, 0x55);
wm = i2c_create_slave(bus, TYPE_WM8750, 0x1b);
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 262089c0c9..f9a4428bd6 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -1056,7 +1056,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
/* Spawn a new virtio-serial bus on which the ports will ride as devices */
qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
dev, vdev->bus_name);
- qbus_set_hotplug_handler(BUS(&vser->bus), OBJECT(vser), errp);
+ qbus_set_hotplug_handler(BUS(&vser->bus), OBJECT(vser));
vser->bus.vser = vser;
QTAILQ_INIT(&vser->ports);
@@ -1147,7 +1147,7 @@ static void virtio_serial_device_unrealize(DeviceState *dev)
g_free(vser->post_load);
}
- qbus_set_hotplug_handler(BUS(&vser->bus), NULL, &error_abort);
+ qbus_set_hotplug_handler(BUS(&vser->bus), NULL);
virtio_cleanup(vdev);
}
diff --git a/hw/core/bus.c b/hw/core/bus.c
index 6cc28b334e..544dd8a6fa 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -23,15 +23,15 @@
#include "qemu/module.h"
#include "qapi/error.h"
-void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp)
+void qbus_set_hotplug_handler(BusState *bus, Object *handler)
{
object_property_set_link(OBJECT(bus), handler,
- QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
+ QDEV_HOTPLUG_HANDLER_PROPERTY, &error_abort);
}
-void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp)
+void qbus_set_bus_hotplug_handler(BusState *bus)
{
- qbus_set_hotplug_handler(bus, OBJECT(bus), errp);
+ qbus_set_hotplug_handler(bus, OBJECT(bus));
}
int qbus_walk_children(BusState *bus,
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 71f8aca7c6..ca7771f307 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -15,6 +15,7 @@
#include "chardev/char.h"
#include "qemu/uuid.h"
#include "qemu/units.h"
+#include "qemu/cutils.h"
void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
Error **errp)
@@ -578,6 +579,94 @@ const PropertyInfo qdev_prop_macaddr = {
.set = set_mac,
};
+/* --- Reserved Region --- */
+
+/*
+ * Accepted syntax:
+ * <low address>:<high address>:<type>
+ * where low/high addresses are uint64_t in hexadecimal
+ * and type is a non-negative decimal integer
+ */
+static void get_reserved_region(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
+ char buffer[64];
+ char *p = buffer;
+ int rc;
+
+ rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
+ rr->low, rr->high, rr->type);
+ assert(rc < sizeof(buffer));
+
+ visit_type_str(v, name, &p, errp);
+}
+
+static void set_reserved_region(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ const char *endptr;
+ char *str;
+ int ret;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ ret = qemu_strtou64(str, &endptr, 16, &rr->low);
+ if (ret) {
+ error_setg(errp, "start address of '%s'"
+ " must be a hexadecimal integer", name);
+ goto out;
+ }
+ if (*endptr != ':') {
+ goto separator_error;
+ }
+
+ ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high);
+ if (ret) {
+ error_setg(errp, "end address of '%s'"
+ " must be a hexadecimal integer", name);
+ goto out;
+ }
+ if (*endptr != ':') {
+ goto separator_error;
+ }
+
+ ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
+ if (ret) {
+ error_setg(errp, "type of '%s'"
+ " must be a non-negative decimal integer", name);
+ }
+ goto out;
+
+separator_error:
+ error_setg(errp, "reserved region fields must be separated with ':'");
+out:
+ g_free(str);
+ return;
+}
+
+const PropertyInfo qdev_prop_reserved_region = {
+ .name = "reserved_region",
+ .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
+ .get = get_reserved_region,
+ .set = set_reserved_region,
+};
+
/* --- on/off/auto --- */
const PropertyInfo qdev_prop_on_off_auto = {
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
index 9228b40b1a..56bf82fe07 100644
--- a/hw/display/ads7846.c
+++ b/hw/display/ads7846.c
@@ -29,6 +29,9 @@ typedef struct {
int output;
} ADS7846State;
+#define TYPE_ADS7846 "ads7846"
+#define ADS7846(obj) OBJECT_CHECK(ADS7846State, (obj), TYPE_ADS7846)
+
/* Control-byte bitfields */
#define CB_PD0 (1 << 0)
#define CB_PD1 (1 << 1)
@@ -61,7 +64,7 @@ static void ads7846_int_update(ADS7846State *s)
static uint32_t ads7846_transfer(SSISlave *dev, uint32_t value)
{
- ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
+ ADS7846State *s = ADS7846(dev);
switch (s->cycle ++) {
case 0:
@@ -139,7 +142,7 @@ static const VMStateDescription vmstate_ads7846 = {
static void ads7846_realize(SSISlave *d, Error **errp)
{
DeviceState *dev = DEVICE(d);
- ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d);
+ ADS7846State *s = ADS7846(d);
qdev_init_gpio_out(dev, &s->interrupt, 1);
@@ -166,7 +169,7 @@ static void ads7846_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ads7846_info = {
- .name = "ads7846",
+ .name = TYPE_ADS7846,
.parent = TYPE_SSI_SLAVE,
.instance_size = sizeof(ADS7846State),
.class_init = ads7846_class_init,
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 7216f7e08f..4c3ad8f47b 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -86,8 +86,8 @@ static void ati_vga_switch_mode(ATIVGAState *s)
break;
default:
qemu_log_mask(LOG_UNIMP, "Unsupported bpp value\n");
+ return;
}
- assert(bpp != 0);
DPRINTF("Switching to %dx%d %d %d @ %x\n", h, v, stride, bpp, offs);
vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_ENABLE);
vbe_ioport_write_data(&s->vga, 0, VBE_DISPI_DISABLED);
@@ -361,6 +361,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
case MC_STATUS:
val = 5;
break;
+ case MEM_SDRAM_MODE_REG:
+ if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
+ val = BIT(28) | BIT(20);
+ }
+ break;
case RBBM_STATUS:
case GUI_STAT:
val = 64; /* free CMDFIFO entries */
@@ -389,22 +394,28 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
case 0xf00 ... 0xfff:
val = pci_default_read_config(&s->dev, addr - 0xf00, size);
break;
- case CUR_OFFSET:
- val = s->regs.cur_offset;
+ case CUR_OFFSET ... CUR_OFFSET + 3:
+ val = ati_reg_read_offs(s->regs.cur_offset, addr - CUR_OFFSET, size);
break;
- case CUR_HORZ_VERT_POSN:
- val = s->regs.cur_hv_pos;
- val |= s->regs.cur_offset & BIT(31);
+ case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3:
+ val = ati_reg_read_offs(s->regs.cur_hv_pos,
+ addr - CUR_HORZ_VERT_POSN, size);
+ if (addr + size > CUR_HORZ_VERT_POSN + 3) {
+ val |= (s->regs.cur_offset & BIT(31)) >> (4 - size);
+ }
break;
- case CUR_HORZ_VERT_OFF:
- val = s->regs.cur_hv_offs;
- val |= s->regs.cur_offset & BIT(31);
+ case CUR_HORZ_VERT_OFF ... CUR_HORZ_VERT_OFF + 3:
+ val = ati_reg_read_offs(s->regs.cur_hv_offs,
+ addr - CUR_HORZ_VERT_OFF, size);
+ if (addr + size > CUR_HORZ_VERT_OFF + 3) {
+ val |= (s->regs.cur_offset & BIT(31)) >> (4 - size);
+ }
break;
- case CUR_CLR0:
- val = s->regs.cur_color0;
+ case CUR_CLR0 ... CUR_CLR0 + 3:
+ val = ati_reg_read_offs(s->regs.cur_color0, addr - CUR_CLR0, size);
break;
- case CUR_CLR1:
- val = s->regs.cur_color1;
+ case CUR_CLR1 ... CUR_CLR1 + 3:
+ val = ati_reg_read_offs(s->regs.cur_color1, addr - CUR_CLR1, size);
break;
case DST_OFFSET:
val = s->regs.dst_offset;
@@ -679,48 +690,71 @@ static void ati_mm_write(void *opaque, hwaddr addr,
case 0xf00 ... 0xfff:
/* read-only copy of PCI config space so ignore writes */
break;
- case CUR_OFFSET:
- if (s->regs.cur_offset != (data & 0x87fffff0)) {
- s->regs.cur_offset = data & 0x87fffff0;
+ case CUR_OFFSET ... CUR_OFFSET + 3:
+ {
+ uint32_t t = s->regs.cur_offset;
+
+ ati_reg_write_offs(&t, addr - CUR_OFFSET, data, size);
+ t &= 0x87fffff0;
+ if (s->regs.cur_offset != t) {
+ s->regs.cur_offset = t;
ati_cursor_define(s);
}
break;
- case CUR_HORZ_VERT_POSN:
- s->regs.cur_hv_pos = data & 0x3fff0fff;
- if (data & BIT(31)) {
- s->regs.cur_offset |= data & BIT(31);
+ }
+ case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3:
+ {
+ uint32_t t = s->regs.cur_hv_pos | (s->regs.cur_offset & BIT(31));
+
+ ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_POSN, data, size);
+ s->regs.cur_hv_pos = t & 0x3fff0fff;
+ if (t & BIT(31)) {
+ s->regs.cur_offset |= t & BIT(31);
} else if (s->regs.cur_offset & BIT(31)) {
s->regs.cur_offset &= ~BIT(31);
ati_cursor_define(s);
}
if (!s->cursor_guest_mode &&
- (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(data & BIT(31))) {
+ (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(t & BIT(31))) {
dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
s->regs.cur_hv_pos & 0xffff, 1);
}
break;
+ }
case CUR_HORZ_VERT_OFF:
- s->regs.cur_hv_offs = data & 0x3f003f;
- if (data & BIT(31)) {
- s->regs.cur_offset |= data & BIT(31);
+ {
+ uint32_t t = s->regs.cur_hv_offs | (s->regs.cur_offset & BIT(31));
+
+ ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_OFF, data, size);
+ s->regs.cur_hv_offs = t & 0x3f003f;
+ if (t & BIT(31)) {
+ s->regs.cur_offset |= t & BIT(31);
} else if (s->regs.cur_offset & BIT(31)) {
s->regs.cur_offset &= ~BIT(31);
ati_cursor_define(s);
}
break;
- case CUR_CLR0:
- if (s->regs.cur_color0 != (data & 0xffffff)) {
- s->regs.cur_color0 = data & 0xffffff;
+ }
+ case CUR_CLR0 ... CUR_CLR0 + 3:
+ {
+ uint32_t t = s->regs.cur_color0;
+
+ ati_reg_write_offs(&t, addr - CUR_CLR0, data, size);
+ t &= 0xffffff;
+ if (s->regs.cur_color0 != t) {
+ s->regs.cur_color0 = t;
ati_cursor_define(s);
}
break;
- case CUR_CLR1:
+ }
+ case CUR_CLR1 ... CUR_CLR1 + 3:
/*
* Update cursor unconditionally here because some clients set up
* other registers before actually writing cursor data to memory at
* offset so we would miss cursor change unless always updating here
*/
- s->regs.cur_color1 = data & 0xffffff;
+ ati_reg_write_offs(&s->regs.cur_color1, addr - CUR_CLR1, data, size);
+ s->regs.cur_color1 &= 0xffffff;
ati_cursor_define(s);
break;
case DST_OFFSET:
diff --git a/hw/display/ati_dbg.c b/hw/display/ati_dbg.c
index 0ebbd36f14..bd0ecd48c7 100644
--- a/hw/display/ati_dbg.c
+++ b/hw/display/ati_dbg.c
@@ -42,6 +42,7 @@ static struct ati_regdesc ati_reg_names[] = {
{"MC_FB_LOCATION", 0x0148},
{"MC_AGP_LOCATION", 0x014C},
{"MC_STATUS", 0x0150},
+ {"MEM_SDRAM_MODE_REG", 0x0158},
{"MEM_POWER_MISC", 0x015c},
{"AGP_BASE", 0x0170},
{"AGP_CNTL", 0x0174},
diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h
index ebd37ee30d..d6282b2ef2 100644
--- a/hw/display/ati_regs.h
+++ b/hw/display/ati_regs.h
@@ -60,6 +60,7 @@
#define MC_FB_LOCATION 0x0148
#define MC_AGP_LOCATION 0x014C
#define MC_STATUS 0x0150
+#define MEM_SDRAM_MODE_REG 0x0158
#define MEM_POWER_MISC 0x015c
#define AGP_BASE 0x0170
#define AGP_CNTL 0x0174
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index c6263808a2..7c0e5eef2d 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -282,6 +282,10 @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
newconf.base = s->vcram_base | (value & 0xc0000000);
newconf.base += BCM2835_FB_OFFSET;
+ /* Copy fields which we don't want to change from the existing config */
+ newconf.pixo = s->config.pixo;
+ newconf.alpha = s->config.alpha;
+
bcm2835_fb_validate_config(&newconf);
pitch = bcm2835_fb_get_pitch(&newconf);
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index a7fc08c52b..9cccc68c35 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -39,15 +39,7 @@
#include "qemu/range.h"
#include "ui/pixel_ops.h"
#include "qemu/bswap.h"
-
-/*#define DEBUG_SM501*/
-/*#define DEBUG_BITBLT*/
-
-#ifdef DEBUG_SM501
-#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define SM501_DPRINTF(fmt, ...) do {} while (0)
-#endif
+#include "trace.h"
#define MMIO_BASE_OFFSET 0x3e00000
#define MMIO_SIZE 0x200000
@@ -684,10 +676,11 @@ static void sm501_2d_operation(SM501State *s)
{
int cmd = (s->twoD_control >> 16) & 0x1F;
int rtl = s->twoD_control & BIT(27);
- int format = (s->twoD_stretch >> 20) & 0x3;
- int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */
+ int format = (s->twoD_stretch >> 20) & 3;
+ int bypp = 1 << format; /* bytes per pixel */
+ int rop_mode = (s->twoD_control >> 15) & 1; /* 1 for rop2, else rop3 */
/* 1 if rop2 source is the pattern, otherwise the source is the bitmap */
- int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1;
+ int rop2_source_is_pattern = (s->twoD_control >> 14) & 1;
int rop = s->twoD_control & 0xFF;
unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
unsigned int dst_y = s->twoD_destination & 0xFFFF;
@@ -697,6 +690,7 @@ static void sm501_2d_operation(SM501State *s)
unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF;
int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
+ bool overlap = false;
if ((s->twoD_stretch >> 16) & 0xF) {
qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n");
@@ -723,9 +717,9 @@ static void sm501_2d_operation(SM501State *s)
dst_y -= height - 1;
}
- if (dst_base >= get_local_mem_size(s) || dst_base +
- (dst_x + width + (dst_y + height) * (dst_pitch + width)) *
- (1 << format) >= get_local_mem_size(s)) {
+ if (dst_base >= get_local_mem_size(s) ||
+ dst_base + (dst_x + width + (dst_y + height) * dst_pitch) * bypp >=
+ get_local_mem_size(s)) {
qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n");
return;
}
@@ -749,9 +743,9 @@ static void sm501_2d_operation(SM501State *s)
src_y -= height - 1;
}
- if (src_base >= get_local_mem_size(s) || src_base +
- (src_x + width + (src_y + height) * (src_pitch + width)) *
- (1 << format) >= get_local_mem_size(s)) {
+ if (src_base >= get_local_mem_size(s) ||
+ src_base + (src_x + width + (src_y + height) * src_pitch) * bypp >=
+ get_local_mem_size(s)) {
qemu_log_mask(LOG_GUEST_ERROR,
"sm501: 2D op src is outside vram.\n");
return;
@@ -763,19 +757,9 @@ static void sm501_2d_operation(SM501State *s)
uint8_t *d = s->local_mem + dst_base;
for (y = 0; y < height; y++) {
- i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format);
- for (x = 0; x < width; x++, i += (1 << format)) {
- switch (format) {
- case 0:
- d[i] = ~d[i];
- break;
- case 1:
- *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i];
- break;
- case 2:
- *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i];
- break;
- }
+ i = (dst_x + (dst_y + y) * dst_pitch) * bypp;
+ for (x = 0; x < width; x++, i += bypp) {
+ stn_he_p(&d[i], bypp, ~ldn_he_p(&d[i], bypp));
}
}
} else {
@@ -788,40 +772,57 @@ static void sm501_2d_operation(SM501State *s)
(rop2_source_is_pattern ?
" with pattern source" : ""));
}
- /* Check for overlaps, this could be made more exact */
- uint32_t sb, se, db, de;
- sb = src_base + src_x + src_y * (width + src_pitch);
- se = sb + width + height * (width + src_pitch);
- db = dst_base + dst_x + dst_y * (width + dst_pitch);
- de = db + width + height * (width + dst_pitch);
- if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) {
- /* regions may overlap: copy via temporary */
- int free_buf = 0, llb = width * (1 << format);
- int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
+ /* Ignore no-op blits, some guests seem to do this */
+ if (src_base == dst_base && src_pitch == dst_pitch &&
+ src_x == dst_x && src_y == dst_y) {
+ break;
+ }
+ /* Some clients also do 1 pixel blits, avoid overhead for these */
+ if (width == 1 && height == 1) {
+ unsigned int si = (src_x + src_y * src_pitch) * bypp;
+ unsigned int di = (dst_x + dst_y * dst_pitch) * bypp;
+ stn_he_p(&s->local_mem[dst_base + di], bypp,
+ ldn_he_p(&s->local_mem[src_base + si], bypp));
+ break;
+ }
+ /* If reverse blit do simple check for overlaps */
+ if (rtl && src_base == dst_base && src_pitch == dst_pitch) {
+ overlap = (src_x < dst_x + width && src_x + width > dst_x &&
+ src_y < dst_y + height && src_y + height > dst_y);
+ } else if (rtl) {
+ unsigned int sb, se, db, de;
+ sb = src_base + (src_x + src_y * src_pitch) * bypp;
+ se = sb + (width + (height - 1) * src_pitch) * bypp;
+ db = dst_base + (dst_x + dst_y * dst_pitch) * bypp;
+ de = db + (width + (height - 1) * dst_pitch) * bypp;
+ overlap = (db < se && sb < de);
+ }
+ if (overlap) {
+ /* pixman can't do reverse blit: copy via temporary */
+ int tmp_stride = DIV_ROUND_UP(width * bypp, sizeof(uint32_t));
uint32_t *tmp = tmp_buf;
if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) {
tmp = g_malloc(tmp_stride * sizeof(uint32_t) * height);
- free_buf = 1;
}
pixman_blt((uint32_t *)&s->local_mem[src_base], tmp,
- src_pitch * (1 << format) / sizeof(uint32_t),
- tmp_stride, 8 * (1 << format), 8 * (1 << format),
+ src_pitch * bypp / sizeof(uint32_t),
+ tmp_stride, 8 * bypp, 8 * bypp,
src_x, src_y, 0, 0, width, height);
pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base],
tmp_stride,
- dst_pitch * (1 << format) / sizeof(uint32_t),
- 8 * (1 << format), 8 * (1 << format),
+ dst_pitch * bypp / sizeof(uint32_t),
+ 8 * bypp, 8 * bypp,
0, 0, dst_x, dst_y, width, height);
- if (free_buf) {
+ if (tmp != tmp_buf) {
g_free(tmp);
}
} else {
pixman_blt((uint32_t *)&s->local_mem[src_base],
(uint32_t *)&s->local_mem[dst_base],
- src_pitch * (1 << format) / sizeof(uint32_t),
- dst_pitch * (1 << format) / sizeof(uint32_t),
- 8 * (1 << format), 8 * (1 << format),
+ src_pitch * bypp / sizeof(uint32_t),
+ dst_pitch * bypp / sizeof(uint32_t),
+ 8 * bypp, 8 * bypp,
src_x, src_y, dst_x, dst_y, width, height);
}
}
@@ -837,9 +838,14 @@ static void sm501_2d_operation(SM501State *s)
color = cpu_to_le16(color);
}
- pixman_fill((uint32_t *)&s->local_mem[dst_base],
- dst_pitch * (1 << format) / sizeof(uint32_t),
- 8 * (1 << format), dst_x, dst_y, width, height, color);
+ if (width == 1 && height == 1) {
+ unsigned int i = (dst_x + dst_y * dst_pitch) * bypp;
+ stn_he_p(&s->local_mem[dst_base + i], bypp, color);
+ } else {
+ pixman_fill((uint32_t *)&s->local_mem[dst_base],
+ dst_pitch * bypp / sizeof(uint32_t),
+ 8 * bypp, dst_x, dst_y, width, height, color);
+ }
break;
}
default:
@@ -851,7 +857,7 @@ static void sm501_2d_operation(SM501State *s)
if (dst_base >= get_fb_addr(s, crt) &&
dst_base <= get_fb_addr(s, crt) + fb_len) {
int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch +
- dst_x + width) * (1 << format));
+ dst_x + width) * bypp);
if (dst_len) {
memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len);
}
@@ -863,7 +869,6 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
{
SM501State *s = (SM501State *)opaque;
uint32_t ret = 0;
- SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
switch (addr) {
case SM501_SYSTEM_CONTROL:
@@ -915,7 +920,7 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config"
"register read. addr=%" HWADDR_PRIx "\n", addr);
}
-
+ trace_sm501_system_config_read(addr, ret);
return ret;
}
@@ -923,9 +928,8 @@ static void sm501_system_config_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
SM501State *s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
- (uint32_t)addr, (uint32_t)value);
+ trace_sm501_system_config_write((uint32_t)addr, (uint32_t)value);
switch (addr) {
case SM501_SYSTEM_CONTROL:
s->system_control &= 0x10DB0000;
@@ -1011,9 +1015,7 @@ static uint64_t sm501_i2c_read(void *opaque, hwaddr addr, unsigned size)
qemu_log_mask(LOG_UNIMP, "sm501 i2c : not implemented register read."
" addr=0x%" HWADDR_PRIx "\n", addr);
}
-
- SM501_DPRINTF("sm501 i2c regs : read addr=%" HWADDR_PRIx " val=%x\n",
- addr, ret);
+ trace_sm501_i2c_read((uint32_t)addr, ret);
return ret;
}
@@ -1021,9 +1023,8 @@ static void sm501_i2c_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
SM501State *s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 i2c regs : write addr=%" HWADDR_PRIx
- " val=%" PRIx64 "\n", addr, value);
+ trace_sm501_i2c_write((uint32_t)addr, (uint32_t)value);
switch (addr) {
case SM501_I2C_BYTE_COUNT:
s->i2c_byte_count = value & 0xf;
@@ -1037,25 +1038,19 @@ static void sm501_i2c_write(void *opaque, hwaddr addr, uint64_t value,
s->i2c_status |= (res ? SM501_I2C_STATUS_ERROR : 0);
if (!res) {
int i;
- SM501_DPRINTF("sm501 i2c : transferring %d bytes to 0x%x\n",
- s->i2c_byte_count + 1, s->i2c_addr >> 1);
for (i = 0; i <= s->i2c_byte_count; i++) {
res = i2c_send_recv(s->i2c_bus, &s->i2c_data[i],
!(s->i2c_addr & 1));
if (res) {
- SM501_DPRINTF("sm501 i2c : transfer failed"
- " i=%d, res=%d\n", i, res);
s->i2c_status |= SM501_I2C_STATUS_ERROR;
return;
}
}
if (i) {
- SM501_DPRINTF("sm501 i2c : transferred %d bytes\n", i);
s->i2c_status = SM501_I2C_STATUS_COMPLETE;
}
}
} else {
- SM501_DPRINTF("sm501 i2c : end transfer\n");
i2c_end_transfer(s->i2c_bus);
s->i2c_status &= ~SM501_I2C_STATUS_ERROR;
}
@@ -1095,7 +1090,8 @@ static const MemoryRegionOps sm501_i2c_ops = {
static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
{
SM501State *s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
+
+ trace_sm501_palette_read((uint32_t)addr);
/* TODO : consider BYTE/WORD access */
/* TODO : consider endian */
@@ -1108,8 +1104,8 @@ static void sm501_palette_write(void *opaque, hwaddr addr,
uint32_t value)
{
SM501State *s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
- (int)addr, value);
+
+ trace_sm501_palette_write((uint32_t)addr, value);
/* TODO : consider BYTE/WORD access */
/* TODO : consider endian */
@@ -1124,7 +1120,6 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
{
SM501State *s = (SM501State *)opaque;
uint32_t ret = 0;
- SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
switch (addr) {
@@ -1229,7 +1224,7 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
"read. addr=%" HWADDR_PRIx "\n", addr);
}
-
+ trace_sm501_disp_ctrl_read((uint32_t)addr, ret);
return ret;
}
@@ -1237,9 +1232,8 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
SM501State *s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
- (unsigned)addr, (unsigned)value);
+ trace_sm501_disp_ctrl_write((uint32_t)addr, (uint32_t)value);
switch (addr) {
case SM501_DC_PANEL_CONTROL:
s->dc_panel_control = value & 0x0FFF73FF;
@@ -1384,7 +1378,6 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
{
SM501State *s = (SM501State *)opaque;
uint32_t ret = 0;
- SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
switch (addr) {
case SM501_2D_SOURCE:
@@ -1454,7 +1447,7 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
"read. addr=%" HWADDR_PRIx "\n", addr);
}
-
+ trace_sm501_2d_engine_read((uint32_t)addr, ret);
return ret;
}
@@ -1462,9 +1455,8 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
SM501State *s = (SM501State *)opaque;
- SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
- (unsigned)addr, (unsigned)value);
+ trace_sm501_2d_engine_write((uint32_t)addr, (uint32_t)value);
switch (addr) {
case SM501_2D_SOURCE:
s->twoD_source = value;
@@ -1495,6 +1487,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr,
s->twoD_background = value;
break;
case SM501_2D_STRETCH:
+ if (((value >> 20) & 3) == 3) {
+ value &= ~BIT(20);
+ }
s->twoD_stretch = value;
break;
case SM501_2D_COLOR_COMPARE:
@@ -1819,8 +1814,6 @@ static void sm501_init(SM501State *s, DeviceState *dev,
uint32_t local_mem_bytes)
{
s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes);
- SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", get_local_mem_size(s),
- s->local_mem_size_index);
/* local memory */
memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local",
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index c3bdb18742..32d27f008a 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -66,9 +66,13 @@ typedef struct {
uint8_t framebuffer[128 * 80 / 2];
} ssd0323_state;
+#define TYPE_SSD0323 "ssd0323"
+#define SSD0323(obj) OBJECT_CHECK(ssd0323_state, (obj), TYPE_SSD0323)
+
+
static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
{
- ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
+ ssd0323_state *s = SSD0323(dev);
switch (s->mode) {
case SSD0323_DATA:
@@ -346,7 +350,7 @@ static const GraphicHwOps ssd0323_ops = {
static void ssd0323_realize(SSISlave *d, Error **errp)
{
DeviceState *dev = DEVICE(d);
- ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d);
+ ssd0323_state *s = SSD0323(d);
s->col_end = 63;
s->row_end = 79;
@@ -368,7 +372,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ssd0323_info = {
- .name = "ssd0323",
+ .name = TYPE_SSD0323,
.parent = TYPE_SSI_SLAVE,
.instance_size = sizeof(ssd0323_state),
.class_init = ssd0323_class_init,
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 72d4c9812c..970d6bac5d 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -161,3 +161,15 @@ cg3_write(uint32_t addr, uint32_t val, unsigned size) "write addr:0x%06"PRIx32"
# dpcd.c
dpcd_read(uint32_t addr, uint8_t val) "read addr:0x%"PRIx32" val:0x%02x"
dpcd_write(uint32_t addr, uint8_t val) "write addr:0x%"PRIx32" val:0x%02x"
+
+# sm501.c
+sm501_system_config_read(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_system_config_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_i2c_read(uint32_t addr, uint8_t val) "addr=0x%x, val=0x%x"
+sm501_i2c_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_palette_read(uint32_t addr) "addr=0x%x"
+sm501_palette_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_disp_ctrl_read(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_disp_ctrl_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_2d_engine_read(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
+sm501_2d_engine_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index b532fe8b5f..41b88b878d 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -44,7 +44,7 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
for (i = 0; i < g->conf.max_outputs; i++) {
object_property_set_link(OBJECT(g->scanout[i].con),
OBJECT(vpci_dev),
- "device", errp);
+ "device", &error_abort);
}
}
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 68a062ece6..67f409e106 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -154,7 +154,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
for (i = 0; i < g->conf.max_outputs; i++) {
object_property_set_link(OBJECT(g->scanout[i].con),
OBJECT(vpci_dev),
- "device", errp);
+ "device", &error_abort);
}
}
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index f02aca6f40..2d7dbbb92d 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -346,7 +346,7 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp)
d = qdev_new(TYPE_LANCE);
object_property_add_child(OBJECT(dev), "lance", OBJECT(d));
qdev_set_nic_properties(d, nd);
- object_property_set_link(OBJECT(d), OBJECT(dev), "dma", errp);
+ object_property_set_link(OBJECT(d), OBJECT(dev), "dma", &error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(d), &error_fatal);
}
@@ -379,7 +379,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp)
}
espdma = qdev_new(TYPE_SPARC32_ESPDMA_DEVICE);
- object_property_set_link(OBJECT(espdma), iommu, "iommu", errp);
+ object_property_set_link(OBJECT(espdma), iommu, "iommu", &error_abort);
object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma));
sysbus_realize_and_unref(SYS_BUS_DEVICE(espdma), &error_fatal);
@@ -394,7 +394,7 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(sbd, 0));
ledma = qdev_new(TYPE_SPARC32_LEDMA_DEVICE);
- object_property_set_link(OBJECT(ledma), iommu, "iommu", errp);
+ object_property_set_link(OBJECT(ledma), iommu, "iommu", &error_abort);
object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma));
sysbus_realize_and_unref(SYS_BUS_DEVICE(ledma), &error_fatal);
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 6a9df2c4db..a069637bf2 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -537,7 +537,6 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
&s->rx_control_dev);
- Error *local_err = NULL;
int i;
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
@@ -548,11 +547,8 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
(Object **)&cs->dma,
object_property_allow_set_link,
OBJ_PROP_LINK_STRONG);
- object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err);
- object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err);
- if (local_err) {
- goto xilinx_axidma_realize_fail;
- }
+ object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &error_abort);
+ object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &error_abort);
for (i = 0; i < 2; i++) {
struct Stream *st = &s->streams[i];
@@ -567,10 +563,6 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
address_space_init(&s->as,
s->dma_mr ? s->dma_mr : get_system_memory(), "dma");
- return;
-
-xilinx_axidma_realize_fail:
- error_propagate(errp, local_err);
}
static void xilinx_axidma_init(Object *obj)
diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c
index 9a12c68342..258e926493 100644
--- a/hw/gpio/zaurus.c
+++ b/hw/gpio/zaurus.c
@@ -22,9 +22,7 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-
-#undef REG_FMT
-#define REG_FMT "0x%02lx"
+#include "qemu/log.h"
/* SCOOP devices */
@@ -104,7 +102,9 @@ static uint64_t scoop_read(void *opaque, hwaddr addr,
case SCOOP_GPRR:
return s->gpio_level;
default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "scoop_read: bad register offset 0x%02" HWADDR_PRIx "\n",
+ addr);
}
return 0;
@@ -150,7 +150,9 @@ static void scoop_write(void *opaque, hwaddr addr,
scoop_gpio_handler_update(s);
break;
default:
- zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "scoop_write: bad register offset 0x%02" HWADDR_PRIx "\n",
+ addr);
}
}
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index b26d30da57..087f601666 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -1549,7 +1549,9 @@ static void amdvi_realize(DeviceState *dev, Error **errp)
/* This device should take care of IOMMU PCI properties */
x86_iommu->type = TYPE_AMD;
- qdev_realize(DEVICE(&s->pci), &bus->qbus, errp);
+ if (!qdev_realize(DEVICE(&s->pci), &bus->qbus, errp)) {
+ return;
+ }
ret = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
AMDVI_CAPAB_SIZE, errp);
if (ret < 0) {
@@ -1578,7 +1580,7 @@ static void amdvi_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR);
pci_setup_iommu(bus, amdvi_host_dma_iommu, s);
- s->devid = object_property_get_int(OBJECT(&s->pci), "addr", errp);
+ s->devid = object_property_get_int(OBJECT(&s->pci), "addr", &error_abort);
msi_init(&s->pci.dev, 0, 1, true, false, errp);
amdvi_init(s);
}
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 34229b45c7..93f7371a56 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -118,14 +118,16 @@ uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms,
void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp)
{
- Object *cpu = NULL;
Error *local_err = NULL;
-
- cpu = object_new(MACHINE(x86ms)->cpu_type);
+ Object *cpu = object_new(MACHINE(x86ms)->cpu_type);
object_property_set_uint(cpu, apic_id, "apic-id", &local_err);
+ if (local_err) {
+ goto out;
+ }
qdev_realize(DEVICE(cpu), NULL, &local_err);
+out:
object_unref(cpu);
error_propagate(errp, local_err);
}
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index cdfab19826..0d7f3cf673 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -100,10 +100,12 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
/* Inter-Thread Communication Unit */
if (itu_present) {
object_initialize_child(OBJECT(dev), "itu", &s->itu, TYPE_MIPS_ITU);
- object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err);
- object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err);
+ object_property_set_int(OBJECT(&s->itu), 16, "num-fifo",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores",
+ &error_abort);
object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present",
- &err);
+ &error_abort);
if (saar_present) {
s->itu.saar = &env->CP0_SAAR;
}
@@ -119,8 +121,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
/* Cluster Power Controller */
object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_MIPS_CPC);
- object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp", &err);
- object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running", &err);
+ object_property_set_int(OBJECT(&s->cpc), s->num_vp, "num-vp",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->cpc), 1, "vp-start-running",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->cpc), &err);
if (err != NULL) {
error_propagate(errp, err);
@@ -132,8 +136,10 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
/* Global Interrupt Controller */
object_initialize_child(OBJECT(dev), "gic", &s->gic, TYPE_MIPS_GIC);
- object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", &err);
- object_property_set_int(OBJECT(&s->gic), 128, "num-irq", &err);
+ object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->gic), 128, "num-irq",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->gic), &err);
if (err != NULL) {
error_propagate(errp, err);
@@ -147,11 +153,16 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
gcr_base = env->CP0_CMGCRBase << 4;
object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_MIPS_GCR);
- object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err);
- object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err);
- object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err);
- object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", &err);
- object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err);
+ object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev",
+ &error_abort);
+ object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base",
+ &error_abort);
+ object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic",
+ &error_abort);
+ object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc",
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->gcr), &err);
if (err != NULL) {
error_propagate(errp, err);
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index 8ba7af073c..3251c79f46 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -136,7 +136,8 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
sysbus_connect_irq(sysbus_dev, 0, irq0);
sysbus_connect_irq(sysbus_dev, 1, irq1);
qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
- object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp);
+ object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma",
+ &error_abort);
macio_ide_register_dma(ide);
qdev_realize(DEVICE(ide), BUS(&s->macio_bus), errp);
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
index 2b87bdee5b..7e6723f343 100644
--- a/hw/misc/max111x.c
+++ b/hw/misc/max111x.c
@@ -11,29 +11,11 @@
*/
#include "qemu/osdep.h"
+#include "hw/misc/max111x.h"
#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
-
-typedef struct {
- SSISlave parent_obj;
-
- qemu_irq interrupt;
- uint8_t tb1, rb2, rb3;
- int cycle;
-
- uint8_t input[8];
- int inputs, com;
-} MAX111xState;
-
-#define TYPE_MAX_111X "max111x"
-
-#define MAX_111X(obj) \
- OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X)
-
-#define TYPE_MAX_1110 "max1110"
-#define TYPE_MAX_1111 "max1111"
+#include "hw/qdev-properties.h"
/* Control-byte bitfields */
#define CB_PD0 (1 << 0)
@@ -127,27 +109,24 @@ static const VMStateDescription vmstate_max111x = {
}
};
+static void max111x_input_set(void *opaque, int line, int value)
+{
+ MAX111xState *s = MAX_111X(opaque);
+
+ assert(line >= 0 && line < s->inputs);
+ s->input[line] = value;
+}
+
static int max111x_init(SSISlave *d, int inputs)
{
DeviceState *dev = DEVICE(d);
MAX111xState *s = MAX_111X(dev);
qdev_init_gpio_out(dev, &s->interrupt, 1);
+ qdev_init_gpio_in(dev, max111x_input_set, inputs);
s->inputs = inputs;
- /* TODO: add a user interface for setting these */
- s->input[0] = 0xf0;
- s->input[1] = 0xe0;
- s->input[2] = 0xd0;
- s->input[3] = 0xc0;
- s->input[4] = 0xb0;
- s->input[5] = 0xa0;
- s->input[6] = 0x90;
- s->input[7] = 0x80;
- s->com = 0;
- vmstate_register(VMSTATE_IF(dev), VMSTATE_INSTANCE_ID_ANY,
- &vmstate_max111x, s);
return 0;
}
@@ -161,18 +140,51 @@ static void max1111_realize(SSISlave *dev, Error **errp)
max111x_init(dev, 4);
}
-void max111x_set_input(DeviceState *dev, int line, uint8_t value)
+static void max111x_reset(DeviceState *dev)
{
MAX111xState *s = MAX_111X(dev);
- assert(line >= 0 && line < s->inputs);
- s->input[line] = value;
+ int i;
+
+ for (i = 0; i < s->inputs; i++) {
+ s->input[i] = s->reset_input[i];
+ }
+ s->com = 0;
+ s->tb1 = 0;
+ s->rb2 = 0;
+ s->rb3 = 0;
+ s->cycle = 0;
}
+static Property max1110_properties[] = {
+ /* Reset values for ADC inputs */
+ DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0),
+ DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0),
+ DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0),
+ DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property max1111_properties[] = {
+ /* Reset values for ADC inputs */
+ DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0),
+ DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0),
+ DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0),
+ DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0),
+ DEFINE_PROP_UINT8("input4", MAX111xState, reset_input[4], 0xb0),
+ DEFINE_PROP_UINT8("input5", MAX111xState, reset_input[5], 0xa0),
+ DEFINE_PROP_UINT8("input6", MAX111xState, reset_input[6], 0x90),
+ DEFINE_PROP_UINT8("input7", MAX111xState, reset_input[7], 0x80),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void max111x_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
k->transfer = max111x_transfer;
+ dc->reset = max111x_reset;
+ dc->vmsd = &vmstate_max111x;
}
static const TypeInfo max111x_info = {
@@ -186,8 +198,10 @@ static const TypeInfo max111x_info = {
static void max1110_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
k->realize = max1110_realize;
+ device_class_set_props(dc, max1110_properties);
}
static const TypeInfo max1110_info = {
@@ -199,8 +213,10 @@ static const TypeInfo max1110_info = {
static void max1111_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
k->realize = max1111_realize;
+ device_class_set_props(dc, max1111_properties);
}
static const TypeInfo max1111_info = {
diff --git a/hw/misc/pca9552.c b/hw/misc/pca9552.c
index 80caa9ec8f..68b574d084 100644
--- a/hw/misc/pca9552.c
+++ b/hw/misc/pca9552.c
@@ -410,6 +410,7 @@ static const TypeInfo pca955x_info = {
.instance_init = pca955x_initfn,
.instance_size = sizeof(PCA955xState),
.class_init = pca955x_class_init,
+ .class_size = sizeof(PCA955xClass),
.abstract = true,
};
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index eefedc252d..2c14804041 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -280,12 +280,16 @@ static void imx_phy_reset(IMXFECState *s)
static uint32_t imx_phy_read(IMXFECState *s, int reg)
{
uint32_t val;
+ uint32_t phy = reg / 32;
- if (reg > 31) {
- /* we only advertise one phy */
+ if (phy != s->phy_num) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad phy num %u\n",
+ TYPE_IMX_FEC, __func__, phy);
return 0;
}
+ reg %= 32;
+
switch (reg) {
case 0: /* Basic Control */
val = s->phy_control;
@@ -331,20 +335,25 @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
break;
}
- trace_imx_phy_read(val, reg);
+ trace_imx_phy_read(val, phy, reg);
return val;
}
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
{
- trace_imx_phy_write(val, reg);
+ uint32_t phy = reg / 32;
- if (reg > 31) {
- /* we only advertise one phy */
+ if (phy != s->phy_num) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad phy num %u\n",
+ TYPE_IMX_FEC, __func__, phy);
return;
}
+ reg %= 32;
+
+ trace_imx_phy_write(val, phy, reg);
+
switch (reg) {
case 0: /* Basic Control */
if (val & 0x8000) {
@@ -926,7 +935,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
extract32(value,
18, 10)));
} else {
- /* This a write operation */
+ /* This is a write operation */
imx_phy_write(s, extract32(value, 18, 10), extract32(value, 0, 16));
}
/* raise the interrupt as the PHY operation is done */
@@ -1315,6 +1324,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
static Property imx_eth_properties[] = {
DEFINE_NIC_PROPERTIES(IMXFECState, conf),
DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1),
+ DEFINE_PROP_UINT32("phy-num", IMXFECState, phy_num, 0),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/net/trace-events b/hw/net/trace-events
index e6875c4c0f..5db45456d9 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -413,8 +413,8 @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries"
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
# imx_fec.c
-imx_phy_read(uint32_t val, int reg) "0x%04"PRIx32" <= reg[%d]"
-imx_phy_write(uint32_t val, int reg) "0x%04"PRIx32" => reg[%d]"
+imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]"
+imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]"
imx_phy_update_link(const char *s) "%s"
imx_phy_reset(void) ""
imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x"
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index aff67a92df..9bb5578e5d 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3129,7 +3129,7 @@ static bool failover_replug_primary(VirtIONet *n, Error **errp)
if (err) {
goto out;
}
- hotplug_handler_plug(hotplug_ctrl, n->primary_dev, errp);
+ hotplug_handler_plug(hotplug_ctrl, n->primary_dev, &err);
}
out:
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index c2f40b8ea9..679a359f9a 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -980,7 +980,6 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev);
XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(
&s->rx_control_dev);
- Error *local_err = NULL;
object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
(Object **) &ds->enet,
@@ -990,11 +989,8 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
(Object **) &cs->enet,
object_property_allow_set_link,
OBJ_PROP_LINK_STRONG);
- object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err);
- object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err);
- if (local_err) {
- goto xilinx_enet_realize_fail;
- }
+ object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &error_abort);
+ object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &error_abort);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
@@ -1008,10 +1004,6 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
s->rxmem = g_malloc(s->c_rxmem);
s->txmem = g_malloc(s->c_txmem);
- return;
-
-xilinx_enet_realize_fail:
- error_propagate(errp, local_err);
}
static void xilinx_enet_init(Object *obj)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index b22dedc88c..de0fae10ab 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2123,7 +2123,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
if (!pci_bus_is_express(pci_get_bus(pci_dev))) {
error_setg(errp, "failover primary device must be on "
"PCIExpress bus");
- error_propagate(errp, local_err);
pci_qdev_unrealize(DEVICE(pci_dev));
return;
}
@@ -2131,7 +2130,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
if (class_id != PCI_CLASS_NETWORK_ETHERNET) {
error_setg(errp, "failover primary device is not an "
"Ethernet device");
- error_propagate(errp, local_err);
pci_qdev_unrealize(DEVICE(pci_dev));
return;
}
@@ -2141,7 +2139,6 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
} else {
error_setg(errp, "failover: primary device must be in its own "
"PCI slot");
- error_propagate(errp, local_err);
pci_qdev_unrealize(DEVICE(pci_dev));
return;
}
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 086d0dfceb..5b48bae0f6 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -574,7 +574,7 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s)
dev->exp.hpev_notified = false;
qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))),
- OBJECT(dev), NULL);
+ OBJECT(dev));
}
void pcie_cap_slot_reset(PCIDevice *dev)
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index 99d65d5c4c..b00dce629c 100644
--- a/hw/pci/shpc.c
+++ b/hw/pci/shpc.c
@@ -649,7 +649,7 @@ int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar,
shpc_cap_update_dword(d);
memory_region_add_subregion(bar, offset, &shpc->mmio);
- qbus_set_hotplug_handler(BUS(sec_bus), OBJECT(d), NULL);
+ qbus_set_hotplug_handler(BUS(sec_bus), OBJECT(d));
d->cap_present |= QEMU_PCI_CAP_SHPC;
return 0;
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 4c185bcc13..f6f034d039 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2731,6 +2731,7 @@ static void spapr_machine_init(MachineState *machine)
error_report_err(resize_hpt_err);
exit(1);
}
+ error_free(resize_hpt_err);
spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
@@ -3032,8 +3033,7 @@ static void spapr_machine_init(MachineState *machine)
register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1,
&savevm_htab_handlers, spapr);
- qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
- &error_fatal);
+ qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine));
qemu_register_boot_set(spapr_boot_set, spapr);
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 2689104295..951bcdf2c0 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -1163,16 +1163,14 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
if (!drc->fdt) {
- Error *local_err = NULL;
void *fdt;
int fdt_size;
fdt = create_device_tree(&fdt_size);
if (drck->dt_populate(drc, spapr, fdt, &drc->fdt_start_offset,
- &local_err)) {
+ NULL)) {
g_free(fdt);
- error_free(local_err);
rc = SPAPR_DR_CC_RESPONSE_ERROR;
goto out;
}
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 329002ac04..0f00e2421f 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1719,7 +1719,7 @@ static void spapr_phb_unrealize(DeviceState *dev)
address_space_remove_listeners(&sphb->iommu_as);
address_space_destroy(&sphb->iommu_as);
- qbus_set_hotplug_handler(BUS(phb->bus), NULL, &error_abort);
+ qbus_set_hotplug_handler(BUS(phb->bus), NULL);
pci_unregister_root_bus(phb->bus);
memory_region_del_subregion(get_system_memory(), &sphb->iowindow);
@@ -1868,7 +1868,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
}
phb->bus = bus;
- qbus_set_hotplug_handler(BUS(phb->bus), OBJECT(sphb), NULL);
+ qbus_set_hotplug_handler(BUS(phb->bus), OBJECT(sphb));
/*
* Initialize PHB address space.
diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
index e26c382259..f59fe52f0f 100644
--- a/hw/riscv/riscv_hart.c
+++ b/hw/riscv/riscv_hart.c
@@ -40,19 +40,13 @@ static void riscv_harts_cpu_reset(void *opaque)
cpu_reset(CPU(cpu));
}
-static void riscv_hart_realize(RISCVHartArrayState *s, int idx,
+static bool riscv_hart_realize(RISCVHartArrayState *s, int idx,
char *cpu_type, Error **errp)
{
- Error *err = NULL;
-
object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type);
s->harts[idx].env.mhartid = s->hartid_base + idx;
qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
- qdev_realize(DEVICE(&s->harts[idx]), NULL, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp);
}
static void riscv_harts_realize(DeviceState *dev, Error **errp)
@@ -63,7 +57,9 @@ static void riscv_harts_realize(DeviceState *dev, Error **errp)
s->harts = g_new0(RISCVCPU, s->num_harts);
for (n = 0; n < s->num_harts; n++) {
- riscv_hart_realize(s, n, s->cpu_type, errp);
+ if (!riscv_hart_realize(s, n, s->cpu_type, errp)) {
+ return;
+ }
}
}
diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c
index b11ffa0edc..669c21adc2 100644
--- a/hw/riscv/sifive_clint.c
+++ b/hw/riscv/sifive_clint.c
@@ -181,7 +181,7 @@ static const MemoryRegionOps sifive_clint_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
- .max_access_size = 4
+ .max_access_size = 8
}
};
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
index 4f216c5585..c20c192034 100644
--- a/hw/riscv/sifive_plic.c
+++ b/hw/riscv/sifive_plic.c
@@ -166,6 +166,9 @@ static void sifive_plic_update(SiFivePLICState *plic)
static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid)
{
int i, j;
+ uint32_t max_irq = 0;
+ uint32_t max_prio = plic->target_priority[addrid];
+
for (i = 0; i < plic->bitfield_words; i++) {
uint32_t pending_enabled_not_claimed =
(plic->pending[i] & ~plic->claimed[i]) &
@@ -177,14 +180,18 @@ static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid)
int irq = (i << 5) + j;
uint32_t prio = plic->source_priority[irq];
int enabled = pending_enabled_not_claimed & (1 << j);
- if (enabled && prio > plic->target_priority[addrid]) {
- sifive_plic_set_pending(plic, irq, false);
- sifive_plic_set_claimed(plic, irq, true);
- return irq;
+ if (enabled && prio > max_prio) {
+ max_irq = irq;
+ max_prio = prio;
}
}
}
- return 0;
+
+ if (max_irq) {
+ sifive_plic_set_pending(plic, max_irq, false);
+ sifive_plic_set_claimed(plic, max_irq, true);
+ }
+ return max_irq;
}
static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
@@ -248,8 +255,8 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
plic->addr_config[addrid].hartid,
mode_to_char(plic->addr_config[addrid].mode),
value);
- sifive_plic_print_state(plic);
}
+ sifive_plic_update(plic);
return value;
}
}
@@ -280,6 +287,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
qemu_log("plic: write priority: irq=%d priority=%d\n",
irq, plic->source_priority[irq]);
}
+ sifive_plic_update(plic);
return;
} else if (addr >= plic->pending_base && /* 1 bit per source */
addr < plic->pending_base + (plic->num_sources >> 3))
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 7d051e7c92..a1d2edfe13 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -677,11 +677,15 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
memmap[SIFIVE_U_CLINT].size, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false);
- sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
+ return;
+ }
sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);
qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16);
- sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+ return;
+ }
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_GPIO].base);
/* Pass all GPIOs to the SOC layer so they are available to the board */
@@ -695,7 +699,9 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
}
qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
- sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) {
+ return;
+ }
sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
if (nd->used) {
diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c
index c4e3188ad6..8bcf8ece9d 100644
--- a/hw/s390x/ap-bridge.c
+++ b/hw/s390x/ap-bridge.c
@@ -58,7 +58,7 @@ void s390_init_ap(void)
bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS);
/* Enable hotplugging */
- qbus_set_hotplug_handler(bus, OBJECT(dev), &error_abort);
+ qbus_set_hotplug_handler(bus, OBJECT(dev));
}
static void ap_bridge_class_init(ObjectClass *oc, void *data)
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index e37a54d3f2..9d793d671e 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -111,7 +111,7 @@ VirtualCssBus *virtual_css_bus_init(void)
cbus = VIRTUAL_CSS_BUS(bus);
/* Enable hotplugging */
- qbus_set_hotplug_handler(bus, OBJECT(dev), &error_abort);
+ qbus_set_hotplug_handler(bus, OBJECT(dev));
css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
0, &error_abort);
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index a13978bb37..736965c928 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -637,22 +637,24 @@ static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
{
- uint8_t ind_old, ind_new;
+ uint8_t expected, actual;
hwaddr len = 1;
- uint8_t *ind_addr;
+ /* avoid multiple fetches */
+ uint8_t volatile *ind_addr;
ind_addr = cpu_physical_memory_map(ind_loc, &len, true);
if (!ind_addr) {
s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0);
return -1;
}
+ actual = *ind_addr;
do {
- ind_old = *ind_addr;
- ind_new = ind_old | to_be_set;
- } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
- cpu_physical_memory_unmap(ind_addr, len, 1, len);
+ expected = actual;
+ actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set);
+ } while (actual != expected);
+ cpu_physical_memory_unmap((void *)ind_addr, len, 1, len);
- return ind_old;
+ return actual;
}
static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
@@ -751,19 +753,11 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(b, s390_pci_dma_iommu, s);
bus = BUS(b);
- qbus_set_hotplug_handler(bus, OBJECT(dev), &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ qbus_set_hotplug_handler(bus, OBJECT(dev));
phb->bus = b;
s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL));
- qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev), &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
+ qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev));
s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,
NULL, g_free);
@@ -921,7 +915,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
- qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s), errp);
+ qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s));
if (dev->hotplugged) {
pci_default_write_config(pdev, PCI_PRIMARY_BUS,
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index c1f4bb1d33..3c988a000b 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -786,9 +786,10 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
uint8_t to_be_set)
{
- uint8_t ind_old, ind_new;
+ uint8_t expected, actual;
hwaddr len = 1;
- uint8_t *ind_addr;
+ /* avoid multiple fetches */
+ uint8_t volatile *ind_addr;
ind_addr = cpu_physical_memory_map(ind_loc, &len, true);
if (!ind_addr) {
@@ -796,14 +797,15 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
__func__, sch->cssid, sch->ssid, sch->schid);
return -1;
}
+ actual = *ind_addr;
do {
- ind_old = *ind_addr;
- ind_new = ind_old | to_be_set;
- } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
- trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new);
- cpu_physical_memory_unmap(ind_addr, len, 1, len);
+ expected = actual;
+ actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set);
+ } while (actual != expected);
+ trace_virtio_ccw_set_ind(ind_loc, actual, actual | to_be_set);
+ cpu_physical_memory_unmap((void *)ind_addr, len, 1, len);
- return ind_old;
+ return actual;
}
static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 27843bb04b..b878a08080 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -107,7 +107,7 @@ void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host,
qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS, host, bus_name);
bus->busnr = next_scsi_bus++;
bus->info = info;
- qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
+ qbus_set_bus_hotplug_handler(BUS(bus));
}
static void scsi_dma_restart_bh(void *opaque)
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 9b72094a61..b49775269e 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -934,7 +934,7 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
scsi_bus_new(&s->bus, sizeof(s->bus), dev,
&virtio_scsi_scsi_info, vdev->bus_name);
/* override default SCSI bus hotplug-handler, with virtio-scsi's one */
- qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev), &error_abort);
+ qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev));
virtio_scsi_dataplane_setup(s, errp);
}
@@ -958,7 +958,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev)
{
VirtIOSCSI *s = VIRTIO_SCSI(dev);
- qbus_set_hotplug_handler(BUS(&s->bus), NULL, &error_abort);
+ qbus_set_hotplug_handler(BUS(&s->bus), NULL);
virtio_scsi_common_unrealize(dev);
}
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index ec5bf9ea34..df07ab6bfb 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -1147,7 +1147,7 @@ pvscsi_realizefn(PCIDevice *pci_dev, Error **errp)
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
&pvscsi_scsi_info, NULL);
/* override default SCSI bus hotplug-handler, with pvscsi's one */
- qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s), &error_abort);
+ qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s));
pvscsi_reset_state(s);
}
diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c
index 482e97191e..afdb8aa0c0 100644
--- a/hw/sd/milkymist-memcard.c
+++ b/hw/sd/milkymist-memcard.c
@@ -280,9 +280,8 @@ static void milkymist_memcard_realize(DeviceState *dev, Error **errp)
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
carddev = qdev_new(TYPE_SD_CARD);
qdev_prop_set_drive(carddev, "drive", blk);
- qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err);
- if (err) {
- error_setg(errp, "failed to init SD card: %s", error_get_pretty(err));
+ if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), &err)) {
+ error_propagate_prepend(errp, err, "failed to init SD card: %s");
return;
}
s->enabled = blk && blk_is_inserted(blk);
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 25cec2ddea..25cdf4c966 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -74,7 +74,7 @@ typedef struct {
static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
{
- ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
+ ssi_sd_state *s = SSI_SD(dev);
/* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */
if (s->mode == SSI_SD_DATA_READ && val == 0x4d) {
@@ -241,7 +241,7 @@ static const VMStateDescription vmstate_ssi_sd = {
static void ssi_sd_realize(SSISlave *d, Error **errp)
{
- ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
+ ssi_sd_state *s = SSI_SD(d);
DeviceState *carddev;
DriveInfo *dinfo;
Error *err = NULL;
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 67b48c31cd..a35d7ebb26 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -90,11 +90,16 @@ static const TypeInfo ssi_slave_info = {
.abstract = true,
};
+bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp)
+{
+ return qdev_realize_and_unref(dev, &bus->parent_obj, errp);
+}
+
DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
{
DeviceState *dev = qdev_new(name);
- qdev_realize_and_unref(dev, &bus->parent_obj, &error_fatal);
+ ssi_realize_and_unref(dev, bus, &error_fatal);
return dev;
}
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index a81aee2051..957559b18d 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -84,7 +84,7 @@ void usb_bus_new(USBBus *bus, size_t bus_size,
USBBusOps *ops, DeviceState *host)
{
qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
- qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
+ qbus_set_bus_hotplug_handler(BUS(bus));
bus->ops = ops;
bus->busnr = next_usb_bus++;
QTAILQ_INIT(&bus->free);
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 168428156b..15a2243101 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -634,7 +634,6 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
error_reportf_err(err,
"usb-mtp: failed to add watch for %s: ",
o->path);
- error_free(err);
} else {
trace_usb_mtp_file_monitor_event(s->dev.addr, o->path,
"Watch Added");
@@ -1279,7 +1278,6 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
if (err) {
error_reportf_err(err,
"usb-mtp: file monitoring init failed: ");
- error_free(err);
} else {
QTAILQ_INIT(&s->events);
}
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index ada18c1983..fcfe216594 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1320,7 +1320,7 @@ static void ccid_realize(USBDevice *dev, Error **errp)
usb_desc_init(dev);
qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev),
NULL);
- qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev), &error_abort);
+ qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev));
s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
s->bulk = usb_ep_get(dev, USB_TOKEN_IN, CCID_BULK_IN_EP);
s->card = NULL;
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 6427a0047d..23109f69bb 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -74,3 +74,4 @@ virtio_iommu_get_domain(uint32_t domain_id) "Alloc domain=%d"
virtio_iommu_put_domain(uint32_t domain_id) "Free domain=%d"
virtio_iommu_translate_out(uint64_t virt_addr, uint64_t phys_addr, uint32_t sid) "0x%"PRIx64" -> 0x%"PRIx64 " for sid=%d"
virtio_iommu_report_fault(uint8_t reason, uint32_t flags, uint32_t endpoint, uint64_t addr) "FAULT reason=%d flags=%d endpoint=%d address =0x%"PRIx64
+virtio_iommu_fill_resv_property(uint32_t devid, uint8_t subtype, uint64_t start, uint64_t end) "dev= %d, type=%d start=0x%"PRIx64" end=0x%"PRIx64
diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c
index 632533abaf..592abc9279 100644
--- a/hw/virtio/virtio-iommu-pci.c
+++ b/hw/virtio/virtio-iommu-pci.c
@@ -33,6 +33,9 @@ struct VirtIOIOMMUPCI {
static Property virtio_iommu_pci_properties[] = {
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_PROP_ARRAY("reserved-regions", VirtIOIOMMUPCI,
+ vdev.nb_reserved_regions, vdev.reserved_regions,
+ qdev_prop_reserved_region, ReservedRegion),
DEFINE_PROP_END_OF_LIST(),
};
@@ -40,6 +43,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VirtIOIOMMUPCI *dev = VIRTIO_IOMMU_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIOIOMMU *s = VIRTIO_IOMMU(vdev);
if (!qdev_get_machine_hotplug_handler(DEVICE(vpci_dev))) {
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
@@ -48,15 +52,22 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
"%s machine fails to create iommu-map device tree bindings",
mc->name);
error_append_hint(errp,
- "Check you machine implements a hotplug handler "
+ "Check your machine implements a hotplug handler "
"for the virtio-iommu-pci device\n");
error_append_hint(errp, "Check the guest is booted without FW or with "
"-no-acpi\n");
return;
}
+ for (int i = 0; i < s->nb_reserved_regions; i++) {
+ if (s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_RESERVED &&
+ s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) {
+ error_setg(errp, "reserved region %d has an invalid type", i);
+ error_append_hint(errp, "Valid values are 0 and 1\n");
+ }
+ }
object_property_set_link(OBJECT(dev),
OBJECT(pci_get_bus(&vpci_dev->pci_dev)),
- "primary-bus", errp);
+ "primary-bus", &error_abort);
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 483883ec1d..b39e836181 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -38,6 +38,7 @@
/* Max size */
#define VIOMMU_DEFAULT_QUEUE_SIZE 256
+#define VIOMMU_PROBE_SIZE 512
typedef struct VirtIOIOMMUDomain {
uint32_t id;
@@ -378,6 +379,65 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s,
return ret;
}
+static ssize_t virtio_iommu_fill_resv_mem_prop(VirtIOIOMMU *s, uint32_t ep,
+ uint8_t *buf, size_t free)
+{
+ struct virtio_iommu_probe_resv_mem prop = {};
+ size_t size = sizeof(prop), length = size - sizeof(prop.head), total;
+ int i;
+
+ total = size * s->nb_reserved_regions;
+
+ if (total > free) {
+ return -ENOSPC;
+ }
+
+ for (i = 0; i < s->nb_reserved_regions; i++) {
+ unsigned subtype = s->reserved_regions[i].type;
+
+ assert(subtype == VIRTIO_IOMMU_RESV_MEM_T_RESERVED ||
+ subtype == VIRTIO_IOMMU_RESV_MEM_T_MSI);
+ prop.head.type = cpu_to_le16(VIRTIO_IOMMU_PROBE_T_RESV_MEM);
+ prop.head.length = cpu_to_le16(length);
+ prop.subtype = subtype;
+ prop.start = cpu_to_le64(s->reserved_regions[i].low);
+ prop.end = cpu_to_le64(s->reserved_regions[i].high);
+
+ memcpy(buf, &prop, size);
+
+ trace_virtio_iommu_fill_resv_property(ep, prop.subtype,
+ prop.start, prop.end);
+ buf += size;
+ }
+ return total;
+}
+
+/**
+ * virtio_iommu_probe - Fill the probe request buffer with
+ * the properties the device is able to return
+ */
+static int virtio_iommu_probe(VirtIOIOMMU *s,
+ struct virtio_iommu_req_probe *req,
+ uint8_t *buf)
+{
+ uint32_t ep_id = le32_to_cpu(req->endpoint);
+ size_t free = VIOMMU_PROBE_SIZE;
+ ssize_t count;
+
+ if (!virtio_iommu_mr(s, ep_id)) {
+ return VIRTIO_IOMMU_S_NOENT;
+ }
+
+ count = virtio_iommu_fill_resv_mem_prop(s, ep_id, buf, free);
+ if (count < 0) {
+ return VIRTIO_IOMMU_S_INVAL;
+ }
+ buf += count;
+ free -= count;
+
+ return VIRTIO_IOMMU_S_OK;
+}
+
static int virtio_iommu_iov_to_req(struct iovec *iov,
unsigned int iov_cnt,
void *req, size_t req_sz)
@@ -407,15 +467,27 @@ virtio_iommu_handle_req(detach)
virtio_iommu_handle_req(map)
virtio_iommu_handle_req(unmap)
+static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
+ struct iovec *iov,
+ unsigned int iov_cnt,
+ uint8_t *buf)
+{
+ struct virtio_iommu_req_probe req;
+ int ret = virtio_iommu_iov_to_req(iov, iov_cnt, &req, sizeof(req));
+
+ return ret ? ret : virtio_iommu_probe(s, &req, buf);
+}
+
static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOIOMMU *s = VIRTIO_IOMMU(vdev);
struct virtio_iommu_req_head head;
struct virtio_iommu_req_tail tail = {};
+ size_t output_size = sizeof(tail), sz;
VirtQueueElement *elem;
unsigned int iov_cnt;
struct iovec *iov;
- size_t sz;
+ void *buf = NULL;
for (;;) {
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
@@ -452,6 +524,17 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq)
case VIRTIO_IOMMU_T_UNMAP:
tail.status = virtio_iommu_handle_unmap(s, iov, iov_cnt);
break;
+ case VIRTIO_IOMMU_T_PROBE:
+ {
+ struct virtio_iommu_req_tail *ptail;
+
+ output_size = s->config.probe_size + sizeof(tail);
+ buf = g_malloc0(output_size);
+
+ ptail = (struct virtio_iommu_req_tail *)
+ (buf + s->config.probe_size);
+ ptail->status = virtio_iommu_handle_probe(s, iov, iov_cnt, buf);
+ }
default:
tail.status = VIRTIO_IOMMU_S_UNSUPP;
}
@@ -459,12 +542,13 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq)
out:
sz = iov_from_buf(elem->in_sg, elem->in_num, 0,
- &tail, sizeof(tail));
- assert(sz == sizeof(tail));
+ buf ? buf : &tail, output_size);
+ assert(sz == output_size);
- virtqueue_push(vq, elem, sizeof(tail));
+ virtqueue_push(vq, elem, sz);
virtio_notify(vdev, vq);
g_free(elem);
+ g_free(buf);
}
}
@@ -523,6 +607,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
uint32_t sid, flags;
bool bypass_allowed;
bool found;
+ int i;
interval.low = addr;
interval.high = addr + 1;
@@ -556,6 +641,25 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
goto unlock;
}
+ for (i = 0; i < s->nb_reserved_regions; i++) {
+ ReservedRegion *reg = &s->reserved_regions[i];
+
+ if (addr >= reg->low && addr <= reg->high) {
+ switch (reg->type) {
+ case VIRTIO_IOMMU_RESV_MEM_T_MSI:
+ entry.perm = flag;
+ break;
+ case VIRTIO_IOMMU_RESV_MEM_T_RESERVED:
+ default:
+ virtio_iommu_report_fault(s, VIRTIO_IOMMU_FAULT_R_MAPPING,
+ VIRTIO_IOMMU_FAULT_F_ADDRESS,
+ sid, addr);
+ break;
+ }
+ goto unlock;
+ }
+ }
+
if (!ep->domain) {
if (!bypass_allowed) {
error_report_once("%s %02x:%02x.%01x not attached to any domain",
@@ -667,6 +771,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
s->config.page_size_mask = TARGET_PAGE_MASK;
s->config.input_range.end = -1UL;
s->config.domain_range.end = 32;
+ s->config.probe_size = VIOMMU_PROBE_SIZE;
virtio_add_feature(&s->features, VIRTIO_RING_F_EVENT_IDX);
virtio_add_feature(&s->features, VIRTIO_RING_F_INDIRECT_DESC);
@@ -676,6 +781,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MAP_UNMAP);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS);
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MMIO);
+ virtio_add_feature(&s->features, VIRTIO_IOMMU_F_PROBE);
qemu_mutex_init(&s->mutex);
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 4b00320f1c..c4e2162ae9 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -1391,5 +1391,5 @@ void xen_bus_init(void)
BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- qbus_set_bus_hotplug_handler(bus, &error_abort);
+ qbus_set_bus_hotplug_handler(bus);
}
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index 2335ee2e65..7d4b13351e 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -705,7 +705,7 @@ int xen_be_init(void)
xen_sysdev = qdev_new(TYPE_XENSYSDEV);
sysbus_realize_and_unref(SYS_BUS_DEVICE(xen_sysdev), &error_fatal);
xen_sysbus = qbus_create(TYPE_XENSYSBUS, xen_sysdev, "xen-sysbus");
- qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort);
+ qbus_set_bus_hotplug_handler(xen_sysbus);
return 0;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 7207025bd4..84ee5b7a01 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -51,6 +51,12 @@ extern bool global_dirty_log;
typedef struct MemoryRegionOps MemoryRegionOps;
+struct ReservedRegion {
+ hwaddr low;
+ hwaddr high;
+ unsigned type;
+};
+
typedef struct IOMMUTLBEntry IOMMUTLBEntry;
/* See address_space_translate: bit 0 is read, bit 1 is write. */
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 7b5c24e928..3ef729a23c 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -442,8 +442,7 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
static inline
uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
ram_addr_t start,
- ram_addr_t length,
- uint64_t *real_dirty_pages)
+ ram_addr_t length)
{
ram_addr_t addr;
unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS);
@@ -469,7 +468,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
if (src[idx][offset]) {
unsigned long bits = atomic_xchg(&src[idx][offset], 0);
unsigned long new_dirty;
- *real_dirty_pages += ctpopl(bits);
new_dirty = ~dest[k];
dest[k] |= bits;
new_dirty &= bits;
@@ -502,7 +500,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
start + addr + offset,
TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
- *real_dirty_pages += 1;
long k = (start + addr) >> TARGET_PAGE_BITS;
if (!test_and_set_bit(k, dest)) {
num_dirty++;
diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h
index 37c89cc5f9..fcbaf3dc86 100644
--- a/include/hw/arm/fsl-imx6ul.h
+++ b/include/hw/arm/fsl-imx6ul.h
@@ -87,6 +87,8 @@ typedef struct FslIMX6ULState {
MemoryRegion caam;
MemoryRegion ocram;
MemoryRegion ocram_alias;
+
+ uint32_t phy_num[FSL_IMX6UL_NUM_ETHS];
} FslIMX6ULState;
enum FslIMX6ULMemoryMap {
diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h
index f6dfb5c0cf..8843e5f910 100644
--- a/include/hw/arm/pxa.h
+++ b/include/hw/arm/pxa.h
@@ -184,7 +184,6 @@ struct PXA2xxI2SState {
};
# define PA_FMT "0x%08lx"
-# define REG_FMT "0x" TARGET_FMT_plx
PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size,
const char *revision);
diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h
index 89e168fbff..e986b28c52 100644
--- a/include/hw/arm/sharpsl.h
+++ b/include/hw/arm/sharpsl.h
@@ -9,9 +9,6 @@
#include "exec/hwaddr.h"
-#define zaurus_printf(format, ...) \
- fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__)
-
/* zaurus.c */
#define SL_PXA_PARAM_BASE 0xa0000a00
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 31878ddc72..54bcf17afd 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -96,6 +96,12 @@ typedef enum VirtIOMMUType {
VIRT_IOMMU_VIRTIO,
} VirtIOMMUType;
+typedef enum VirtMSIControllerType {
+ VIRT_MSI_CTRL_NONE,
+ VIRT_MSI_CTRL_GICV2M,
+ VIRT_MSI_CTRL_ITS,
+} VirtMSIControllerType;
+
typedef enum VirtGICType {
VIRT_GIC_VERSION_MAX,
VIRT_GIC_VERSION_HOST,
@@ -119,6 +125,7 @@ typedef struct {
bool no_highmem_ecam;
bool no_ged; /* Machines < 4.2 has no support for ACPI GED device */
bool kvm_no_adjvtime;
+ bool acpi_expose_flash;
} VirtMachineClass;
typedef struct {
@@ -136,6 +143,7 @@ typedef struct {
OnOffAuto acpi;
VirtGICType gic_version;
VirtIOMMUType iommu;
+ VirtMSIControllerType msi_controller;
uint16_t virtio_iommu_bdf;
struct arm_boot_info bootinfo;
MemMapEntry *memmap;
diff --git a/include/hw/misc/max111x.h b/include/hw/misc/max111x.h
new file mode 100644
index 0000000000..af7f1017ef
--- /dev/null
+++ b/include/hw/misc/max111x.h
@@ -0,0 +1,56 @@
+/*
+ * Maxim MAX1110/1111 ADC chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#ifndef HW_MISC_MAX111X_H
+#define HW_MISC_MAX111X_H
+
+#include "hw/ssi/ssi.h"
+
+/*
+ * This is a model of the Maxim MAX1110/1111 ADC chip, which for QEMU
+ * is an SSI slave device. It has either 4 (max1110) or 8 (max1111)
+ * 8-bit ADC channels.
+ *
+ * QEMU interface:
+ * + GPIO inputs 0..3 (for max1110) or 0..7 (for max1111): set the value
+ * of each ADC input, as an unsigned 8-bit value
+ * + GPIO output 0: interrupt line
+ * + Properties "input0" to "input3" (max1110) or "input0" to "input7"
+ * (max1111): initial reset values for ADC inputs.
+ *
+ * Known bugs:
+ * + the interrupt line is not correctly implemented, and will never
+ * be lowered once it has been asserted.
+ */
+typedef struct {
+ SSISlave parent_obj;
+
+ qemu_irq interrupt;
+ /* Values of inputs at system reset (settable by QOM property) */
+ uint8_t reset_input[8];
+
+ uint8_t tb1, rb2, rb3;
+ int cycle;
+
+ uint8_t input[8];
+ int inputs, com;
+} MAX111xState;
+
+#define TYPE_MAX_111X "max111x"
+
+#define MAX_111X(obj) \
+ OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X)
+
+#define TYPE_MAX_1110 "max1110"
+#define TYPE_MAX_1111 "max1111"
+
+#endif
diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h
index 7b3faa4019..9f03034b89 100644
--- a/include/hw/net/imx_fec.h
+++ b/include/hw/net/imx_fec.h
@@ -268,6 +268,7 @@ typedef struct IMXFECState {
uint32_t phy_advertise;
uint32_t phy_int;
uint32_t phy_int_mask;
+ uint32_t phy_num;
bool is_fec;
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 7dc10be46f..fe78073c70 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -535,9 +535,8 @@ extern bool qdev_hot_removed;
char *qdev_get_dev_path(DeviceState *dev);
-void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp);
-
-void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp);
+void qbus_set_hotplug_handler(BusState *bus, Object *handler);
+void qbus_set_bus_hotplug_handler(BusState *bus);
static inline bool qbus_is_hotpluggable(BusState *bus)
{
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 49c6cd2460..944e3f2e0c 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -19,6 +19,7 @@ extern const PropertyInfo qdev_prop_string;
extern const PropertyInfo qdev_prop_chr;
extern const PropertyInfo qdev_prop_tpm;
extern const PropertyInfo qdev_prop_macaddr;
+extern const PropertyInfo qdev_prop_reserved_region;
extern const PropertyInfo qdev_prop_on_off_auto;
extern const PropertyInfo qdev_prop_multifd_compression;
extern const PropertyInfo qdev_prop_losttickpolicy;
@@ -184,6 +185,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
DEFINE_PROP(_n, _s, _f, qdev_prop_drive_iothread, BlockBackend *)
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
+#define DEFINE_PROP_RESERVED_REGION(_n, _s, _f) \
+ DEFINE_PROP(_n, _s, _f, qdev_prop_reserved_region, ReservedRegion)
#define DEFINE_PROP_ON_OFF_AUTO(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_on_off_auto, OnOffAuto)
#define DEFINE_PROP_MULTIFD_COMPRESSION(_n, _s, _f, _d) \
diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h
index 93f2b8b0be..eac168aa1d 100644
--- a/include/hw/ssi/ssi.h
+++ b/include/hw/ssi/ssi.h
@@ -66,8 +66,6 @@ struct SSISlave {
bool cs;
};
-#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
-
extern const VMStateDescription vmstate_ssi_slave;
#define VMSTATE_SSI_SLAVE(_field, _state) { \
@@ -79,13 +77,36 @@ extern const VMStateDescription vmstate_ssi_slave;
}
DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
+/**
+ * ssi_realize_and_unref: realize and unref an SSI slave device
+ * @dev: SSI slave device to realize
+ * @bus: SSI bus to put it on
+ * @errp: error pointer
+ *
+ * Call 'realize' on @dev, put it on the specified @bus, and drop the
+ * reference to it. Errors are reported via @errp and by returning
+ * false.
+ *
+ * This function is useful if you have created @dev via qdev_new()
+ * (which takes a reference to the device it returns to you), so that
+ * you can set properties on it before realizing it. If you don't need
+ * to set properties then ssi_create_slave() is probably better (as it
+ * does the create, init and realize in one step).
+ *
+ * If you are embedding the SSI slave into another QOM device and
+ * initialized it via some variant on object_initialize_child() then
+ * do not use this function, because that family of functions arrange
+ * for the only reference to the child device to be held by the parent
+ * via the child<> property, and so the reference-count-drop done here
+ * would be incorrect. (Instead you would want ssi_realize(), which
+ * doesn't currently exist but would be trivial to create if we had
+ * any code that wanted it.)
+ */
+bool ssi_realize_and_unref(DeviceState *dev, SSIBus *bus, Error **errp);
/* Master interface. */
SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
-/* max111x.c */
-void max111x_set_input(DeviceState *dev, int line, uint8_t value);
-
#endif
diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h
index e653004d7c..49eb105cd8 100644
--- a/include/hw/virtio/virtio-iommu.h
+++ b/include/hw/virtio/virtio-iommu.h
@@ -53,6 +53,8 @@ typedef struct VirtIOIOMMU {
GHashTable *as_by_busptr;
IOMMUPciBus *iommu_pcibus_by_bus_num[PCI_BUS_MAX];
PCIBus *primary_bus;
+ ReservedRegion *reserved_regions;
+ uint32_t nb_reserved_regions;
GTree *domains;
QemuMutex mutex;
GTree *endpoints;
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index ce4a78b687..15f5047bf1 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -58,6 +58,7 @@ typedef struct ISABus ISABus;
typedef struct ISADevice ISADevice;
typedef struct IsaDma IsaDma;
typedef struct MACAddr MACAddr;
+typedef struct ReservedRegion ReservedRegion;
typedef struct MachineClass MachineClass;
typedef struct MachineState MachineState;
typedef struct MemoryListener MemoryListener;
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index a36402722b..bef2a3afed 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -389,7 +389,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
*/
if (munlockall()) {
error_report("%s: munlockall: %s", __func__, strerror(errno));
- return -1;
+ goto out;
}
/*
diff --git a/migration/ram.c b/migration/ram.c
index 069b6e30bc..5554a7d2d8 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -859,9 +859,11 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
/* Called with RCU critical section */
static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb)
{
- rs->migration_dirty_pages +=
- cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length,
- &rs->num_dirty_pages_period);
+ uint64_t new_dirty_pages =
+ cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length);
+
+ rs->migration_dirty_pages += new_dirty_pages;
+ rs->num_dirty_pages_period += new_dirty_pages;
}
/**
diff --git a/migration/rdma.c b/migration/rdma.c
index ec45d33ba3..3b18823268 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -3787,7 +3787,6 @@ static int qemu_rdma_registration_start(QEMUFile *f, void *opaque,
static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
uint64_t flags, void *data)
{
- Error *local_err = NULL, **errp = &local_err;
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
RDMAContext *rdma;
RDMAControlHeader head = { .len = 0, .repeat = 1 };
@@ -3832,7 +3831,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
&reg_result_idx, rdma->pin_all ?
qemu_rdma_reg_whole_ram_blocks : NULL);
if (ret < 0) {
- ERROR(errp, "receiving remote info!");
+ fprintf(stderr, "receiving remote info!");
return ret;
}
@@ -3851,10 +3850,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
*/
if (local->nb_blocks != nb_dest_blocks) {
- ERROR(errp, "ram blocks mismatch (Number of blocks %d vs %d) "
- "Your QEMU command line parameters are probably "
- "not identical on both the source and destination.",
- local->nb_blocks, nb_dest_blocks);
+ fprintf(stderr, "ram blocks mismatch (Number of blocks %d vs %d) "
+ "Your QEMU command line parameters are probably "
+ "not identical on both the source and destination.",
+ local->nb_blocks, nb_dest_blocks);
rdma->error_state = -EINVAL;
return -EINVAL;
}
@@ -3867,10 +3866,10 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
/* We require that the blocks are in the same order */
if (rdma->dest_blocks[i].length != local->block[i].length) {
- ERROR(errp, "Block %s/%d has a different length %" PRIu64
- "vs %" PRIu64, local->block[i].block_name, i,
- local->block[i].length,
- rdma->dest_blocks[i].length);
+ fprintf(stderr, "Block %s/%d has a different length %" PRIu64
+ "vs %" PRIu64, local->block[i].block_name, i,
+ local->block[i].length,
+ rdma->dest_blocks[i].length);
rdma->error_state = -EINVAL;
return -EINVAL;
}
diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin
index 4af7f7d5a9..25b69cafba 100644
--- a/pc-bios/bios-256k.bin
+++ b/pc-bios/bios-256k.bin
Binary files differ
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index 67874c31b8..1167633985 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index b9da9d8ecb..3074686a8c 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index a048b6b077..50bc880272 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -38,5 +38,8 @@ s390-netboot.img:
@echo "s390-netboot.img not built since roms/SLOF/ is not available."
endif
+ALL_OBJS = $(sort $(OBJECTS) $(NETOBJS) $(LIBCOBJS) $(LIBNETOBJS))
+-include $(ALL_OBJS:%.o=%.d)
+
clean:
rm -f *.o *.d *.img *.elf *~ *.a
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index d13b7cbd15..97205674e5 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -328,9 +328,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
msg[0] = '2';
break;
default:
- msg[0] = vlbl->LDL_version;
- msg[0] &= 0x0f; /* convert EBCDIC */
- msg[0] |= 0x30; /* to ASCII (digit) */
+ msg[0] = ebc2asc[vlbl->LDL_version];
msg[1] = '?';
break;
}
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 339ec5fbe7..83ca27ab41 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -49,13 +49,13 @@ void enable_subchannel(SubChannelId schid)
uint16_t cu_type(SubChannelId schid)
{
- Ccw1 sense_id_ccw;
SenseId sense_data;
-
- sense_id_ccw.cmd_code = CCW_CMD_SENSE_ID;
- sense_id_ccw.cda = ptr2u32(&sense_data);
- sense_id_ccw.count = sizeof(sense_data);
- sense_id_ccw.flags |= CCW_FLAG_SLI;
+ Ccw1 sense_id_ccw = {
+ .cmd_code = CCW_CMD_SENSE_ID,
+ .flags = CCW_FLAG_SLI,
+ .count = sizeof(sense_data),
+ .cda = ptr2u32(&sense_data),
+ };
if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
panic("Failed to run SenseID CCw\n");
@@ -67,13 +67,13 @@ uint16_t cu_type(SubChannelId schid)
int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
uint16_t data_size)
{
- Ccw1 senseCcw;
+ Ccw1 senseCcw = {
+ .cmd_code = CCW_CMD_BASIC_SENSE,
+ .count = data_size,
+ .cda = ptr2u32(sense_data),
+ };
Irb irb;
- senseCcw.cmd_code = CCW_CMD_BASIC_SENSE;
- senseCcw.cda = ptr2u32(sense_data);
- senseCcw.count = data_size;
-
return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb);
}
@@ -314,7 +314,17 @@ static void print_irb_err(Irb *irb)
*/
static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
{
- CmdOrb orb = {};
+ /*
+ * QEMU's CIO implementation requires prefetch and 64-bit idaws. We
+ * allow all paths.
+ */
+ CmdOrb orb = {
+ .fmt = fmt,
+ .pfch = 1,
+ .c64 = 1,
+ .lpm = 0xFF,
+ .cpa = ccw_addr,
+ };
int rc;
IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
@@ -324,12 +334,6 @@ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
}
- orb.fmt = fmt;
- orb.pfch = 1; /* QEMU's cio implementation requires prefetch */
- orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */
- orb.lpm = 0xFF; /* All paths allowed */
- orb.cpa = ccw_addr;
-
rc = ssch(schid, &orb);
if (rc == 1 || rc == 2) {
/* Subchannel status pending or busy. Eat status and ask for retry. */
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index aaa432dedd..1e5d4e92e1 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -122,12 +122,17 @@ typedef struct schib {
} __attribute__ ((packed, aligned(4))) Schib;
typedef struct subchannel_id {
- __u32 cssid:8;
- __u32:4;
- __u32 m:1;
- __u32 ssid:2;
- __u32 one:1;
- __u32 sch_no:16;
+ union {
+ struct {
+ __u16 cssid:8;
+ __u16 reserved:4;
+ __u16 m:1;
+ __u16 ssid:2;
+ __u16 one:1;
+ };
+ __u16 sch_id;
+ };
+ __u16 sch_no;
} __attribute__ ((packed, aligned(4))) SubChannelId;
struct chsc_header {
diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h
index 78d5bc7442..dfcfea0ff0 100644
--- a/pc-bios/s390-ccw/helper.h
+++ b/pc-bios/s390-ccw/helper.h
@@ -14,11 +14,12 @@
#define S390_CCW_HELPER_H
#include "s390-ccw.h"
+#include "s390-time.h"
/* Avoids compiler warnings when casting a pointer to a u32 */
static inline uint32_t ptr2u32(void *ptr)
{
- IPL_assert((uint64_t)ptr <= 0xffffffff, "ptr2u32: ptr too large");
+ IPL_assert((uint64_t)ptr <= 0xffffffffull, "ptr2u32: ptr too large");
return (uint32_t)(uint64_t)ptr;
}
@@ -28,4 +29,20 @@ static inline void *u32toptr(uint32_t n)
return (void *)(uint64_t)n;
}
+static inline void yield(void)
+{
+ asm volatile ("diag 0,0,0x44"
+ : :
+ : "memory", "cc");
+}
+
+static inline void sleep(unsigned int seconds)
+{
+ ulong target = get_time_seconds() + seconds;
+
+ while (get_time_seconds() < target) {
+ yield();
+ }
+}
+
#endif
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 4eba2510b0..767012bf0c 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -8,12 +8,10 @@
#include "libc.h"
#include "s390-ccw.h"
+#include "s390-arch.h"
#define KERN_IMAGE_START 0x010000UL
-#define PSW_MASK_64 0x0000000100000000ULL
-#define PSW_MASK_32 0x0000000080000000ULL
-#define PSW_MASK_SHORTPSW 0x0008000000000000ULL
-#define RESET_PSW_MASK (PSW_MASK_SHORTPSW | PSW_MASK_32 | PSW_MASK_64)
+#define RESET_PSW_MASK (PSW_MASK_SHORTPSW | PSW_MASK_64)
typedef struct ResetInfo {
uint64_t ipl_psw;
@@ -54,7 +52,7 @@ void jump_to_IPL_code(uint64_t address)
current->ipl_psw = (uint64_t) &jump_to_IPL_2;
current->ipl_psw |= RESET_PSW_MASK;
- current->ipl_continue = address & 0x7fffffff;
+ current->ipl_continue = address & PSW_MASK_SHORT_ADDR;
debug_print_int("set IPL addr to", current->ipl_continue);
@@ -86,7 +84,7 @@ void jump_to_low_kernel(void)
/* Trying to get PSW at zero address */
if (*((uint64_t *)0) & RESET_PSW_MASK) {
- jump_to_IPL_code((*((uint64_t *)0)) & 0x7fffffff);
+ jump_to_IPL_code((*((uint64_t *)0)) & PSW_MASK_SHORT_ADDR);
}
/* No other option left, so use the Linux kernel start address */
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 4e65b411e1..146a50760b 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -36,11 +36,9 @@ LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
*/
void write_subsystem_identification(void)
{
- SubChannelId *schid = (SubChannelId *) 184;
- uint32_t *zeroes = (uint32_t *) 188;
-
- *schid = blk_schid;
- *zeroes = 0;
+ lowcore->subchannel_id = blk_schid.sch_id;
+ lowcore->subchannel_nr = blk_schid.sch_no;
+ lowcore->io_int_parm = 0;
}
void write_iplb_location(void)
@@ -48,13 +46,6 @@ void write_iplb_location(void)
lowcore->ptr_iplb = ptr2u32(&iplb);
}
-void panic(const char *string)
-{
- sclp_print(string);
- disabled_wait();
- while (1) { }
-}
-
unsigned int get_loadparm_index(void)
{
return atoui(loadparm_str);
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index ce3815b201..de8260a5d6 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -12,6 +12,7 @@
#include "libc.h"
#include "s390-ccw.h"
#include "sclp.h"
+#include "s390-time.h"
#define KEYCODE_NO_INP '\0'
#define KEYCODE_ESCAPE '\033'
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
index 5eefb7c289..577c023afe 100644
--- a/pc-bios/s390-ccw/netboot.mak
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -1,8 +1,7 @@
SLOF_DIR := $(SRC_PATH)/roms/SLOF
-NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o \
- libnet.a libc.a
+NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o
LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
@@ -11,15 +10,16 @@ NETLDFLAGS := $(LDFLAGS) -Ttext=0x7800000
$(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
-s390-netboot.elf: $(NETOBJS)
- $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $(NETOBJS),"BUILD","$(TARGET_DIR)$@")
+s390-netboot.elf: $(NETOBJS) libnet.a libc.a
+ $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $^,"BUILD","$(TARGET_DIR)$@")
s390-netboot.img: s390-netboot.elf
$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@")
# libc files:
-LIBC_CFLAGS := $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC)
+LIBC_CFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
+ -MMD -MP -MT $@ -MF $(@:%.o=%.d)
CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
@@ -52,7 +52,8 @@ libc.a: $(LIBCOBJS)
LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
-LIBNETCFLAGS := $(QEMU_CFLAGS) $(CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC)
+LIBNETCFLAGS = $(QEMU_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
+ -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
%.o : $(SLOF_DIR)/lib/libnet/%.c
$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 309ffa30d9..056e93a818 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -35,6 +35,7 @@
#include "s390-ccw.h"
#include "cio.h"
#include "virtio.h"
+#include "s390-time.h"
#define DEFAULT_BOOT_RETRIES 10
#define DEFAULT_TFTP_RETRIES 20
@@ -57,24 +58,14 @@ static SubChannelId net_schid = { .one = 1 };
static uint8_t mac[6];
static uint64_t dest_timer;
-static uint64_t get_timer_ms(void)
-{
- uint64_t clk;
-
- asm volatile(" stck %0 " : : "Q"(clk) : "memory");
-
- /* Bit 51 is incremented each microsecond */
- return (clk >> (63 - 51)) / 1000;
-}
-
void set_timer(int val)
{
- dest_timer = get_timer_ms() + val;
+ dest_timer = get_time_ms() + val;
}
int get_timer(void)
{
- return dest_timer - get_timer_ms();
+ return dest_timer - get_time_ms();
}
int get_sec_ticks(void)
@@ -448,14 +439,6 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip)
return rc;
}
-void panic(const char *string)
-{
- sclp_print(string);
- for (;;) {
- disabled_wait();
- }
-}
-
void write_subsystem_identification(void)
{
SubChannelId *schid = (SubChannelId *) 184;
diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
index 5f36361c02..6da44d4436 100644
--- a/pc-bios/s390-ccw/s390-arch.h
+++ b/pc-bios/s390-ccw/s390-arch.h
@@ -26,10 +26,12 @@ _Static_assert(sizeof(struct PSWLegacy) == 8, "PSWLegacy size incorrect");
/* s390 psw bit masks */
#define PSW_MASK_IOINT 0x0200000000000000ULL
+#define PSW_MASK_SHORTPSW 0x0008000000000000ULL
#define PSW_MASK_WAIT 0x0002000000000000ULL
#define PSW_MASK_EAMODE 0x0000000100000000ULL
#define PSW_MASK_BAMODE 0x0000000080000000ULL
-#define PSW_MASK_ZMODE (PSW_MASK_EAMODE | PSW_MASK_BAMODE)
+#define PSW_MASK_SHORT_ADDR 0x000000007fffffffULL
+#define PSW_MASK_64 (PSW_MASK_EAMODE | PSW_MASK_BAMODE)
/* Low core mapping */
typedef struct LowCore {
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 21f27e7990..36b884cced 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -50,12 +50,11 @@ typedef unsigned long long __u64;
#include "iplb.h"
/* start.s */
-void disabled_wait(void);
+void disabled_wait(void) __attribute__ ((__noreturn__));
void consume_sclp_int(void);
void consume_io_int(void);
/* main.c */
-void panic(const char *string);
void write_subsystem_identification(void);
void write_iplb_location(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
@@ -74,8 +73,6 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
bool virtio_is_supported(SubChannelId schid);
void virtio_blk_setup_device(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr);
-u64 get_clock(void);
-ulong get_second(void);
/* bootmap.c */
void zipl_load(void);
@@ -93,6 +90,12 @@ bool menu_is_enabled_enum(void);
#define MAX_BOOT_ENTRIES 31
+static inline void panic(const char *string)
+{
+ sclp_print(string);
+ disabled_wait();
+}
+
static inline void fill_hex(char *out, unsigned char val)
{
const char hex[] = "0123456789abcdef";
@@ -144,24 +147,8 @@ static inline void debug_print_addr(const char *desc, void *p)
#define KVM_S390_VIRTIO_SET_STATUS 2
#define KVM_S390_VIRTIO_CCW_NOTIFY 3
-static inline void yield(void)
-{
- asm volatile ("diag 0,0,0x44"
- : :
- : "memory", "cc");
-}
-
#define MAX_SECTOR_SIZE 4096
-static inline void sleep(unsigned int seconds)
-{
- ulong target = get_second() + seconds;
-
- while (get_second() < target) {
- yield();
- }
-}
-
static inline void IPL_assert(bool term, const char *message)
{
if (!term) {
diff --git a/pc-bios/s390-ccw/s390-time.h b/pc-bios/s390-ccw/s390-time.h
new file mode 100644
index 0000000000..ed6d982371
--- /dev/null
+++ b/pc-bios/s390-ccw/s390-time.h
@@ -0,0 +1,23 @@
+#ifndef TIME_H
+#define TIME_H
+
+static inline u64 get_clock(void)
+{
+ u64 r;
+
+ asm volatile("stck %0" : "=Q" (r) : : "cc");
+ return r;
+}
+
+static inline u64 get_time_ms(void)
+{
+ /* Bit 51 is incremented each microsecond */
+ return (get_clock() >> 12) / 1000;
+}
+
+static inline u64 get_time_seconds(void)
+{
+ return get_time_ms() / 1000;
+}
+
+#endif
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index aa8fceb19d..ce519300a1 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -47,8 +47,9 @@ memsetxc:
*/
.globl disabled_wait
disabled_wait:
- larl %r1,disabled_wait_psw
- lpswe 0(%r1)
+ larl %r1,disabled_wait_psw
+ lpswe 0(%r1)
+1: j 1b
/*
diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c
index ff7f4dad25..2fcb0a58c5 100644
--- a/pc-bios/s390-ccw/virtio-net.c
+++ b/pc-bios/s390-ccw/virtio-net.c
@@ -19,6 +19,8 @@
#include <ethernet.h>
#include "s390-ccw.h"
#include "virtio.h"
+#include "s390-time.h"
+#include "helper.h"
#ifndef DEBUG_VIRTIO_NET
#define DEBUG_VIRTIO_NET 0
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index 4fe4b9d261..eddfb8a7ad 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -14,6 +14,8 @@
#include "virtio.h"
#include "scsi.h"
#include "virtio-scsi.h"
+#include "s390-time.h"
+#include "helper.h"
static ScsiDevice default_scsi_device;
static VirtioScsiCmdReq req;
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index fb40ca9828..ab49840db8 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -15,6 +15,7 @@
#include "virtio-scsi.h"
#include "bswap.h"
#include "helper.h"
+#include "s390-time.h"
#define VRING_WAIT_REPLY_TIMEOUT 30
@@ -157,19 +158,6 @@ void vring_send_buf(VRing *vr, void *p, int len, int flags)
}
}
-u64 get_clock(void)
-{
- u64 r;
-
- asm volatile("stck %0" : "=Q" (r) : : "cc");
- return r;
-}
-
-ulong get_second(void)
-{
- return (get_clock() >> 12) / 1000000;
-}
-
int vr_poll(VRing *vr)
{
if (vr->used->idx == vr->used_idx) {
@@ -194,7 +182,7 @@ int vr_poll(VRing *vr)
*/
int vring_wait_reply(void)
{
- ulong target_second = get_second() + vdev.wait_reply_timeout;
+ ulong target_second = get_time_seconds() + vdev.wait_reply_timeout;
/* Wait for any queue to be updated by the host */
do {
@@ -207,7 +195,7 @@ int vring_wait_reply(void)
if (r) {
return 0;
}
- } while (!vdev.wait_reply_timeout || (get_second() < target_second));
+ } while (!vdev.wait_reply_timeout || (get_time_seconds() < target_second));
return 1;
}
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
index 6bb5c86eb0..d9c319604b 100644
--- a/pc-bios/s390-netboot.img
+++ b/pc-bios/s390-netboot.img
Binary files differ
diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin
index 6202cf73e2..d034f6d254 100644
--- a/pc-bios/vgabios-ati.bin
+++ b/pc-bios/vgabios-ati.bin
Binary files differ
diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin
index b675f86bc6..1ced8400f4 100644
--- a/pc-bios/vgabios-bochs-display.bin
+++ b/pc-bios/vgabios-bochs-display.bin
Binary files differ
diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin
index 63fde14fea..b3af3771bd 100644
--- a/pc-bios/vgabios-cirrus.bin
+++ b/pc-bios/vgabios-cirrus.bin
Binary files differ
diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin
index 80168826e2..3fac6dc137 100644
--- a/pc-bios/vgabios-qxl.bin
+++ b/pc-bios/vgabios-qxl.bin
Binary files differ
diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin
index 1dc413dcd2..1ca4f68a6e 100644
--- a/pc-bios/vgabios-ramfb.bin
+++ b/pc-bios/vgabios-ramfb.bin
Binary files differ
diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin
index f92b9a664d..a146eead00 100644
--- a/pc-bios/vgabios-stdvga.bin
+++ b/pc-bios/vgabios-stdvga.bin
Binary files differ
diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin
index b0d2f70670..49981a4334 100644
--- a/pc-bios/vgabios-virtio.bin
+++ b/pc-bios/vgabios-virtio.bin
Binary files differ
diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin
index 1c2776e8cf..2f8935bf1f 100644
--- a/pc-bios/vgabios-vmware.bin
+++ b/pc-bios/vgabios-vmware.bin
Binary files differ
diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin
index c5aad8f3a9..d371983ab9 100644
--- a/pc-bios/vgabios.bin
+++ b/pc-bios/vgabios.bin
Binary files differ
diff --git a/qemu-img.c b/qemu-img.c
index d7e846e607..bdb9f6aa46 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2084,15 +2084,6 @@ static int convert_do_copy(ImgConvertState *s)
s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
}
- if (!s->has_zero_init && !s->target_has_backing &&
- bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)))
- {
- ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK);
- if (ret == 0) {
- s->has_zero_init = true;
- }
- }
-
/* Allocate buffer for copied data. For compressed images, only one cluster
* can be copied at a time. */
if (s->compressed) {
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
index 9e7adfe3a6..7e9b0e0d3f 100644
--- a/qemu-storage-daemon.c
+++ b/qemu-storage-daemon.c
@@ -316,6 +316,7 @@ int main(int argc, char *argv[])
module_call_init(MODULE_INIT_QOM);
module_call_init(MODULE_INIT_TRACE);
+ qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_trace_opts);
qcrypto_init(&error_fatal);
bdrv_init();
@@ -334,5 +335,9 @@ int main(int argc, char *argv[])
main_loop_wait(false);
}
+ monitor_cleanup();
+ qemu_chr_cleanup();
+ user_creatable_cleanup();
+
return EXIT_SUCCESS;
}
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index ae1348dc8f..cdbeb59dcc 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -2421,6 +2421,7 @@ static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
if (sys2memblk) {
error_propagate(errp, local_err);
} else {
+ error_free(local_err);
result->response =
GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
}
diff --git a/roms/config.seabios-128k b/roms/config.seabios-128k
index c43912bf9d..d18c802c46 100644
--- a/roms/config.seabios-128k
+++ b/roms/config.seabios-128k
@@ -11,8 +11,11 @@ CONFIG_USB_UAS=n
CONFIG_SDCARD=n
CONFIG_TCGBIOS=n
CONFIG_MPT_SCSI=n
+CONFIG_ESP_SCSI=n
+CONFIG_MEGASAS=n
CONFIG_PVSCSI=n
CONFIG_NVME=n
CONFIG_USE_SMM=n
CONFIG_VGAHOOKS=n
CONFIG_HOST_BIOS_GEOMETRY=n
+CONFIG_ACPI_PARSE=n
diff --git a/roms/seabios b/roms/seabios
-Subproject f21b5a4aeb020f2a5e2c6503f906a9349dd2f06
+Subproject 88ab0c15525ced2eefe39220742efe4769089ad
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index cf99dcca9f..9e8ed423ea 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -573,6 +573,8 @@ typedef struct CPUARMState {
uint64_t esr;
} serror;
+ uint8_t ext_dabt_raised; /* Tracking/verifying injection of ext DABT */
+
/* State of our input IRQ/FIQ/VIRQ/VFIQ lines */
uint32_t irq_line_state;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 7c672c78b8..8bb7318378 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -39,6 +39,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
static bool cap_has_mp_state;
static bool cap_has_inject_serror_esr;
+static bool cap_has_inject_ext_dabt;
static ARMHostCPUFeatures arm_host_cpu_features;
@@ -245,6 +246,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
ret = -EINVAL;
}
+ if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) {
+ if (kvm_vm_enable_cap(s, KVM_CAP_ARM_NISV_TO_USER, 0)) {
+ error_report("Failed to enable KVM_CAP_ARM_NISV_TO_USER cap");
+ } else {
+ /* Set status for supporting the external dabt injection */
+ cap_has_inject_ext_dabt = kvm_check_extension(s,
+ KVM_CAP_ARM_INJECT_EXT_DABT);
+ }
+ }
+
return ret;
}
@@ -738,6 +749,29 @@ int kvm_get_vcpu_events(ARMCPU *cpu)
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ if (unlikely(env->ext_dabt_raised)) {
+ /*
+ * Verifying that the ext DABT has been properly injected,
+ * otherwise risking indefinitely re-running the faulting instruction
+ * Covering a very narrow case for kernels 5.5..5.5.4
+ * when injected abort was misconfigured to be
+ * an IMPLEMENTATION DEFINED exception (for 32-bit EL1)
+ */
+ if (!arm_feature(env, ARM_FEATURE_AARCH64) &&
+ unlikely(!kvm_arm_verify_ext_dabt_pending(cs))) {
+
+ error_report("Data abort exception with no valid ISS generated by "
+ "guest memory access. KVM unable to emulate faulting "
+ "instruction. Failed to inject an external data abort "
+ "into the guest.");
+ abort();
+ }
+ /* Clear the status */
+ env->ext_dabt_raised = 0;
+ }
}
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
@@ -810,6 +844,47 @@ void kvm_arm_vm_state_change(void *opaque, int running, RunState state)
}
}
+/**
+ * kvm_arm_handle_dabt_nisv:
+ * @cs: CPUState
+ * @esr_iss: ISS encoding (limited) for the exception from Data Abort
+ * ISV bit set to '0b0' -> no valid instruction syndrome
+ * @fault_ipa: faulting address for the synchronous data abort
+ *
+ * Returns: 0 if the exception has been handled, < 0 otherwise
+ */
+static int kvm_arm_handle_dabt_nisv(CPUState *cs, uint64_t esr_iss,
+ uint64_t fault_ipa)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ /*
+ * Request KVM to inject the external data abort into the guest
+ */
+ if (cap_has_inject_ext_dabt) {
+ struct kvm_vcpu_events events = { };
+ /*
+ * The external data abort event will be handled immediately by KVM
+ * using the address fault that triggered the exit on given VCPU.
+ * Requesting injection of the external data abort does not rely
+ * on any other VCPU state. Therefore, in this particular case, the VCPU
+ * synchronization can be exceptionally skipped.
+ */
+ events.exception.ext_dabt_pending = 1;
+ /* KVM_CAP_ARM_INJECT_EXT_DABT implies KVM_CAP_VCPU_EVENTS */
+ if (!kvm_vcpu_ioctl(cs, KVM_SET_VCPU_EVENTS, &events)) {
+ env->ext_dabt_raised = 1;
+ return 0;
+ }
+ } else {
+ error_report("Data abort exception triggered by guest memory access "
+ "at physical address: 0x" TARGET_FMT_lx,
+ (target_ulong)fault_ipa);
+ error_printf("KVM unable to emulate faulting instruction.\n");
+ }
+ return -1;
+}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
int ret = 0;
@@ -820,6 +895,11 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
ret = EXCP_DEBUG;
} /* otherwise return to guest */
break;
+ case KVM_EXIT_ARM_NISV:
+ /* External DABT with no valid iss to decode */
+ ret = kvm_arm_handle_dabt_nisv(cs, run->arm_nisv.esr_iss,
+ run->arm_nisv.fault_ipa);
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
__func__, run->exit_reason);
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 7b3a19e9ae..0af46b41c8 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -559,3 +559,37 @@ void kvm_arm_pmu_init(CPUState *cs)
{
qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
}
+
+#define ARM_REG_DFSR ARM_CP15_REG32(0, 5, 0, 0)
+#define ARM_REG_TTBCR ARM_CP15_REG32(0, 2, 0, 2)
+/*
+ *DFSR:
+ * TTBCR.EAE == 0
+ * FS[4] - DFSR[10]
+ * FS[3:0] - DFSR[3:0]
+ * TTBCR.EAE == 1
+ * FS, bits [5:0]
+ */
+#define DFSR_FSC(lpae, v) \
+ ((lpae) ? ((v) & 0x3F) : (((v) >> 6) | ((v) & 0x1F)))
+
+#define DFSC_EXTABT(lpae) ((lpae) ? 0x10 : 0x08)
+
+bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
+{
+ uint32_t dfsr_val;
+
+ if (!kvm_get_one_reg(cs, ARM_REG_DFSR, &dfsr_val)) {
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint32_t ttbcr;
+ int lpae = 0;
+
+ if (!kvm_get_one_reg(cs, ARM_REG_TTBCR, &ttbcr)) {
+ lpae = arm_feature(env, ARM_FEATURE_LPAE) && (ttbcr & TTBCR_EAE);
+ }
+ /* The verification is based on FS filed of the DFSR reg only*/
+ return (DFSR_FSC(lpae, dfsr_val) == DFSC_EXTABT(lpae));
+ }
+ return false;
+}
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 3dc494aaa7..1169237905 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -1493,3 +1493,52 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
return false;
}
+
+#define ARM64_REG_ESR_EL1 ARM64_SYS_REG(3, 0, 5, 2, 0)
+#define ARM64_REG_TCR_EL1 ARM64_SYS_REG(3, 0, 2, 0, 2)
+
+/*
+ * ESR_EL1
+ * ISS encoding
+ * AARCH64: DFSC, bits [5:0]
+ * AARCH32:
+ * TTBCR.EAE == 0
+ * FS[4] - DFSR[10]
+ * FS[3:0] - DFSR[3:0]
+ * TTBCR.EAE == 1
+ * FS, bits [5:0]
+ */
+#define ESR_DFSC(aarch64, lpae, v) \
+ ((aarch64 || (lpae)) ? ((v) & 0x3F) \
+ : (((v) >> 6) | ((v) & 0x1F)))
+
+#define ESR_DFSC_EXTABT(aarch64, lpae) \
+ ((aarch64) ? 0x10 : (lpae) ? 0x10 : 0x8)
+
+bool kvm_arm_verify_ext_dabt_pending(CPUState *cs)
+{
+ uint64_t dfsr_val;
+
+ if (!kvm_get_one_reg(cs, ARM64_REG_ESR_EL1, &dfsr_val)) {
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ int aarch64_mode = arm_feature(env, ARM_FEATURE_AARCH64);
+ int lpae = 0;
+
+ if (!aarch64_mode) {
+ uint64_t ttbcr;
+
+ if (!kvm_get_one_reg(cs, ARM64_REG_TCR_EL1, &ttbcr)) {
+ lpae = arm_feature(env, ARM_FEATURE_LPAE)
+ && (ttbcr & TTBCR_EAE);
+ }
+ }
+ /*
+ * The verification here is based on the DFSC bits
+ * of the ESR_EL1 reg only
+ */
+ return (ESR_DFSC(aarch64_mode, lpae, dfsr_val) ==
+ ESR_DFSC_EXTABT(aarch64_mode, lpae));
+ }
+ return false;
+}
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index a4ce4fd93d..adb38514bf 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -450,6 +450,16 @@ struct kvm_guest_debug_arch;
void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
/**
+ * kvm_arm_verify_ext_dabt_pending:
+ * @cs: CPUState
+ *
+ * Verify the fault status code wrt the Ext DABT injection
+ *
+ * Returns: true if the fault status code is as expected, false otherwise
+ */
+bool kvm_arm_verify_ext_dabt_pending(CPUState *cs);
+
+/**
* its_class_name:
*
* Return the ITS class name to use depending on whether KVM acceleration
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 73d753f11f..8c0764957c 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -461,6 +461,12 @@ TCGv_i64 new_tmp_a64(DisasContext *s)
return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
}
+TCGv_i64 new_tmp_a64_local(DisasContext *s)
+{
+ assert(s->tmp_a64_count < TMP_A64_MAX);
+ return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_local_new_i64();
+}
+
TCGv_i64 new_tmp_a64_zero(DisasContext *s)
{
TCGv_i64 t = new_tmp_a64(s);
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index 49e4865918..647f0c74f6 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -30,6 +30,7 @@ void unallocated_encoding(DisasContext *s);
} while (0)
TCGv_i64 new_tmp_a64(DisasContext *s);
+TCGv_i64 new_tmp_a64_local(DisasContext *s);
TCGv_i64 new_tmp_a64_zero(DisasContext *s);
TCGv_i64 cpu_reg(DisasContext *s, int reg);
TCGv_i64 cpu_reg_sp(DisasContext *s, int reg);
diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c
index f318ca265f..08f0fd15b2 100644
--- a/target/arm/translate-sve.c
+++ b/target/arm/translate-sve.c
@@ -4372,9 +4372,8 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
/* Copy the clean address into a local temp, live across the loop. */
t0 = clean_addr;
- clean_addr = tcg_temp_local_new_i64();
+ clean_addr = new_tmp_a64_local(s);
tcg_gen_mov_i64(clean_addr, t0);
- tcg_temp_free_i64(t0);
gen_set_label(loop);
@@ -4422,7 +4421,6 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
tcg_gen_st_i64(t0, cpu_env, vofs + len_align);
tcg_temp_free_i64(t0);
}
- tcg_temp_free_i64(clean_addr);
}
/* Similarly for stores. */
@@ -4463,9 +4461,8 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
/* Copy the clean address into a local temp, live across the loop. */
t0 = clean_addr;
- clean_addr = tcg_temp_local_new_i64();
+ clean_addr = new_tmp_a64_local(s);
tcg_gen_mov_i64(clean_addr, t0);
- tcg_temp_free_i64(t0);
gen_set_label(loop);
@@ -4509,7 +4506,6 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm)
}
tcg_temp_free_i64(t0);
}
- tcg_temp_free_i64(clean_addr);
}
static bool trans_LDR_zri(DisasContext *s, arg_rri *a)
diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs
index ff651f69f6..ff38df6219 100644
--- a/target/riscv/Makefile.objs
+++ b/target/riscv/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o
+obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o vector_helper.o gdbstub.o
obj-$(CONFIG_SOFTMMU) += pmp.o
ifeq ($(CONFIG_SOFTMMU),y)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 391a0b9eec..228b9bdb5d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -106,6 +106,11 @@ 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);
@@ -334,6 +339,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
CPURISCVState *env = &cpu->env;
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
int priv_version = PRIV_VERSION_1_11_0;
+ int vext_version = VEXT_VERSION_0_07_1;
target_ulong target_misa = 0;
Error *local_err = NULL;
@@ -357,6 +363,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
set_priv_version(env, priv_version);
+ set_vext_version(env, vext_version);
if (cpu->cfg.mmu) {
set_feature(env, RISCV_FEATURE_MMU);
@@ -423,6 +430,45 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
if (cpu->cfg.ext_h) {
target_misa |= RVH;
}
+ if (cpu->cfg.ext_v) {
+ target_misa |= 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 verison is not specified, "
+ "use the default value v0.7.1\n");
+ }
+ set_vext_version(env, vext_version);
+ }
set_misa(env, RVXLEN | target_misa);
}
@@ -462,10 +508,14 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
/* This is experimental so mark with 'x-' */
DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
+ DEFINE_PROP_BOOL("x-v", RISCVCPU, cfg.ext_v, false),
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_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
+ 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),
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
DEFINE_PROP_END_OF_LIST(),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 80569f0d44..eef20ca6e5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -21,6 +21,7 @@
#define RISCV_CPU_H
#include "hw/core/cpu.h"
+#include "hw/registerfields.h"
#include "exec/cpu-defs.h"
#include "fpu/softfloat-types.h"
@@ -59,6 +60,7 @@
#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')
@@ -77,6 +79,8 @@ enum {
#define PRIV_VERSION_1_10_0 0x00011000
#define PRIV_VERSION_1_11_0 0x00011100
+#define VEXT_VERSION_0_07_1 0x00000701
+
#define TRANSLATE_PMP_FAIL 2
#define TRANSLATE_FAIL 1
#define TRANSLATE_SUCCESS 0
@@ -88,9 +92,26 @@ typedef struct CPURISCVState CPURISCVState;
#include "pmp.h"
+#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 - 2, 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;
@@ -101,6 +122,7 @@ struct CPURISCVState {
target_ulong guest_phys_fault_addr;
target_ulong priv_ver;
+ target_ulong vext_ver;
target_ulong misa;
target_ulong misa_mask;
@@ -257,12 +279,16 @@ typedef struct RISCVCPU {
bool ext_s;
bool ext_u;
bool ext_h;
+ bool ext_v;
bool ext_counters;
bool ext_ifencei;
bool ext_icsr;
char *priv_spec;
char *user_spec;
+ char *vext_spec;
+ uint16_t vlen;
+ uint16_t elen;
bool mmu;
bool pmp;
} cfg;
@@ -335,19 +361,62 @@ void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong);
#define TB_FLAGS_MMU_MASK 3
#define TB_FLAGS_MSTATUS_FS MSTATUS_FS
+typedef CPURISCVState CPUArchState;
+typedef RISCVCPU ArchCPU;
+#include "exec/cpu-all.h"
+
+FIELD(TB_FLAGS, VL_EQ_VLMAX, 2, 1)
+FIELD(TB_FLAGS, LMUL, 3, 2)
+FIELD(TB_FLAGS, SEW, 5, 3)
+FIELD(TB_FLAGS, VILL, 8, 1)
+
+/*
+ * 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);
+}
+
static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
- target_ulong *cs_base, uint32_t *flags)
+ 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;
+ flags |= TB_FLAGS_MSTATUS_FS;
#else
- *flags = cpu_mmu_index(env, 0);
+ flags |= cpu_mmu_index(env, 0);
if (riscv_cpu_fp_enabled(env)) {
- *flags |= env->mstatus & MSTATUS_FS;
+ flags |= env->mstatus & MSTATUS_FS;
}
#endif
+ *pflags = flags;
}
int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
@@ -388,9 +457,4 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
-typedef CPURISCVState CPUArchState;
-typedef RISCVCPU ArchCPU;
-
-#include "exec/cpu-all.h"
-
#endif /* RISCV_CPU_H */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 7f64ee1174..8117e8b5a7 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -29,6 +29,14 @@
#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 */
@@ -48,6 +56,13 @@
#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
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 383be0a955..ac01c835e1 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -46,6 +46,10 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
static int fs(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
+ /* loose check condition for fcsr in vector extension */
+ if ((csrno == CSR_FCSR) && (env->misa & RVV)) {
+ return 0;
+ }
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
@@ -53,6 +57,14 @@ static int fs(CPURISCVState *env, int csrno)
return 0;
}
+static int vs(CPURISCVState *env, int csrno)
+{
+ if (env->misa & RVV) {
+ return 0;
+ }
+ return -1;
+}
+
static int ctr(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
@@ -154,6 +166,10 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
#endif
*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 0;
}
@@ -166,10 +182,62 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
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 0;
}
+static int read_vtype(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->vtype;
+ return 0;
+}
+
+static int read_vl(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->vl;
+ return 0;
+}
+
+static int read_vxrm(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->vxrm;
+ return 0;
+}
+
+static int write_vxrm(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->vxrm = val;
+ return 0;
+}
+
+static int read_vxsat(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->vxsat;
+ return 0;
+}
+
+static int write_vxsat(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->vxsat = val;
+ return 0;
+}
+
+static int read_vstart(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->vstart;
+ return 0;
+}
+
+static int write_vstart(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->vstart = val;
+ return 0;
+}
+
/* User Timers and Counters */
static int read_instret(CPURISCVState *env, int csrno, target_ulong *val)
{
@@ -1183,7 +1251,12 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_FFLAGS] = { fs, read_fflags, write_fflags },
[CSR_FRM] = { fs, read_frm, write_frm },
[CSR_FCSR] = { fs, read_fcsr, write_fcsr },
-
+ /* Vector CSRs */
+ [CSR_VSTART] = { vs, read_vstart, write_vstart },
+ [CSR_VXSAT] = { vs, read_vxsat, write_vxsat },
+ [CSR_VXRM] = { vs, read_vxrm, write_vxrm },
+ [CSR_VL] = { vs, read_vl },
+ [CSR_VTYPE] = { vs, read_vtype },
/* User Timers and Counters */
[CSR_CYCLE] = { ctr, read_instret },
[CSR_INSTRET] = { ctr, read_instret },
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index 0b79562a69..4379756dc4 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -22,6 +22,7 @@
#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)
{
@@ -230,21 +231,7 @@ uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1)
target_ulong helper_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;
- }
+ return fclass_s(frs1);
}
uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
@@ -353,19 +340,5 @@ uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1)
target_ulong helper_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;
- }
+ return fclass_d(frs1);
}
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index b36be978d5..acc298219d 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -81,3 +81,1072 @@ DEF_HELPER_1(tlb_flush, void, env)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(hyp_tlb_flush, void, env)
#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)
+#ifdef TARGET_RISCV64
+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)
+#endif
+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/insn32-64.decode b/target/riscv/insn32-64.decode
index 380bf791bc..86153d93fa 100644
--- a/target/riscv/insn32-64.decode
+++ b/target/riscv/insn32-64.decode
@@ -57,6 +57,17 @@ amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st
amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st
amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st
+#*** 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
+
# *** RV64F Standard Extension (in addition to RV32F) ***
fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm
fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 4c8d1215ce..bdd8563067 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -25,6 +25,7 @@
%sh10 20:10
%csr 20:12
%rm 12:3
+%nf 29:3 !function=ex_plus_1
# immediates:
%imm_i 20:s12
@@ -43,6 +44,11 @@
&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
@@ -62,6 +68,16 @@
@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd
@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
@hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1
@hfence_vvma ....... ..... ..... ... ..... ....... %rs2 %rs1
@@ -209,3 +225,359 @@ fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm
# *** RV32H Base Instruction Set ***
hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma
hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma
+
+# *** RV32V Extension ***
+
+# *** 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
diff --git a/target/riscv/insn_trans/trans_rvv.inc.c b/target/riscv/insn_trans/trans_rvv.inc.c
new file mode 100644
index 0000000000..dc333e6a91
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvv.inc.c
@@ -0,0 +1,2888 @@
+/*
+ * 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 = tcg_temp_new();
+ dst = tcg_temp_new();
+
+ /* 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_const_tl(RV_VLEN_MAX);
+ } else {
+ s1 = tcg_temp_new();
+ gen_get_gpr(s1, a->rs1);
+ }
+ gen_get_gpr(s2, a->rs2);
+ gen_helper_vsetvl(dst, cpu_env, s1, s2);
+ gen_set_gpr(a->rd, dst);
+ tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
+ lookup_and_goto_ptr(ctx);
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ tcg_temp_free(s1);
+ tcg_temp_free(s2);
+ tcg_temp_free(dst);
+ return true;
+}
+
+static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a)
+{
+ TCGv s1, s2, dst;
+
+ if (!has_ext(ctx, RVV)) {
+ return false;
+ }
+
+ s2 = tcg_const_tl(a->zimm);
+ dst = tcg_temp_new();
+
+ /* 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_const_tl(RV_VLEN_MAX);
+ } else {
+ s1 = tcg_temp_new();
+ gen_get_gpr(s1, a->rs1);
+ }
+ gen_helper_vsetvl(dst, cpu_env, s1, s2);
+ gen_set_gpr(a->rd, dst);
+ gen_goto_tb(ctx, 0, ctx->pc_succ_insn);
+ ctx->base.is_jmp = DISAS_NORETURN;
+
+ tcg_temp_free(s1);
+ tcg_temp_free(s2);
+ tcg_temp_free(dst);
+ 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 = tcg_temp_new();
+
+ /*
+ * 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_const_i32(simd_desc(0, s->vlen / 8, data));
+
+ gen_get_gpr(base, rs1);
+ 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);
+ tcg_temp_free(base);
+ tcg_temp_free_i32(desc);
+ 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 = tcg_temp_new();
+ stride = tcg_temp_new();
+ desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
+
+ gen_get_gpr(base, rs1);
+ gen_get_gpr(stride, rs2);
+ 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);
+ tcg_temp_free(base);
+ tcg_temp_free(stride);
+ tcg_temp_free_i32(desc);
+ 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 = tcg_temp_new();
+ desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
+
+ gen_get_gpr(base, rs1);
+ 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);
+ tcg_temp_free(base);
+ tcg_temp_free_i32(desc);
+ 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);
+}
+
+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));
+}
+
+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 = tcg_temp_new();
+ desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
+
+ gen_get_gpr(base, rs1);
+ 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);
+ tcg_temp_free(base);
+ tcg_temp_free_i32(desc);
+ 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 = tcg_temp_new();
+ desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data));
+
+ gen_get_gpr(base, rs1);
+ 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);
+ tcg_temp_free(base);
+ tcg_temp_free_i32(desc);
+ 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
+ };
+#ifdef TARGET_RISCV64
+ 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
+ };
+#endif
+
+ if (tb_cflags(s->base.tb) & CF_PARALLEL) {
+ gen_helper_exit_atomic(cpu_env);
+ s->base.is_jmp = DISAS_NORETURN;
+ return true;
+ } else {
+ if (s->sew == 3) {
+#ifdef TARGET_RISCV64
+ fn = fnsd[seq];
+#else
+ /* Check done in amo_check(). */
+ g_assert_not_reached();
+#endif
+ } else {
+ fn = fnsw[seq];
+ }
+ }
+
+ 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));
+}
+
+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)
+#ifdef TARGET_RISCV64
+GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check)
+GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check)
+#endif
+
+/*
+ *** 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, 0, 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 = tcg_temp_new();
+ gen_get_gpr(src1, rs1);
+
+ 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_const_i32(simd_desc(0, 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);
+ tcg_temp_free(src1);
+ tcg_temp_free_i32(desc);
+ 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();
+ TCGv tmp = tcg_temp_new();
+
+ gen_get_gpr(tmp, a->rs1);
+ tcg_gen_ext_tl_i64(src1, tmp);
+ gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
+ src1, MAXSZ(s), MAXSZ(s));
+
+ tcg_temp_free_i64(src1);
+ tcg_temp_free(tmp);
+ 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_sub8_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 GVecGen2s rsub_op[4] = {
+ { .fni8 = gen_vec_rsub8_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs8,
+ .vece = MO_8 },
+ { .fni8 = gen_vec_rsub16_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs16,
+ .vece = MO_16 },
+ { .fni4 = gen_rsub_i32,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs32,
+ .vece = MO_32 },
+ { .fni8 = gen_rsub_i64,
+ .fniv = gen_rsub_vec,
+ .fno = gen_helper_vec_rsubs64,
+ .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_const_tl(imm);
+ } else {
+ src1 = tcg_const_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_const_i32(simd_desc(0, 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);
+ tcg_temp_free(src1);
+ tcg_temp_free_i32(desc);
+ 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_const_i64(c);
+ tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
+ tcg_temp_free_i64(tmp);
+}
+
+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, 0, 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 true;
+}
+
+#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, 0, 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, 0, \
+ 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();
+ TCGv tmp = tcg_temp_new();
+
+ gen_get_gpr(tmp, a->rs1);
+ tcg_gen_trunc_tl_i32(src1, tmp);
+ 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);
+ tcg_temp_free(tmp);
+ 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, 0, \
+ 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, 0, 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 = tcg_temp_new();
+ gen_get_gpr(s1, a->rs1);
+
+ 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_const_i32(simd_desc(0, 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_i32(desc);
+ tcg_temp_free_i64(s1_i64);
+ }
+
+ tcg_temp_free(s1);
+ 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_const_i64(simm);
+ dest = tcg_temp_new_ptr();
+ desc = tcg_const_i32(simd_desc(0, 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);
+ tcg_temp_free_i32(desc);
+ tcg_temp_free_i64(s1);
+ 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, 0, \
+ 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_const_i32(simd_desc(0, 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);
+ tcg_temp_free_i32(desc);
+ 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, 0, \
+ 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, 0, \
+ 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, 0, \
+ 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_const_i32(simd_desc(0, 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);
+ tcg_temp_free_i32(desc);
+ 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, 0, \
+ 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, 0, \
+ 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, 0, \
+ 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 = tcg_temp_new();
+ desc = tcg_const_i32(simd_desc(0, 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(a->rd, dst);
+
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ tcg_temp_free(dst);
+ tcg_temp_free_i32(desc);
+ 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 = tcg_temp_new();
+ desc = tcg_const_i32(simd_desc(0, 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(a->rd, dst);
+
+ tcg_temp_free_ptr(mask);
+ tcg_temp_free_ptr(src2);
+ tcg_temp_free(dst);
+ tcg_temp_free_i32(desc);
+ 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, 0, 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, 0,
+ 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, 0, 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_const_i64(vlmax);
+ t_zero = tcg_const_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_vlmax);
+ tcg_temp_free_i64(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 = tcg_temp_new();
+
+ 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(a->rd, dest);
+
+ tcg_temp_free(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, 0, s->vlen / 8, data, fns[s->sew]);
+ gen_set_label(over);
+ return true;
+ }
+ return false;
+}
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
new file mode 100644
index 0000000000..37d33820ad
--- /dev/null
+++ b/target/riscv/internals.h
@@ -0,0 +1,41 @@
+/*
+ * 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
+
+#endif
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index ce71ca7a92..9632e79cf3 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -32,7 +32,7 @@
#include "instmap.h"
/* global register indices */
-static TCGv cpu_gpr[32], cpu_pc;
+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;
@@ -56,6 +56,13 @@ typedef struct DisasContext {
to reset this known value. */
int frm;
bool ext_ifencei;
+ /* vector extension */
+ bool vill;
+ uint8_t lmul;
+ uint8_t sew;
+ uint16_t vlen;
+ uint16_t mlen;
+ bool vl_eq_vlmax;
} DisasContext;
#ifdef TARGET_RISCV64
@@ -542,6 +549,11 @@ static void decode_RV32_64C(DisasContext *ctx, uint16_t opcode)
}
}
+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) \
{ \
@@ -712,6 +724,7 @@ static bool gen_shift(DisasContext *ctx, arg_r *a,
#include "insn_trans/trans_rvf.inc.c"
#include "insn_trans/trans_rvd.inc.c"
#include "insn_trans/trans_rvh.inc.c"
+#include "insn_trans/trans_rvv.inc.c"
#include "insn_trans/trans_privileged.inc.c"
/* Include the auto-generated decoder for 16 bit insn */
@@ -746,10 +759,11 @@ 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 = ctx->base.tb->flags & TB_FLAGS_MMU_MASK;
- ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS;
+ ctx->mem_idx = tb_flags & TB_FLAGS_MMU_MASK;
+ 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)) {
@@ -773,6 +787,12 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->misa = env->misa;
ctx->frm = -1; /* unknown rounding mode */
ctx->ext_ifencei = cpu->cfg.ext_ifencei;
+ ctx->vlen = cpu->cfg.vlen;
+ 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);
}
static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
@@ -887,6 +907,7 @@ void riscv_translate_init(void)
}
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),
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
new file mode 100644
index 0000000000..39f44d1029
--- /dev/null
+++ b/target/riscv/vector_helper.c
@@ -0,0 +1,4899 @@
+/*
+ * 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((void *)((uintptr_t)tail & ~(7ULL)), 0, part1);
+ memset((void *)(((uintptr_t)tail + 8) & ~(7ULL)), 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)
+#ifdef TARGET_RISCV64
+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)
+#endif
+
+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()); \
+}
+
+#ifdef TARGET_RISCV64
+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)
+#endif
+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); \
+ } \
+}
+
+static bool float16_eq_quiet(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare_quiet(a, b, s);
+ return compare == float_relation_equal;
+}
+
+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)
+
+static bool float16_lt(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare(a, b, s);
+ return compare == float_relation_less;
+}
+
+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)
+
+static bool float16_le(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare(a, b, s);
+ return compare == float_relation_less ||
+ compare == float_relation_equal;
+}
+
+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)
+
+static bool float16_unordered_quiet(uint16_t a, uint16_t b, float_status *s)
+{
+ FloatRelation compare = float16_compare_quiet(a, b, s);
+ return compare == float_relation_unordered;
+}
+
+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; \
+ uint32_t index, 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; \
+ uint32_t index = s1, 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)
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index 91ddaedd84..d79ae9e3f1 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -798,7 +798,7 @@
/* SQUARE ROOT */
F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP)
F(0xb315, SQDBR, RRE, Z, 0, f2, new, f1, sqdb, 0, IF_BFP)
- F(0xb316, SQXBR, RRE, Z, x2h, x2l, new, x1, sqxb, 0, IF_BFP)
+ F(0xb316, SQXBR, RRE, Z, x2h, x2l, new_P, x1, sqxb, 0, IF_BFP)
F(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0, IF_BFP)
F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP)
diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c
index 73d3e9f574..5a25825093 100644
--- a/tests/check-block-qdict.c
+++ b/tests/check-block-qdict.c
@@ -610,9 +610,7 @@ static void qdict_rename_keys_test(void)
copy = qdict_clone_shallow(dict);
qdict_rename_keys(copy, renames, &local_err);
- g_assert(local_err != NULL);
- error_free(local_err);
- local_err = NULL;
+ error_free_or_abort(&local_err);
g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
@@ -649,9 +647,7 @@ static void qdict_crumple_test_bad_inputs(void)
qdict_put_str(src, "rule.0.policy", "allow");
g_assert(qdict_crumple(src, &error) == NULL);
- g_assert(error != NULL);
- error_free(error);
- error = NULL;
+ error_free_or_abort(&error);
qobject_unref(src);
src = qdict_new();
@@ -660,9 +656,7 @@ static void qdict_crumple_test_bad_inputs(void)
qdict_put_str(src, "rule.a", "allow");
g_assert(qdict_crumple(src, &error) == NULL);
- g_assert(error != NULL);
- error_free(error);
- error = NULL;
+ error_free_or_abort(&error);
qobject_unref(src);
src = qdict_new();
@@ -673,9 +667,7 @@ static void qdict_crumple_test_bad_inputs(void)
qdict_put_str(src, "rule.b", "allow");
g_assert(qdict_crumple(src, &error) == NULL);
- g_assert(error != NULL);
- error_free(error);
- error = NULL;
+ error_free_or_abort(&error);
qobject_unref(src);
src = qdict_new();
@@ -684,9 +676,7 @@ static void qdict_crumple_test_bad_inputs(void)
qdict_put_str(src, "rule.3", "allow");
g_assert(qdict_crumple(src, &error) == NULL);
- g_assert(error != NULL);
- error_free(error);
- error = NULL;
+ error_free_or_abort(&error);
qobject_unref(src);
src = qdict_new();
@@ -695,9 +685,7 @@ static void qdict_crumple_test_bad_inputs(void)
qdict_put_str(src, "rule.+1", "allow");
g_assert(qdict_crumple(src, &error) == NULL);
- g_assert(error != NULL);
- error_free(error);
- error = NULL;
+ error_free_or_abort(&error);
qobject_unref(src);
}
diff --git a/tests/check-qobject.c b/tests/check-qobject.c
index 593c3a0618..6b6deaeb8b 100644
--- a/tests/check-qobject.c
+++ b/tests/check-qobject.c
@@ -9,6 +9,7 @@
#include "qemu/osdep.h"
#include "block/qdict.h"
+#include "qapi/error.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qlist.h"
@@ -213,7 +214,6 @@ static void qobject_is_equal_list_test(void)
static void qobject_is_equal_dict_test(void)
{
- Error *local_err = NULL;
QDict *dict_0, *dict_1, *dict_cloned;
QDict *dict_different_key, *dict_different_value, *dict_different_null_key;
QDict *dict_longer, *dict_shorter, *dict_nested;
@@ -276,8 +276,7 @@ static void qobject_is_equal_dict_test(void)
dict_different_null_key, dict_longer, dict_shorter,
dict_nested);
- dict_crumpled = qobject_to(QDict, qdict_crumple(dict_1, &local_err));
- g_assert(!local_err);
+ dict_crumpled = qobject_to(QDict, qdict_crumple(dict_1, &error_abort));
check_equal(dict_crumpled, dict_nested);
qdict_flatten(dict_nested);
diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c
index 13a824cfae..e1e0a96661 100644
--- a/tests/check-qom-proplist.c
+++ b/tests/check-qom-proplist.c
@@ -419,9 +419,7 @@ static void test_dummy_createcmdl(void)
g_assert(dobj->bv == true);
g_assert(dobj->av == DUMMY_PLATYPUS);
- user_creatable_del("dev0", &err);
- g_assert(err == NULL);
- error_free(err);
+ user_creatable_del("dev0", &error_abort);
object_unref(OBJECT(dobj));
@@ -485,8 +483,7 @@ static void test_dummy_getenum(void)
val = object_property_get_enum(OBJECT(dobj),
"av",
"DummyAnimal",
- &err);
- g_assert(err == NULL);
+ &error_abort);
g_assert(val == DUMMY_PLATYPUS);
/* A bad enum type name */
@@ -494,17 +491,14 @@ static void test_dummy_getenum(void)
"av",
"BadAnimal",
&err);
- g_assert(err != NULL);
- error_free(err);
- err = NULL;
+ error_free_or_abort(&err);
/* A non-enum property name */
val = object_property_get_enum(OBJECT(dobj),
"iv",
"DummyAnimal",
&err);
- g_assert(err != NULL);
- error_free(err);
+ error_free_or_abort(&err);
object_unparent(OBJECT(dobj));
}
diff --git a/tests/data/acpi/virt/DSDT b/tests/data/acpi/virt/DSDT
index d6f5c61788..e669508d17 100644
--- a/tests/data/acpi/virt/DSDT
+++ b/tests/data/acpi/virt/DSDT
Binary files differ
diff --git a/tests/data/acpi/virt/DSDT.memhp b/tests/data/acpi/virt/DSDT.memhp
index 730e95a46d..4cb81f692d 100644
--- a/tests/data/acpi/virt/DSDT.memhp
+++ b/tests/data/acpi/virt/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/virt/DSDT.numamem b/tests/data/acpi/virt/DSDT.numamem
index d6f5c61788..e669508d17 100644
--- a/tests/data/acpi/virt/DSDT.numamem
+++ b/tests/data/acpi/virt/DSDT.numamem
Binary files differ
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
index 0ea80d35f0..da8ad87187 100644
--- a/tests/qemu-iotests/051.pc.out
+++ b/tests/qemu-iotests/051.pc.out
@@ -142,7 +142,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive if=ide
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: Initialization of device ide-hd failed: Device needs media, but drive is empty
+(qemu) QEMU_PROG: Device needs media, but drive is empty
Testing: -drive if=virtio
QEMU X.Y.Z monitor - type 'help' for more information
@@ -214,7 +214,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: Initialization of device ide-hd failed: Block node is read-only
+(qemu) QEMU_PROG: Block node is read-only
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
diff --git a/tests/qemu-iotests/291 b/tests/qemu-iotests/291
index 28e4fb9b4d..1e0bb76959 100755
--- a/tests/qemu-iotests/291
+++ b/tests/qemu-iotests/291
@@ -64,8 +64,6 @@ $QEMU_IO -c 'w 1M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG bitmap --disable -f $IMGFMT "$TEST_IMG" b1
$QEMU_IMG bitmap --enable -f $IMGFMT "$TEST_IMG" b2
$QEMU_IO -c 'w 2M 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
-echo "Check resulting qcow2 header extensions:"
-$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
echo
echo "=== Bitmap preservation not possible to non-qcow2 ==="
@@ -92,8 +90,6 @@ $QEMU_IMG bitmap --merge tmp -f $IMGFMT "$TEST_IMG" b0
$QEMU_IMG bitmap --remove --image-opts \
driver=$IMGFMT,file.driver=file,file.filename="$TEST_IMG" tmp
_img_info --format-specific
-echo "Check resulting qcow2 header extensions:"
-$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
echo
echo "=== Check bitmap contents ==="
diff --git a/tests/qemu-iotests/291.out b/tests/qemu-iotests/291.out
index 08bfaaaa6b..9f661515b4 100644
--- a/tests/qemu-iotests/291.out
+++ b/tests/qemu-iotests/291.out
@@ -14,25 +14,6 @@ wrote 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 1048576/1048576 bytes at offset 2097152
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Check resulting qcow2 header extensions:
-Header extension:
-magic 0xe2792aca (Backing format)
-length 5
-data 'qcow2'
-
-Header extension:
-magic 0x6803f857 (Feature table)
-length 336
-data <binary>
-
-Header extension:
-magic 0x23852875 (Bitmaps)
-length 24
-nb_bitmaps 2
-reserved32 0
-bitmap_directory_size 0x40
-bitmap_directory_offset 0x510000
-
=== Bitmap preservation not possible to non-qcow2 ===
@@ -84,20 +65,6 @@ Format specific information:
granularity: 65536
refcount bits: 16
corrupt: false
-Check resulting qcow2 header extensions:
-Header extension:
-magic 0x6803f857 (Feature table)
-length 336
-data <binary>
-
-Header extension:
-magic 0x23852875 (Bitmaps)
-length 24
-nb_bitmaps 3
-reserved32 0
-bitmap_directory_size 0x60
-bitmap_directory_offset 0x520000
-
=== Check bitmap contents ===
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 5ea4c4df8b..ef739dd1e3 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -146,11 +146,12 @@ def qemu_img_pipe(*args):
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
- exitcode = subp.wait()
- if exitcode < 0:
+ output = subp.communicate()[0]
+ if subp.returncode < 0:
sys.stderr.write('qemu-img received signal %i: %s\n'
- % (-exitcode, ' '.join(qemu_img_args + list(args))))
- return subp.communicate()[0]
+ % (-subp.returncode,
+ ' '.join(qemu_img_args + list(args))))
+ return output
def qemu_img_log(*args):
result = qemu_img_pipe(*args)
@@ -177,11 +178,11 @@ def qemu_io(*args):
subp = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
- exitcode = subp.wait()
- if exitcode < 0:
+ output = subp.communicate()[0]
+ if subp.returncode < 0:
sys.stderr.write('qemu-io received signal %i: %s\n'
- % (-exitcode, ' '.join(args)))
- return subp.communicate()[0]
+ % (-subp.returncode, ' '.join(args)))
+ return output
def qemu_io_log(*args):
result = qemu_io(*args)
@@ -257,15 +258,14 @@ def qemu_nbd_early_pipe(*args):
and its output in case of an error'''
subp = subprocess.Popen(qemu_nbd_args + ['--fork'] + list(args),
stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
universal_newlines=True)
- exitcode = subp.wait()
- if exitcode < 0:
+ output = subp.communicate()[0]
+ if subp.returncode < 0:
sys.stderr.write('qemu-nbd received signal %i: %s\n' %
- (-exitcode,
+ (-subp.returncode,
' '.join(qemu_nbd_args + ['--fork'] + list(args))))
- return exitcode, subp.communicate()[0] if exitcode else ''
+ return subp.returncode, output if subp.returncode else ''
def qemu_nbd_popen(*args):
'''Run qemu-nbd in daemon mode and return the parent's exit code'''
@@ -1062,11 +1062,11 @@ def qemu_pipe(*args):
subp = subprocess.Popen(args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
- exitcode = subp.wait()
- if exitcode < 0:
+ output = subp.communicate()[0]
+ if subp.returncode < 0:
sys.stderr.write('qemu received signal %i: %s\n' %
- (-exitcode, ' '.join(args)))
- return subp.communicate()[0]
+ (-subp.returncode, ' '.join(args)))
+ return output
def supported_formats(read_only=False):
'''Set 'read_only' to True to check ro-whitelist
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 8992f1f12b..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,19 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/pc/DSDT",
-"tests/data/acpi/pc/DSDT.acpihmat",
-"tests/data/acpi/pc/DSDT.bridge",
-"tests/data/acpi/pc/DSDT.cphp",
-"tests/data/acpi/pc/DSDT.dimmpxm",
-"tests/data/acpi/pc/DSDT.ipmikcs",
-"tests/data/acpi/pc/DSDT.memhp",
-"tests/data/acpi/pc/DSDT.numamem",
-"tests/data/acpi/q35/DSDT",
-"tests/data/acpi/q35/DSDT.acpihmat",
-"tests/data/acpi/q35/DSDT.bridge",
-"tests/data/acpi/q35/DSDT.cphp",
-"tests/data/acpi/q35/DSDT.dimmpxm",
-"tests/data/acpi/q35/DSDT.ipmibt",
-"tests/data/acpi/q35/DSDT.memhp",
-"tests/data/acpi/q35/DSDT.mmio64",
-"tests/data/acpi/q35/DSDT.numamem",
-"tests/data/acpi/q35/DSDT.tis",
diff --git a/tests/test-base64.c b/tests/test-base64.c
index ec122ceba5..a7f722c459 100644
--- a/tests/test-base64.c
+++ b/tests/test-base64.c
@@ -54,10 +54,9 @@ static void test_base64_bad(const char *input,
&len,
&err);
- g_assert(err != NULL);
+ error_free_or_abort(&err);
g_assert(actual == NULL);
g_assert_cmpint(len, ==, 0);
- error_free(err);
}
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
index f93f3168b0..8cff13830e 100644
--- a/tests/test-bdrv-graph-mod.c
+++ b/tests/test-bdrv-graph-mod.c
@@ -115,9 +115,7 @@ static void test_update_perm_tree(void)
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, &error_abort);
bdrv_append(filter, bs, &local_err);
-
- g_assert_nonnull(local_err);
- error_free(local_err);
+ error_free_or_abort(&local_err);
blk_unref(root);
}
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
index a953794be2..3f866a35c6 100644
--- a/tests/test-block-iothread.c
+++ b/tests/test-block-iothread.c
@@ -650,8 +650,7 @@ static void test_propagate_mirror(void)
blk_insert_bs(blk, src, &error_abort);
bdrv_try_set_aio_context(target, ctx, &local_err);
- g_assert(local_err);
- error_free(local_err);
+ error_free_or_abort(&local_err);
g_assert(blk_get_aio_context(blk) == main_ctx);
g_assert(bdrv_get_aio_context(src) == main_ctx);
diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
index 07fa2fa616..bebba1a4f4 100644
--- a/tests/test-crypto-cipher.c
+++ b/tests/test-crypto-cipher.c
@@ -761,10 +761,7 @@ static void test_cipher_short_plaintext(void)
sizeof(plaintext1),
&err);
g_assert(ret == -1);
- g_assert(err != NULL);
-
- error_free(err);
- err = NULL;
+ error_free_or_abort(&err);
/* Should report an error as plaintext is larger than
* block size, but not a multiple of block size
@@ -775,9 +772,8 @@ static void test_cipher_short_plaintext(void)
sizeof(plaintext2),
&err);
g_assert(ret == -1);
- g_assert(err != NULL);
+ error_free_or_abort(&err);
- error_free(err);
qcrypto_cipher_free(cipher);
}
diff --git a/tests/test-io-task.c b/tests/test-io-task.c
index c8a3813d49..85e7a98da5 100644
--- a/tests/test-io-task.c
+++ b/tests/test-io-task.c
@@ -240,9 +240,7 @@ static void test_task_thread_failure(void)
object_unref(obj);
g_assert(data.source == obj);
- g_assert(data.err != NULL);
-
- error_free(data.err);
+ error_free_or_abort(&data.err);
self = g_thread_self();
diff --git a/tests/test-logging.c b/tests/test-logging.c
index 8580b82420..8a1161de1d 100644
--- a/tests/test-logging.c
+++ b/tests/test-logging.c
@@ -113,7 +113,6 @@ static void test_logfile_write(gconstpointer data)
QemuLogFile *logfile;
QemuLogFile *logfile2;
gchar const *dir = data;
- Error *err = NULL;
g_autofree gchar *file_path = NULL;
g_autofree gchar *file_path1 = NULL;
FILE *orig_fd;
@@ -132,8 +131,7 @@ static void test_logfile_write(gconstpointer data)
* Test that even if an open file handle is changed,
* our handle remains valid due to RCU.
*/
- qemu_set_log_filename(file_path, &err);
- g_assert(!err);
+ qemu_set_log_filename(file_path, &error_abort);
rcu_read_lock();
logfile = atomic_rcu_read(&qemu_logfile);
orig_fd = logfile->fd;
@@ -142,8 +140,7 @@ static void test_logfile_write(gconstpointer data)
fflush(logfile->fd);
/* Change the logfile and ensure that the handle is still valid. */
- qemu_set_log_filename(file_path1, &err);
- g_assert(!err);
+ qemu_set_log_filename(file_path1, &error_abort);
logfile2 = atomic_rcu_read(&qemu_logfile);
g_assert(logfile->fd == orig_fd);
g_assert(logfile2->fd != logfile->fd);
@@ -156,7 +153,6 @@ static void test_logfile_lock(gconstpointer data)
{
FILE *logfile;
gchar const *dir = data;
- Error *err = NULL;
g_autofree gchar *file_path = NULL;
file_path = g_build_filename(dir, "qemu_test_logfile_lock0.log", NULL);
@@ -166,7 +162,7 @@ static void test_logfile_lock(gconstpointer data)
* that even if an open file handle is closed,
* our handle remains valid for use due to RCU.
*/
- qemu_set_log_filename(file_path, &err);
+ qemu_set_log_filename(file_path, &error_abort);
logfile = qemu_log_lock();
g_assert(logfile);
fprintf(logfile, "%s 1st write to file\n", __func__);
@@ -180,8 +176,6 @@ static void test_logfile_lock(gconstpointer data)
fprintf(logfile, "%s 2nd write to file\n", __func__);
fflush(logfile);
qemu_log_unlock(logfile);
-
- g_assert(!err);
}
/* Remove a directory and all its entries (non-recursive). */
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index 2a0f42a09b..297ffe79dd 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -187,7 +187,6 @@ static void test_qemu_opt_get(void)
static void test_qemu_opt_get_bool(void)
{
- Error *err = NULL;
QemuOptsList *list;
QemuOpts *opts;
bool opt;
@@ -210,16 +209,14 @@ static void test_qemu_opt_get_bool(void)
opt = qemu_opt_get_bool(opts, "bool1", false);
g_assert(opt == false);
- qemu_opt_set_bool(opts, "bool1", true, &err);
- g_assert(!err);
+ qemu_opt_set_bool(opts, "bool1", true, &error_abort);
/* now we have set bool1, should know about it */
opt = qemu_opt_get_bool(opts, "bool1", false);
g_assert(opt == true);
/* having reset the value, opt should be the reset one not defval */
- qemu_opt_set_bool(opts, "bool1", false, &err);
- g_assert(!err);
+ qemu_opt_set_bool(opts, "bool1", false, &error_abort);
opt = qemu_opt_get_bool(opts, "bool1", true);
g_assert(opt == false);
@@ -233,7 +230,6 @@ static void test_qemu_opt_get_bool(void)
static void test_qemu_opt_get_number(void)
{
- Error *err = NULL;
QemuOptsList *list;
QemuOpts *opts;
uint64_t opt;
@@ -256,16 +252,14 @@ static void test_qemu_opt_get_number(void)
opt = qemu_opt_get_number(opts, "number1", 5);
g_assert(opt == 5);
- qemu_opt_set_number(opts, "number1", 10, &err);
- g_assert(!err);
+ qemu_opt_set_number(opts, "number1", 10, &error_abort);
/* now we have set number1, should know about it */
opt = qemu_opt_get_number(opts, "number1", 5);
g_assert(opt == 10);
/* having reset it, the returned should be the reset one not defval */
- qemu_opt_set_number(opts, "number1", 15, &err);
- g_assert(!err);
+ qemu_opt_set_number(opts, "number1", 15, &error_abort);
opt = qemu_opt_get_number(opts, "number1", 5);
g_assert(opt == 15);
@@ -367,7 +361,6 @@ static void test_qemu_opt_unset(void)
static void test_qemu_opts_reset(void)
{
- Error *err = NULL;
QemuOptsList *list;
QemuOpts *opts;
uint64_t opt;
@@ -390,8 +383,7 @@ static void test_qemu_opts_reset(void)
opt = qemu_opt_get_number(opts, "number1", 5);
g_assert(opt == 5);
- qemu_opt_set_number(opts, "number1", 10, &err);
- g_assert(!err);
+ qemu_opt_set_number(opts, "number1", 10, &error_abort);
/* now we have set number1, should know about it */
opt = qemu_opt_get_number(opts, "number1", 5);
@@ -406,7 +398,6 @@ static void test_qemu_opts_reset(void)
static void test_qemu_opts_set(void)
{
- Error *err = NULL;
QemuOptsList *list;
QemuOpts *opts;
const char *opt;
@@ -421,8 +412,7 @@ static void test_qemu_opts_set(void)
g_assert(opts == NULL);
/* implicitly create opts and set str3 value */
- qemu_opts_set(list, NULL, "str3", "value", &err);
- g_assert(!err);
+ qemu_opts_set(list, NULL, "str3", "value", &error_abort);
g_assert(!QTAILQ_EMPTY(&list->head));
/* get the just created opts */
diff --git a/tests/test-replication.c b/tests/test-replication.c
index cbc37db2df..e0b03dafc2 100644
--- a/tests/test-replication.c
+++ b/tests/test-replication.c
@@ -139,8 +139,6 @@ static void make_temp(char *template)
static void prepare_imgs(void)
{
- Error *local_err = NULL;
-
make_temp(p_local_disk);
make_temp(s_local_disk);
make_temp(s_active_disk);
@@ -148,19 +146,15 @@ static void prepare_imgs(void)
/* Primary */
bdrv_img_create(p_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
- BDRV_O_RDWR, true, &local_err);
- g_assert(!local_err);
+ BDRV_O_RDWR, true, &error_abort);
/* Secondary */
bdrv_img_create(s_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
- BDRV_O_RDWR, true, &local_err);
- g_assert(!local_err);
+ BDRV_O_RDWR, true, &error_abort);
bdrv_img_create(s_active_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
- BDRV_O_RDWR, true, &local_err);
- g_assert(!local_err);
+ BDRV_O_RDWR, true, &error_abort);
bdrv_img_create(s_hidden_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
- BDRV_O_RDWR, true, &local_err);
- g_assert(!local_err);
+ BDRV_O_RDWR, true, &error_abort);
}
static void cleanup_imgs(void)
@@ -179,7 +173,6 @@ static BlockBackend *start_primary(void)
BlockBackend *blk;
QemuOpts *opts;
QDict *qdict;
- Error *local_err = NULL;
char *cmdline;
cmdline = g_strdup_printf("driver=replication,mode=primary,node-name=xxx,"
@@ -193,12 +186,10 @@ static BlockBackend *start_primary(void)
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
- blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
+ blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort);
g_assert(blk);
- g_assert(!local_err);
- monitor_add_blk(blk, P_ID, &local_err);
- g_assert(!local_err);
+ monitor_add_blk(blk, P_ID, &error_abort);
qemu_opts_del(opts);
@@ -248,12 +239,10 @@ static void test_primary_write(void)
static void test_primary_start(void)
{
BlockBackend *blk = NULL;
- Error *local_err = NULL;
blk = start_primary();
- replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort);
/* read from 0 to IMG_SIZE */
test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
@@ -266,46 +255,35 @@ static void test_primary_start(void)
static void test_primary_stop(void)
{
- Error *local_err = NULL;
bool failover = true;
start_primary();
- replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort);
- replication_stop_all(failover, &local_err);
- g_assert(!local_err);
+ replication_stop_all(failover, &error_abort);
teardown_primary();
}
static void test_primary_do_checkpoint(void)
{
- Error *local_err = NULL;
-
start_primary();
- replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort);
- replication_do_checkpoint_all(&local_err);
- g_assert(!local_err);
+ replication_do_checkpoint_all(&error_abort);
teardown_primary();
}
static void test_primary_get_error_all(void)
{
- Error *local_err = NULL;
-
start_primary();
- replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort);
- replication_get_error_all(&local_err);
- g_assert(!local_err);
+ replication_get_error_all(&error_abort);
teardown_primary();
}
@@ -316,7 +294,6 @@ static BlockBackend *start_secondary(void)
QDict *qdict;
BlockBackend *blk;
char *cmdline;
- Error *local_err = NULL;
/* add s_local_disk and forge S_LOCAL_DISK_ID */
cmdline = g_strdup_printf("file.filename=%s,driver=qcow2,"
@@ -329,10 +306,9 @@ static BlockBackend *start_secondary(void)
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
- blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
+ blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort);
assert(blk);
- monitor_add_blk(blk, S_LOCAL_DISK_ID, &local_err);
- g_assert(!local_err);
+ monitor_add_blk(blk, S_LOCAL_DISK_ID, &error_abort);
/* format s_local_disk with pattern "0x11" */
test_blk_write(blk, 0x11, 0, IMG_SIZE, false);
@@ -356,10 +332,9 @@ static BlockBackend *start_secondary(void)
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
- blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
+ blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &error_abort);
assert(blk);
- monitor_add_blk(blk, S_ID, &local_err);
- g_assert(!local_err);
+ monitor_add_blk(blk, S_ID, &error_abort);
qemu_opts_del(opts);
@@ -420,12 +395,10 @@ static void test_secondary_write(void)
static void test_secondary_start(void)
{
BlockBackend *top_blk, *local_blk;
- Error *local_err = NULL;
bool failover = true;
top_blk = start_secondary();
- replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort);
/* read from s_local_disk (0, IMG_SIZE) */
test_blk_read(top_blk, 0x11, 0, IMG_SIZE, 0, IMG_SIZE, false);
@@ -446,8 +419,7 @@ static void test_secondary_start(void)
0, IMG_SIZE / 2, false);
/* unblock top_bs */
- replication_stop_all(failover, &local_err);
- g_assert(!local_err);
+ replication_stop_all(failover, &error_abort);
teardown_secondary();
}
@@ -456,12 +428,10 @@ static void test_secondary_start(void)
static void test_secondary_stop(void)
{
BlockBackend *top_blk, *local_blk;
- Error *local_err = NULL;
bool failover = true;
top_blk = start_secondary();
- replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort);
/* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
local_blk = blk_by_name(S_LOCAL_DISK_ID);
@@ -475,8 +445,7 @@ static void test_secondary_stop(void)
test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false);
/* do active commit */
- replication_stop_all(failover, &local_err);
- g_assert(!local_err);
+ replication_stop_all(failover, &error_abort);
/* read from s_local_disk (0, IMG_SIZE / 2) */
test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2,
@@ -493,11 +462,9 @@ static void test_secondary_stop(void)
static void test_secondary_continuous_replication(void)
{
BlockBackend *top_blk, *local_blk;
- Error *local_err = NULL;
top_blk = start_secondary();
- replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort);
/* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
local_blk = blk_by_name(S_LOCAL_DISK_ID);
@@ -511,22 +478,18 @@ static void test_secondary_continuous_replication(void)
test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false);
/* do failover (active commit) */
- replication_stop_all(true, &local_err);
- g_assert(!local_err);
+ replication_stop_all(true, &error_abort);
/* it should ignore all requests from now on */
/* start after failover */
- replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_PRIMARY, &error_abort);
/* checkpoint */
- replication_do_checkpoint_all(&local_err);
- g_assert(!local_err);
+ replication_do_checkpoint_all(&error_abort);
/* stop */
- replication_stop_all(true, &local_err);
- g_assert(!local_err);
+ replication_stop_all(true, &error_abort);
/* read from s_local_disk (0, IMG_SIZE / 2) */
test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2,
@@ -543,12 +506,10 @@ static void test_secondary_continuous_replication(void)
static void test_secondary_do_checkpoint(void)
{
BlockBackend *top_blk, *local_blk;
- Error *local_err = NULL;
bool failover = true;
top_blk = start_secondary();
- replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort);
/* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
local_blk = blk_by_name(S_LOCAL_DISK_ID);
@@ -559,35 +520,29 @@ static void test_secondary_do_checkpoint(void)
test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
IMG_SIZE / 2, 0, IMG_SIZE, false);
- replication_do_checkpoint_all(&local_err);
- g_assert(!local_err);
+ replication_do_checkpoint_all(&error_abort);
/* after checkpoint, read pattern 0x22 from s_local_disk */
test_blk_read(top_blk, 0x22, IMG_SIZE / 2,
IMG_SIZE / 2, 0, IMG_SIZE, false);
/* unblock top_bs */
- replication_stop_all(failover, &local_err);
- g_assert(!local_err);
+ replication_stop_all(failover, &error_abort);
teardown_secondary();
}
static void test_secondary_get_error_all(void)
{
- Error *local_err = NULL;
bool failover = true;
start_secondary();
- replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
- g_assert(!local_err);
+ replication_start_all(REPLICATION_MODE_SECONDARY, &error_abort);
- replication_get_error_all(&local_err);
- g_assert(!local_err);
+ replication_get_error_all(&error_abort);
/* unblock top_bs */
- replication_stop_all(failover, &local_err);
- g_assert(!local_err);
+ replication_stop_all(failover, &error_abort);
teardown_secondary();
}
diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c
index 5418e085a4..249faafc9d 100644
--- a/tests/test-string-input-visitor.c
+++ b/tests/test-string-input-visitor.c
@@ -53,8 +53,7 @@ static void test_visitor_in_int(TestInputVisitorData *data,
v = visitor_input_test_init(data, "-42");
- visit_type_int(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_int(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, value);
v = visitor_input_test_init(data, "not an int");
@@ -327,44 +326,37 @@ static void test_visitor_in_uintList(TestInputVisitorData *data,
static void test_visitor_in_bool(TestInputVisitorData *data,
const void *unused)
{
- Error *err = NULL;
bool res = false;
Visitor *v;
v = visitor_input_test_init(data, "true");
- visit_type_bool(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, true);
v = visitor_input_test_init(data, "yes");
- visit_type_bool(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, true);
v = visitor_input_test_init(data, "on");
- visit_type_bool(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, true);
v = visitor_input_test_init(data, "false");
- visit_type_bool(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, false);
v = visitor_input_test_init(data, "no");
- visit_type_bool(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, false);
v = visitor_input_test_init(data, "off");
- visit_type_bool(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_bool(v, NULL, &res, &error_abort);
g_assert_cmpint(res, ==, false);
}
@@ -377,8 +369,7 @@ static void test_visitor_in_number(TestInputVisitorData *data,
v = visitor_input_test_init(data, "3.14");
- visit_type_number(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_number(v, NULL, &res, &error_abort);
g_assert_cmpfloat(res, ==, value);
/* NaN and infinity has to be rejected */
@@ -399,13 +390,11 @@ static void test_visitor_in_string(TestInputVisitorData *data,
const void *unused)
{
char *res = NULL, *value = (char *) "Q E M U";
- Error *err = NULL;
Visitor *v;
v = visitor_input_test_init(data, value);
- visit_type_str(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_str(v, NULL, &res, &error_abort);
g_assert_cmpstr(res, ==, value);
g_free(res);
@@ -414,7 +403,6 @@ static void test_visitor_in_string(TestInputVisitorData *data,
static void test_visitor_in_enum(TestInputVisitorData *data,
const void *unused)
{
- Error *err = NULL;
Visitor *v;
EnumOne i;
@@ -423,8 +411,7 @@ static void test_visitor_in_enum(TestInputVisitorData *data,
v = visitor_input_test_init(data, EnumOne_str(i));
- visit_type_EnumOne(v, NULL, &res, &err);
- g_assert(!err);
+ visit_type_EnumOne(v, NULL, &res, &error_abort);
g_assert_cmpint(i, ==, res);
}
}
diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c
index 3bd732222c..9f6581439a 100644
--- a/tests/test-string-output-visitor.c
+++ b/tests/test-string-output-visitor.c
@@ -71,11 +71,9 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
const void *unused)
{
int64_t value = 42;
- Error *err = NULL;
char *str;
- visit_type_int(data->ov, NULL, &value, &err);
- g_assert(!err);
+ visit_type_int(data->ov, NULL, &value, &error_abort);
str = visitor_get(data);
if (data->human) {
@@ -120,12 +118,10 @@ static void test_visitor_out_intList(TestOutputVisitorData *data,
static void test_visitor_out_bool(TestOutputVisitorData *data,
const void *unused)
{
- Error *err = NULL;
bool value = true;
char *str;
- visit_type_bool(data->ov, NULL, &value, &err);
- g_assert(!err);
+ visit_type_bool(data->ov, NULL, &value, &error_abort);
str = visitor_get(data);
g_assert_cmpstr(str, ==, "true");
@@ -135,11 +131,9 @@ static void test_visitor_out_number(TestOutputVisitorData *data,
const void *unused)
{
double value = 3.14;
- Error *err = NULL;
char *str;
- visit_type_number(data->ov, NULL, &value, &err);
- g_assert(!err);
+ visit_type_number(data->ov, NULL, &value, &error_abort);
str = visitor_get(data);
g_assert_cmpstr(str, ==, "3.140000");
@@ -150,11 +144,9 @@ static void test_visitor_out_string(TestOutputVisitorData *data,
{
char *string = (char *) "Q E M U";
const char *string_human = "\"Q E M U\"";
- Error *err = NULL;
char *str;
- visit_type_str(data->ov, NULL, &string, &err);
- g_assert(!err);
+ visit_type_str(data->ov, NULL, &string, &error_abort);
str = visitor_get(data);
if (data->human) {
diff --git a/tests/test-util-filemonitor.c b/tests/test-util-filemonitor.c
index 45009c69f4..8f0eff3d03 100644
--- a/tests/test-util-filemonitor.c
+++ b/tests/test-util-filemonitor.c
@@ -495,6 +495,7 @@ test_file_monitor_events(void)
if (*op->watchid < 0) {
g_printerr("Unable to add watch %s",
error_get_pretty(local_err));
+ error_free(local_err);
goto cleanup;
}
if (debug) {
diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
index 00a1ef666a..3105b6c23a 100644
--- a/tools/virtiofsd/helper.c
+++ b/tools/virtiofsd/helper.c
@@ -174,6 +174,8 @@ void fuse_cmdline_help(void)
" default: no_writeback\n"
" -o xattr|no_xattr enable/disable xattr\n"
" default: no_xattr\n"
+ " -o modcaps=CAPLIST Modify the list of capabilities\n"
+ " e.g. -o modcaps=+sys_admin:-chown\n"
" --rlimit-nofile=<num> set maximum number of file descriptors\n"
" (0 leaves rlimit unchanged)\n"
" default: min(1000000, fs.file-max - 16384)\n"
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 2ce7c96085..94e0de2d2b 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -145,6 +145,7 @@ struct lo_data {
int posix_lock;
int xattr;
char *source;
+ char *modcaps;
double timeout;
int cache;
int timeout_set;
@@ -170,6 +171,7 @@ static const struct fuse_opt lo_opts[] = {
{ "no_posix_lock", offsetof(struct lo_data, posix_lock), 0 },
{ "xattr", offsetof(struct lo_data, xattr), 1 },
{ "no_xattr", offsetof(struct lo_data, xattr), 0 },
+ { "modcaps=%s", offsetof(struct lo_data, modcaps), 0 },
{ "timeout=%lf", offsetof(struct lo_data, timeout), 0 },
{ "timeout=", offsetof(struct lo_data, timeout_set), 1 },
{ "cache=none", offsetof(struct lo_data, cache), CACHE_NONE },
@@ -2570,9 +2572,11 @@ static void setup_mounts(const char *source)
/*
* Only keep whitelisted capabilities that are needed for file system operation
+ * The (possibly NULL) modcaps_in string passed in is free'd before exit.
*/
-static void setup_capabilities(void)
+static void setup_capabilities(char *modcaps_in)
{
+ char *modcaps = modcaps_in;
pthread_mutex_lock(&cap.mutex);
capng_restore_state(&cap.saved);
@@ -2589,7 +2593,7 @@ static void setup_capabilities(void)
*/
capng_setpid(syscall(SYS_gettid));
capng_clear(CAPNG_SELECT_BOTH);
- capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE,
+ if (capng_updatev(CAPNG_ADD, CAPNG_PERMITTED | CAPNG_EFFECTIVE,
CAP_CHOWN,
CAP_DAC_OVERRIDE,
CAP_DAC_READ_SEARCH,
@@ -2598,10 +2602,67 @@ static void setup_capabilities(void)
CAP_SETGID,
CAP_SETUID,
CAP_MKNOD,
- CAP_SETFCAP);
- capng_apply(CAPNG_SELECT_BOTH);
+ CAP_SETFCAP,
+ -1)) {
+ fuse_log(FUSE_LOG_ERR, "%s: capng_updatev failed\n", __func__);
+ exit(1);
+ }
+
+ /*
+ * The modcaps option is a colon separated list of caps,
+ * each preceded by either + or -.
+ */
+ while (modcaps) {
+ capng_act_t action;
+ int cap;
+
+ char *next = strchr(modcaps, ':');
+ if (next) {
+ *next = '\0';
+ next++;
+ }
+
+ switch (modcaps[0]) {
+ case '+':
+ action = CAPNG_ADD;
+ break;
+
+ case '-':
+ action = CAPNG_DROP;
+ break;
+
+ default:
+ fuse_log(FUSE_LOG_ERR,
+ "%s: Expecting '+'/'-' in modcaps but found '%c'\n",
+ __func__, modcaps[0]);
+ exit(1);
+ }
+ cap = capng_name_to_capability(modcaps + 1);
+ if (cap < 0) {
+ fuse_log(FUSE_LOG_ERR, "%s: Unknown capability '%s'\n", __func__,
+ modcaps);
+ exit(1);
+ }
+ if (capng_update(action, CAPNG_PERMITTED | CAPNG_EFFECTIVE, cap)) {
+ fuse_log(FUSE_LOG_ERR, "%s: capng_update failed for '%s'\n",
+ __func__, modcaps);
+ exit(1);
+ }
+
+ modcaps = next;
+ }
+ g_free(modcaps_in);
+
+ if (capng_apply(CAPNG_SELECT_BOTH)) {
+ fuse_log(FUSE_LOG_ERR, "%s: capng_apply failed\n", __func__);
+ exit(1);
+ }
cap.saved = capng_save_state();
+ if (!cap.saved) {
+ fuse_log(FUSE_LOG_ERR, "%s: capng_save_state failed\n", __func__);
+ exit(1);
+ }
pthread_mutex_unlock(&cap.mutex);
}
@@ -2615,7 +2676,7 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se,
setup_namespaces(lo, se);
setup_mounts(lo->source);
setup_seccomp(enable_syslog);
- setup_capabilities();
+ setup_capabilities(g_strdup(lo->modcaps));
}
/* Set the maximum number of open file descriptors */
diff --git a/ui/vnc.c b/ui/vnc.c
index 12a12714e1..527ad25124 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -458,9 +458,8 @@ static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
Error *err = NULL;
SocketAddress *addr;
- addr = qio_channel_socket_get_local_address(ioc, &err);
+ addr = qio_channel_socket_get_local_address(ioc, NULL);
if (!addr) {
- error_free(err);
return prev;
}
@@ -3275,13 +3274,12 @@ int vnc_display_pw_expire(const char *id, time_t expires)
static void vnc_display_print_local_addr(VncDisplay *vd)
{
SocketAddress *addr;
- Error *err = NULL;
if (!vd->listener || !vd->listener->nsioc) {
return;
}
- addr = qio_channel_socket_get_local_address(vd->listener->sioc[0], &err);
+ addr = qio_channel_socket_get_local_address(vd->listener->sioc[0], NULL);
if (!addr) {
return;
}