aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS14
-rw-r--r--default-configs/devices/m68k-softmmu.mak1
-rw-r--r--default-configs/devices/tricore-softmmu.mak2
-rw-r--r--docs/specs/virt-ctlr.txt26
-rw-r--r--docs/system/deprecated.rst9
-rw-r--r--docs/system/removed-features.rst8
-rw-r--r--hw/avr/arduino.c20
-rw-r--r--hw/block/virtio-blk.c8
-rw-r--r--hw/char/Kconfig3
-rw-r--r--hw/char/goldfish_tty.c285
-rw-r--r--hw/char/meson.build2
-rw-r--r--hw/char/trace-events10
-rw-r--r--hw/core/machine.c2
-rw-r--r--hw/intc/Kconfig6
-rw-r--r--hw/intc/goldfish_pic.c219
-rw-r--r--hw/intc/m68k_irqc.c119
-rw-r--r--hw/intc/meson.build2
-rw-r--r--hw/intc/trace-events8
-rw-r--r--hw/isa/Kconfig1
-rw-r--r--hw/m68k/Kconfig9
-rw-r--r--hw/m68k/meson.build1
-rw-r--r--hw/m68k/virt.c313
-rw-r--r--hw/mips/gt64xxx_pci.c59
-rw-r--r--hw/mips/trace-events6
-rw-r--r--hw/misc/Kconfig3
-rw-r--r--hw/misc/led.c1
-rw-r--r--hw/misc/meson.build3
-rw-r--r--hw/misc/trace-events7
-rw-r--r--hw/misc/virt_ctrl.c151
-rw-r--r--hw/net/cadence_gem.c4
-rw-r--r--hw/net/dp8393x.c2
-rw-r--r--hw/net/e1000.c6
-rw-r--r--hw/net/lan9118.c2
-rw-r--r--hw/net/msf2-emac.c2
-rw-r--r--hw/net/net_tx_pkt.c2
-rw-r--r--hw/net/pcnet.c2
-rw-r--r--hw/net/rtl8139.c2
-rw-r--r--hw/net/sungem.c2
-rw-r--r--hw/net/xen_nic.c5
-rw-r--r--hw/rdma/vmw/pvrdma.h5
-rw-r--r--hw/rdma/vmw/pvrdma_cmd.c6
-rw-r--r--hw/rdma/vmw/pvrdma_dev_ring.c41
-rw-r--r--hw/rdma/vmw/pvrdma_dev_ring.h9
-rw-r--r--hw/rdma/vmw/pvrdma_main.c4
-rw-r--r--hw/tricore/Kconfig8
-rw-r--r--hw/tricore/meson.build2
-rw-r--r--hw/tricore/tc27x_soc.c246
-rw-r--r--hw/tricore/triboard.c98
-rw-r--r--hw/usb/Kconfig13
-rw-r--r--hw/usb/bus.c39
-rw-r--r--hw/usb/dev-audio.c1
-rw-r--r--hw/usb/dev-serial.c2
-rw-r--r--hw/usb/dev-storage-bot.c63
-rw-r--r--hw/usb/dev-storage-classic.c156
-rw-r--r--hw/usb/dev-storage.c226
-rw-r--r--hw/usb/hcd-uhci.c83
-rw-r--r--hw/usb/hcd-uhci.h93
-rw-r--r--hw/usb/meson.build5
-rw-r--r--hw/usb/u2f.c1
-rw-r--r--hw/usb/vt82c686-uhci-pci.c43
-rw-r--r--hw/virtio/virtio-net-pci.c10
-rw-r--r--include/hw/char/goldfish_tty.h35
-rw-r--r--include/hw/intc/goldfish_pic.h33
-rw-r--r--include/hw/intc/m68k_irqc.h41
-rw-r--r--include/hw/misc/led.h1
-rw-r--r--include/hw/misc/virt_ctrl.h22
-rw-r--r--include/hw/tricore/tc27x_soc.h129
-rw-r--r--include/hw/tricore/triboard.h50
-rw-r--r--include/hw/usb.h3
-rw-r--r--include/hw/usb/msd.h54
-rw-r--r--include/hw/virtio/virtio-blk.h1
-rw-r--r--include/net/net.h10
-rw-r--r--include/net/queue.h8
-rw-r--r--include/qapi/hmp-output-visitor.h30
-rw-r--r--include/standard-headers/asm-m68k/bootinfo-virt.h18
-rw-r--r--include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h114
-rw-r--r--migration/migration.c6
-rw-r--r--migration/multifd.c21
-rw-r--r--migration/ram.c6
-rw-r--r--monitor/monitor.c8
-rw-r--r--monitor/qmp.c51
-rw-r--r--net/l2tpv3.c8
-rw-r--r--net/net.c117
-rw-r--r--net/netmap.c7
-rw-r--r--net/queue.c22
-rw-r--r--net/slirp.c124
-rw-r--r--net/socket.c92
-rw-r--r--net/tap-win32.c10
-rw-r--r--net/tap.c107
-rw-r--r--net/vde.c25
-rw-r--r--net/vhost-user.c20
-rw-r--r--net/vhost-vdpa.c15
-rw-r--r--qapi/hmp-output-visitor.c193
-rw-r--r--qapi/meson.build1
-rw-r--r--qapi/net.json80
-rw-r--r--qemu-options.hx35
-rwxr-xr-xscripts/update-linux-headers.sh3
-rw-r--r--softmmu/vl.c2
-rw-r--r--target/avr/helper.c10
-rw-r--r--target/mips/meson.build18
-rw-r--r--target/mips/mxu_translate.c1609
-rw-r--r--target/mips/translate.c3663
-rw-r--r--target/mips/translate.h10
-rw-r--r--target/mips/tx79.decode39
-rw-r--r--target/mips/tx79_translate.c303
-rw-r--r--target/mips/txx9_translate.c20
-rw-r--r--target/tricore/cpu.h12
-rw-r--r--target/tricore/helper.c9
-rw-r--r--target/tricore/translate.c21
-rw-r--r--tests/qtest/meson.build3
-rw-r--r--tests/qtest/test-query-netdev.c120
-rw-r--r--tests/unit/test-cutils.c2
-rw-r--r--tools/virtiofsd/fuse_virtio.c6
-rw-r--r--tools/virtiofsd/passthrough_ll.c52
-rw-r--r--util/cutils.c50
115 files changed, 5581 insertions, 4349 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 5ca3c9f851..57f3d3f690 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1130,6 +1130,19 @@ F: include/hw/nubus/*
F: include/hw/display/macfb.h
F: include/hw/block/swim.h
+virt
+M: Laurent Vivier <laurent@vivier.eu>
+S: Maintained
+F: hw/m68k/virt.c
+F: hw/char/goldfish_tty.c
+F: hw/intc/goldfish_pic.c
+F: hw/intc/m68k_irqc.c
+F: hw/misc/virt_ctrl.c
+F: include/hw/char/goldfish_tty.h
+F: include/hw/intc/goldfish_pic.h
+F: include/hw/intc/m68k_irqc.h
+F: include/hw/misc/virt_ctrl.h
+
MicroBlaze Machines
-------------------
petalogix_s3adsp1800
@@ -1180,6 +1193,7 @@ S: Odd Fixes
F: hw/mips/fuloong2e.c
F: hw/isa/vt82c686.c
F: hw/pci-host/bonito.c
+F: hw/usb/vt82c686-uhci-pci.c
F: include/hw/isa/vt82c686.h
Loongson-3 virtual platforms
diff --git a/default-configs/devices/m68k-softmmu.mak b/default-configs/devices/m68k-softmmu.mak
index 6629fd2aa3..7f8619e427 100644
--- a/default-configs/devices/m68k-softmmu.mak
+++ b/default-configs/devices/m68k-softmmu.mak
@@ -8,3 +8,4 @@ CONFIG_AN5206=y
CONFIG_MCF5208=y
CONFIG_NEXTCUBE=y
CONFIG_Q800=y
+CONFIG_M68K_VIRT=y
diff --git a/default-configs/devices/tricore-softmmu.mak b/default-configs/devices/tricore-softmmu.mak
index c397cff38a..5cc91cebce 100644
--- a/default-configs/devices/tricore-softmmu.mak
+++ b/default-configs/devices/tricore-softmmu.mak
@@ -1 +1 @@
-CONFIG_TRICORE=y
+CONFIG_TRIBOARD=y
diff --git a/docs/specs/virt-ctlr.txt b/docs/specs/virt-ctlr.txt
new file mode 100644
index 0000000000..24d38084f7
--- /dev/null
+++ b/docs/specs/virt-ctlr.txt
@@ -0,0 +1,26 @@
+Virtual System Controller
+=========================
+
+This device is a simple interface defined for the pure virtual machine with no
+hardware reference implementation to allow the guest kernel to send command
+to the host hypervisor.
+
+The specification can evolve, the current state is defined as below.
+
+This is a MMIO mapped device using 256 bytes.
+
+Two 32bit registers are defined:
+
+1- the features register (read-only, address 0x00)
+
+ This register allows the device to report features supported by the
+ controller.
+ The only feature supported for the moment is power control (0x01).
+
+2- the command register (write-only, address 0x04)
+
+ This register allows the kernel to send the commands to the hypervisor.
+ The implemented commands are part of the power control feature and
+ are reset (1), halt (2) and panic (3).
+ A basic command, no-op (0), is always present and can be used to test the
+ register access. This command has no effect.
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 8cba672a7b..1db30f8f27 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -21,15 +21,6 @@ deprecated.
System emulator command line arguments
--------------------------------------
-``-usbdevice`` (since 2.10.0)
-'''''''''''''''''''''''''''''
-
-The ``-usbdevice DEV`` argument is now a synonym for setting
-the ``-device usb-DEV`` argument instead. The deprecated syntax
-would automatically enable USB support on the machine type.
-If using the new syntax, USB support must be explicitly
-enabled via the ``-machine usb=on`` argument.
-
``-drive file=json:{...{'driver':'file'}}`` (since 3.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst
index 83148dcfda..82e7fcc517 100644
--- a/docs/system/removed-features.rst
+++ b/docs/system/removed-features.rst
@@ -38,6 +38,14 @@ or ``-display default,show-cursor=on`` instead.
QEMU 5.0 introduced an alternative syntax to specify the size of the translation
block cache, ``-accel tcg,tb-size=``.
+``-usbdevice audio`` (removed in 6.0)
+'''''''''''''''''''''''''''''''''''''
+
+This option lacked the possibility to specify an audio backend device.
+Use ``-device usb-audio`` now instead (and specify a corresponding USB
+host controller or ``-usb`` if necessary).
+
+
QEMU Machine Protocol (QMP) commands
------------------------------------
diff --git a/hw/avr/arduino.c b/hw/avr/arduino.c
index 3c8388490d..3ff31492fa 100644
--- a/hw/avr/arduino.c
+++ b/hw/avr/arduino.c
@@ -75,7 +75,10 @@ static void arduino_duemilanove_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
- /* https://www.arduino.cc/en/Main/ArduinoBoardDuemilanove */
+ /*
+ * https://www.arduino.cc/en/Main/ArduinoBoardDuemilanove
+ * https://www.arduino.cc/en/uploads/Main/arduino-duemilanove-schematic.pdf
+ */
mc->desc = "Arduino Duemilanove (ATmega168)",
mc->alias = "2009";
amc->mcu_type = TYPE_ATMEGA168_MCU;
@@ -87,7 +90,10 @@ static void arduino_uno_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
- /* https://store.arduino.cc/arduino-uno-rev3 */
+ /*
+ * https://store.arduino.cc/arduino-uno-rev3
+ * https://www.arduino.cc/en/uploads/Main/arduino-uno-schematic.pdf
+ */
mc->desc = "Arduino UNO (ATmega328P)";
mc->alias = "uno";
amc->mcu_type = TYPE_ATMEGA328_MCU;
@@ -99,7 +105,10 @@ static void arduino_mega_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
- /* https://www.arduino.cc/en/Main/ArduinoBoardMega */
+ /*
+ * https://www.arduino.cc/en/Main/ArduinoBoardMega
+ * https://www.arduino.cc/en/uploads/Main/arduino-mega2560-schematic.pdf
+ */
mc->desc = "Arduino Mega (ATmega1280)";
mc->alias = "mega";
amc->mcu_type = TYPE_ATMEGA1280_MCU;
@@ -111,7 +120,10 @@ static void arduino_mega2560_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc);
- /* https://store.arduino.cc/arduino-mega-2560-rev3 */
+ /*
+ * https://store.arduino.cc/arduino-mega-2560-rev3
+ * https://www.arduino.cc/en/uploads/Main/arduino-mega2560_R3-sch.pdf
+ */
mc->desc = "Arduino Mega 2560 (ATmega2560)";
mc->alias = "mega2560";
amc->mcu_type = TYPE_ATMEGA2560_MCU;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 3d2072cf75..d28979efb8 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -962,10 +962,14 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blkcfg.wce = blk_enable_write_cache(s->blk);
virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues);
if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD)) {
+ uint32_t discard_granularity = conf->discard_granularity;
+ if (discard_granularity == -1 || !s->conf.report_discard_granularity) {
+ discard_granularity = blk_size;
+ }
virtio_stl_p(vdev, &blkcfg.max_discard_sectors,
s->conf.max_discard_sectors);
virtio_stl_p(vdev, &blkcfg.discard_sector_alignment,
- blk_size >> BDRV_SECTOR_BITS);
+ discard_granularity >> BDRV_SECTOR_BITS);
/*
* We support only one segment per request since multiple segments
* are not widely used and there are no userspace APIs that allow
@@ -1299,6 +1303,8 @@ static Property virtio_blk_properties[] = {
IOThread *),
DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
VIRTIO_BLK_F_DISCARD, true),
+ DEFINE_PROP_BOOL("report-discard-granularity", VirtIOBlock,
+ conf.report_discard_granularity, true),
DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
VIRTIO_BLK_F_WRITE_ZEROES, true),
DEFINE_PROP_UINT32("max-discard-sectors", VirtIOBlock,
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index f6f4fffd1b..4cf36ac637 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -64,3 +64,6 @@ config MCHP_PFSOC_MMUART
config SIFIVE_UART
bool
+
+config GOLDFISH_TTY
+ bool
diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c
new file mode 100644
index 0000000000..8365a18761
--- /dev/null
+++ b/hw/char/goldfish_tty.c
@@ -0,0 +1,285 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * Goldfish TTY
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "chardev/char-fe.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "exec/address-spaces.h"
+#include "hw/char/goldfish_tty.h"
+
+#define GOLDFISH_TTY_VERSION 1
+
+/* registers */
+
+enum {
+ REG_PUT_CHAR = 0x00,
+ REG_BYTES_READY = 0x04,
+ REG_CMD = 0x08,
+ REG_DATA_PTR = 0x10,
+ REG_DATA_LEN = 0x14,
+ REG_DATA_PTR_HIGH = 0x18,
+ REG_VERSION = 0x20,
+};
+
+/* commands */
+
+enum {
+ CMD_INT_DISABLE = 0x00,
+ CMD_INT_ENABLE = 0x01,
+ CMD_WRITE_BUFFER = 0x02,
+ CMD_READ_BUFFER = 0x03,
+};
+
+static uint64_t goldfish_tty_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ GoldfishTTYState *s = opaque;
+ uint64_t value = 0;
+
+ switch (addr) {
+ case REG_BYTES_READY:
+ value = fifo8_num_used(&s->rx_fifo);
+ break;
+ case REG_VERSION:
+ value = GOLDFISH_TTY_VERSION;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
+ __func__, addr);
+ break;
+ }
+
+ trace_goldfish_tty_read(s, addr, size, value);
+
+ return value;
+}
+
+static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
+{
+ uint32_t to_copy;
+ uint8_t *buf;
+ uint8_t data_out[GOLFISH_TTY_BUFFER_SIZE];
+ int len;
+ uint64_t ptr;
+
+ switch (cmd) {
+ case CMD_INT_DISABLE:
+ if (s->int_enabled) {
+ if (!fifo8_is_empty(&s->rx_fifo)) {
+ qemu_set_irq(s->irq, 0);
+ }
+ s->int_enabled = false;
+ }
+ break;
+ case CMD_INT_ENABLE:
+ if (!s->int_enabled) {
+ if (!fifo8_is_empty(&s->rx_fifo)) {
+ qemu_set_irq(s->irq, 1);
+ }
+ s->int_enabled = true;
+ }
+ break;
+ case CMD_WRITE_BUFFER:
+ len = s->data_len;
+ ptr = s->data_ptr;
+ while (len) {
+ to_copy = MIN(GOLFISH_TTY_BUFFER_SIZE, len);
+
+ address_space_rw(&address_space_memory, ptr,
+ MEMTXATTRS_UNSPECIFIED, data_out, to_copy, 0);
+ qemu_chr_fe_write_all(&s->chr, data_out, to_copy);
+
+ len -= to_copy;
+ ptr += to_copy;
+ }
+ break;
+ case CMD_READ_BUFFER:
+ len = s->data_len;
+ ptr = s->data_ptr;
+ while (len && !fifo8_is_empty(&s->rx_fifo)) {
+ buf = (uint8_t *)fifo8_pop_buf(&s->rx_fifo, len, &to_copy);
+ address_space_rw(&address_space_memory, ptr,
+ MEMTXATTRS_UNSPECIFIED, buf, to_copy, 1);
+
+ len -= to_copy;
+ ptr += to_copy;
+ }
+ if (s->int_enabled && fifo8_is_empty(&s->rx_fifo)) {
+ qemu_set_irq(s->irq, 0);
+ }
+ break;
+ }
+}
+
+static void goldfish_tty_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ GoldfishTTYState *s = opaque;
+ unsigned char c;
+
+ trace_goldfish_tty_write(s, addr, size, value);
+
+ switch (addr) {
+ case REG_PUT_CHAR:
+ c = value;
+ qemu_chr_fe_write_all(&s->chr, &c, sizeof(c));
+ break;
+ case REG_CMD:
+ goldfish_tty_cmd(s, value);
+ break;
+ case REG_DATA_PTR:
+ s->data_ptr = value;
+ break;
+ case REG_DATA_PTR_HIGH:
+ s->data_ptr = deposit64(s->data_ptr, 32, 32, value);
+ break;
+ case REG_DATA_LEN:
+ s->data_len = value;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
+ __func__, addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps goldfish_tty_ops = {
+ .read = goldfish_tty_read,
+ .write = goldfish_tty_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.max_access_size = 4,
+ .impl.max_access_size = 4,
+ .impl.min_access_size = 4,
+};
+
+static int goldfish_tty_can_receive(void *opaque)
+{
+ GoldfishTTYState *s = opaque;
+ int available = fifo8_num_free(&s->rx_fifo);
+
+ trace_goldfish_tty_can_receive(s, available);
+
+ return available;
+}
+
+static void goldfish_tty_receive(void *opaque, const uint8_t *buffer, int size)
+{
+ GoldfishTTYState *s = opaque;
+
+ trace_goldfish_tty_receive(s, size);
+
+ g_assert(size <= fifo8_num_free(&s->rx_fifo));
+
+ fifo8_push_all(&s->rx_fifo, buffer, size);
+
+ if (s->int_enabled && !fifo8_is_empty(&s->rx_fifo)) {
+ qemu_set_irq(s->irq, 1);
+ }
+}
+
+static void goldfish_tty_reset(DeviceState *dev)
+{
+ GoldfishTTYState *s = GOLDFISH_TTY(dev);
+
+ trace_goldfish_tty_reset(s);
+
+ fifo8_reset(&s->rx_fifo);
+ s->int_enabled = false;
+ s->data_ptr = 0;
+ s->data_len = 0;
+}
+
+static void goldfish_tty_realize(DeviceState *dev, Error **errp)
+{
+ GoldfishTTYState *s = GOLDFISH_TTY(dev);
+
+ trace_goldfish_tty_realize(s);
+
+ fifo8_create(&s->rx_fifo, GOLFISH_TTY_BUFFER_SIZE);
+ memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_tty_ops, s,
+ "goldfish_tty", 0x24);
+
+ if (qemu_chr_fe_backend_connected(&s->chr)) {
+ qemu_chr_fe_set_handlers(&s->chr, goldfish_tty_can_receive,
+ goldfish_tty_receive, NULL, NULL,
+ s, NULL, true);
+ }
+}
+
+static void goldfish_tty_unrealize(DeviceState *dev)
+{
+ GoldfishTTYState *s = GOLDFISH_TTY(dev);
+
+ trace_goldfish_tty_unrealize(s);
+
+ fifo8_destroy(&s->rx_fifo);
+}
+
+static const VMStateDescription vmstate_goldfish_tty = {
+ .name = "goldfish_tty",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(data_len, GoldfishTTYState),
+ VMSTATE_UINT64(data_ptr, GoldfishTTYState),
+ VMSTATE_BOOL(int_enabled, GoldfishTTYState),
+ VMSTATE_FIFO8(rx_fifo, GoldfishTTYState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property goldfish_tty_properties[] = {
+ DEFINE_PROP_CHR("chardev", GoldfishTTYState, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void goldfish_tty_instance_init(Object *obj)
+{
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+ GoldfishTTYState *s = GOLDFISH_TTY(obj);
+
+ trace_goldfish_tty_instance_init(s);
+
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+}
+
+static void goldfish_tty_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ device_class_set_props(dc, goldfish_tty_properties);
+ dc->reset = goldfish_tty_reset;
+ dc->realize = goldfish_tty_realize;
+ dc->unrealize = goldfish_tty_unrealize;
+ dc->vmsd = &vmstate_goldfish_tty;
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static const TypeInfo goldfish_tty_info = {
+ .name = TYPE_GOLDFISH_TTY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = goldfish_tty_class_init,
+ .instance_init = goldfish_tty_instance_init,
+ .instance_size = sizeof(GoldfishTTYState),
+};
+
+static void goldfish_tty_register_types(void)
+{
+ type_register_static(&goldfish_tty_info);
+}
+
+type_init(goldfish_tty_register_types)
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 7ba38dbd96..da5bb8b762 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -39,3 +39,5 @@ specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))
specific_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-serial-bus.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c'))
+
+specific_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 81026f6612..76d52938ea 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -20,6 +20,16 @@ virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, i
virtio_console_chr_read(unsigned int port, int size) "port %u, size %d"
virtio_console_chr_event(unsigned int port, int event) "port %u, event %d"
+# goldfish_tty.c
+goldfish_tty_read(void *dev, unsigned int addr, unsigned int size, uint64_t value) "tty: %p reg: 0x%02x size: %d value: 0x%"PRIx64
+goldfish_tty_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) "tty: %p reg: 0x%02x size: %d value: 0x%"PRIx64
+goldfish_tty_can_receive(void *dev, unsigned int available) "tty: %p available: %u"
+goldfish_tty_receive(void *dev, unsigned int size) "tty: %p size: %u"
+goldfish_tty_reset(void *dev) "tty: %p"
+goldfish_tty_realize(void *dev) "tty: %p"
+goldfish_tty_unrealize(void *dev) "tty: %p"
+goldfish_tty_instance_init(void *dev) "tty: %p"
+
# grlib_apbuart.c
grlib_apbuart_event(int event) "event:%d"
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 4386f57b5c..257a664ea2 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -39,6 +39,8 @@
GlobalProperty hw_compat_5_2[] = {
{ "ICH9-LPC", "smm-compat", "on"},
{ "PIIX4_PM", "smm-compat", "on"},
+ { "virtio-blk-device", "report-discard-granularity", "off" },
+ { "virtio-net-pci", "vectors", "3"},
};
const size_t hw_compat_5_2_len = G_N_ELEMENTS(hw_compat_5_2);
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 66bf0b90b4..f4694088a4 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -67,3 +67,9 @@ config SIFIVE_CLINT
config SIFIVE_PLIC
bool
+
+config GOLDFISH_PIC
+ bool
+
+config M68K_IRQC
+ bool
diff --git a/hw/intc/goldfish_pic.c b/hw/intc/goldfish_pic.c
new file mode 100644
index 0000000000..e3b43a69f1
--- /dev/null
+++ b/hw/intc/goldfish_pic.c
@@ -0,0 +1,219 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * Goldfish PIC
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "monitor/monitor.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/intc/intc.h"
+#include "hw/intc/goldfish_pic.h"
+
+/* registers */
+
+enum {
+ REG_STATUS = 0x00,
+ REG_IRQ_PENDING = 0x04,
+ REG_IRQ_DISABLE_ALL = 0x08,
+ REG_DISABLE = 0x0c,
+ REG_ENABLE = 0x10,
+};
+
+static bool goldfish_pic_get_statistics(InterruptStatsProvider *obj,
+ uint64_t **irq_counts,
+ unsigned int *nb_irqs)
+{
+ GoldfishPICState *s = GOLDFISH_PIC(obj);
+
+ *irq_counts = s->stats_irq_count;
+ *nb_irqs = ARRAY_SIZE(s->stats_irq_count);
+ return true;
+}
+
+static void goldfish_pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
+{
+ GoldfishPICState *s = GOLDFISH_PIC(obj);
+ monitor_printf(mon, "goldfish-pic.%d: pending=0x%08x enabled=0x%08x\n",
+ s->idx, s->pending, s->enabled);
+}
+
+static void goldfish_pic_update(GoldfishPICState *s)
+{
+ if (s->pending & s->enabled) {
+ qemu_irq_raise(s->irq);
+ } else {
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static void goldfish_irq_request(void *opaque, int irq, int level)
+{
+ GoldfishPICState *s = opaque;
+
+ trace_goldfish_irq_request(s, s->idx, irq, level);
+
+ if (level) {
+ s->pending |= 1 << irq;
+ s->stats_irq_count[irq]++;
+ } else {
+ s->pending &= ~(1 << irq);
+ }
+ goldfish_pic_update(s);
+}
+
+static uint64_t goldfish_pic_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ GoldfishPICState *s = opaque;
+ uint64_t value = 0;
+
+ switch (addr) {
+ case REG_STATUS:
+ /* The number of pending interrupts (0 to 32) */
+ value = ctpop32(s->pending & s->enabled);
+ break;
+ case REG_IRQ_PENDING:
+ /* The pending interrupt mask */
+ value = s->pending & s->enabled;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
+ __func__, addr);
+ break;
+ }
+
+ trace_goldfish_pic_read(s, s->idx, addr, size, value);
+
+ return value;
+}
+
+static void goldfish_pic_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ GoldfishPICState *s = opaque;
+
+ trace_goldfish_pic_write(s, s->idx, addr, size, value);
+
+ switch (addr) {
+ case REG_IRQ_DISABLE_ALL:
+ s->enabled = 0;
+ s->pending = 0;
+ break;
+ case REG_DISABLE:
+ s->enabled &= ~value;
+ break;
+ case REG_ENABLE:
+ s->enabled |= value;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
+ __func__, addr);
+ break;
+ }
+ goldfish_pic_update(s);
+}
+
+static const MemoryRegionOps goldfish_pic_ops = {
+ .read = goldfish_pic_read,
+ .write = goldfish_pic_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void goldfish_pic_reset(DeviceState *dev)
+{
+ GoldfishPICState *s = GOLDFISH_PIC(dev);
+ int i;
+
+ trace_goldfish_pic_reset(s, s->idx);
+ s->pending = 0;
+ s->enabled = 0;
+
+ for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) {
+ s->stats_irq_count[i] = 0;
+ }
+}
+
+static void goldfish_pic_realize(DeviceState *dev, Error **errp)
+{
+ GoldfishPICState *s = GOLDFISH_PIC(dev);
+
+ trace_goldfish_pic_realize(s, s->idx);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_pic_ops, s,
+ "goldfish_pic", 0x24);
+}
+
+static const VMStateDescription vmstate_goldfish_pic = {
+ .name = "goldfish_pic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(pending, GoldfishPICState),
+ VMSTATE_UINT32(enabled, GoldfishPICState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void goldfish_pic_instance_init(Object *obj)
+{
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+ GoldfishPICState *s = GOLDFISH_PIC(obj);
+
+ trace_goldfish_pic_instance_init(s);
+
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+
+ qdev_init_gpio_in(DEVICE(obj), goldfish_irq_request, GOLDFISH_PIC_IRQ_NB);
+}
+
+static Property goldfish_pic_properties[] = {
+ DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void goldfish_pic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
+
+ dc->reset = goldfish_pic_reset;
+ dc->realize = goldfish_pic_realize;
+ dc->vmsd = &vmstate_goldfish_pic;
+ ic->get_statistics = goldfish_pic_get_statistics;
+ ic->print_info = goldfish_pic_print_info;
+ device_class_set_props(dc, goldfish_pic_properties);
+}
+
+static const TypeInfo goldfish_pic_info = {
+ .name = TYPE_GOLDFISH_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = goldfish_pic_class_init,
+ .instance_init = goldfish_pic_instance_init,
+ .instance_size = sizeof(GoldfishPICState),
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_INTERRUPT_STATS_PROVIDER },
+ { }
+ },
+};
+
+static void goldfish_pic_register_types(void)
+{
+ type_register_static(&goldfish_pic_info);
+}
+
+type_init(goldfish_pic_register_types)
diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c
new file mode 100644
index 0000000000..2133d2a698
--- /dev/null
+++ b/hw/intc/m68k_irqc.c
@@ -0,0 +1,119 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * QEMU Motorola 680x0 IRQ Controller
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "migration/vmstate.h"
+#include "monitor/monitor.h"
+#include "hw/nmi.h"
+#include "hw/intc/intc.h"
+#include "hw/intc/m68k_irqc.h"
+
+
+static bool m68k_irqc_get_statistics(InterruptStatsProvider *obj,
+ uint64_t **irq_counts, unsigned int *nb_irqs)
+{
+ M68KIRQCState *s = M68K_IRQC(obj);
+
+ *irq_counts = s->stats_irq_count;
+ *nb_irqs = ARRAY_SIZE(s->stats_irq_count);
+ return true;
+}
+
+static void m68k_irqc_print_info(InterruptStatsProvider *obj, Monitor *mon)
+{
+ M68KIRQCState *s = M68K_IRQC(obj);
+ monitor_printf(mon, "m68k-irqc: ipr=0x%x\n", s->ipr);
+}
+
+static void m68k_set_irq(void *opaque, int irq, int level)
+{
+ M68KIRQCState *s = opaque;
+ M68kCPU *cpu = M68K_CPU(first_cpu);
+ int i;
+
+ if (level) {
+ s->ipr |= 1 << irq;
+ s->stats_irq_count[irq]++;
+ } else {
+ s->ipr &= ~(1 << irq);
+ }
+
+ for (i = M68K_IRQC_LEVEL_7; i >= M68K_IRQC_LEVEL_1; i--) {
+ if ((s->ipr >> i) & 1) {
+ m68k_set_irq_level(cpu, i + 1, i + M68K_IRQC_AUTOVECTOR_BASE);
+ return;
+ }
+ }
+ m68k_set_irq_level(cpu, 0, 0);
+}
+
+static void m68k_irqc_reset(DeviceState *d)
+{
+ M68KIRQCState *s = M68K_IRQC(d);
+ int i;
+
+ s->ipr = 0;
+ for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) {
+ s->stats_irq_count[i] = 0;
+ }
+}
+
+static void m68k_irqc_instance_init(Object *obj)
+{
+ qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM);
+}
+
+static void m68k_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+ m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1);
+}
+
+static const VMStateDescription vmstate_m68k_irqc = {
+ .name = "m68k-irqc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(ipr, M68KIRQCState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void m68k_irqc_class_init(ObjectClass *oc, void *data)
+ {
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ NMIClass *nc = NMI_CLASS(oc);
+ InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
+
+ nc->nmi_monitor_handler = m68k_nmi;
+ dc->reset = m68k_irqc_reset;
+ dc->vmsd = &vmstate_m68k_irqc;
+ ic->get_statistics = m68k_irqc_get_statistics;
+ ic->print_info = m68k_irqc_print_info;
+}
+
+static const TypeInfo m68k_irqc_type_info = {
+ .name = TYPE_M68K_IRQC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(M68KIRQCState),
+ .instance_init = m68k_irqc_instance_init,
+ .class_init = m68k_irqc_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_NMI },
+ { TYPE_INTERRUPT_STATS_PROVIDER },
+ { }
+ },
+};
+
+static void q800_irq_register_types(void)
+{
+ type_register_static(&m68k_irqc_type_info);
+}
+
+type_init(q800_irq_register_types);
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 8df3656419..1c299039f6 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -57,3 +57,5 @@ specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('xics_spapr.c', 'spapr_xi
specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c'))
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
if_true: files('spapr_xive_kvm.c'))
+specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
+specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 45ddaf48df..c9ab17234b 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -239,3 +239,11 @@ xive_end_source_read(uint8_t end_blk, uint32_t end_idx, uint64_t addr) "END 0x%x
# pnv_xive.c
pnv_xive_ic_hw_trigger(uint64_t addr, uint64_t val) "@0x%"PRIx64" val=0x%"PRIx64
+
+# goldfish_pic.c
+goldfish_irq_request(void *dev, int idx, int irq, int level) "pic: %p goldfish-irq.%d irq: %d level: %d"
+goldfish_pic_read(void *dev, int idx, unsigned int addr, unsigned int size, uint64_t value) "pic: %p goldfish-irq.%d reg: 0x%02x size: %d value: 0x%"PRIx64
+goldfish_pic_write(void *dev, int idx, unsigned int addr, unsigned int size, uint64_t value) "pic: %p goldfish-irq.%d reg: 0x%02x size: %d value: 0x%"PRIx64
+goldfish_pic_reset(void *dev, int idx) "pic: %p goldfish-irq.%d"
+goldfish_pic_realize(void *dev, int idx) "pic: %p goldfish-irq.%d"
+goldfish_pic_instance_init(void *dev) "pic: %p goldfish-irq"
diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig
index c7f07854f7..2691eae2f0 100644
--- a/hw/isa/Kconfig
+++ b/hw/isa/Kconfig
@@ -47,6 +47,7 @@ config VT82C686
select ACPI_SMBUS
select SERIAL_ISA
select FDC
+ select USB_UHCI
config SMC37C669
bool
diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
index 60d7bcfb8f..f839f8a030 100644
--- a/hw/m68k/Kconfig
+++ b/hw/m68k/Kconfig
@@ -23,3 +23,12 @@ config Q800
select ESP
select DP8393X
select OR_IRQ
+
+config M68K_VIRT
+ bool
+ select M68K_IRQC
+ select VIRT_CTRL
+ select GOLDFISH_PIC
+ select GOLDFISH_TTY
+ select GOLDFISH_RTC
+ select VIRTIO_MMIO
diff --git a/hw/m68k/meson.build b/hw/m68k/meson.build
index ca0044c652..31248641d3 100644
--- a/hw/m68k/meson.build
+++ b/hw/m68k/meson.build
@@ -3,5 +3,6 @@ m68k_ss.add(when: 'CONFIG_AN5206', if_true: files('an5206.c', 'mcf5206.c'))
m68k_ss.add(when: 'CONFIG_MCF5208', if_true: files('mcf5208.c', 'mcf_intc.c'))
m68k_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-kbd.c', 'next-cube.c'))
m68k_ss.add(when: 'CONFIG_Q800', if_true: files('q800.c'))
+m68k_ss.add(when: 'CONFIG_M68K_VIRT', if_true: files('virt.c'))
hw_arch += {'m68k': m68k_ss}
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
new file mode 100644
index 0000000000..e9a5d4c69b
--- /dev/null
+++ b/hw/m68k/virt.c
@@ -0,0 +1,313 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * QEMU Vitual M68K Machine
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "elf.h"
+#include "hw/loader.h"
+#include "ui/console.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"
+#include "standard-headers/asm-m68k/bootinfo.h"
+#include "standard-headers/asm-m68k/bootinfo-virt.h"
+#include "bootinfo.h"
+#include "net/net.h"
+#include "qapi/error.h"
+#include "sysemu/qtest.h"
+#include "sysemu/runstate.h"
+#include "sysemu/reset.h"
+
+#include "hw/intc/m68k_irqc.h"
+#include "hw/misc/virt_ctrl.h"
+#include "hw/char/goldfish_tty.h"
+#include "hw/rtc/goldfish_rtc.h"
+#include "hw/intc/goldfish_pic.h"
+#include "hw/virtio/virtio-mmio.h"
+#include "hw/virtio/virtio-blk.h"
+
+/*
+ * 6 goldfish-pic for CPU IRQ #1 to IRQ #6
+ * CPU IRQ #1 -> PIC #1
+ * IRQ #1 to IRQ #31 -> unused
+ * IRQ #32 -> goldfish-tty
+ * CPU IRQ #2 -> PIC #2
+ * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32
+ * CPU IRQ #3 -> PIC #3
+ * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64
+ * CPU IRQ #4 -> PIC #4
+ * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96
+ * CPU IRQ #5 -> PIC #5
+ * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128
+ * CPU IRQ #6 -> PIC #6
+ * IRQ #1 -> goldfish-rtc
+ * IRQ #2 to IRQ #32 -> unused
+ * CPU IRQ #7 -> NMI
+ */
+
+#define PIC_IRQ_BASE(num) (8 + (num - 1) * 32)
+#define PIC_IRQ(num, irq) (PIC_IRQ_BASE(num) + irq - 1)
+#define PIC_GPIO(pic_irq) (qdev_get_gpio_in(pic_dev[(pic_irq - 8) / 32], \
+ (pic_irq - 8) % 32))
+
+#define VIRT_GF_PIC_MMIO_BASE 0xff000000 /* MMIO: 0xff000000 - 0xff005fff */
+#define VIRT_GF_PIC_IRQ_BASE 1 /* IRQ: #1 -> #6 */
+#define VIRT_GF_PIC_NB 6
+
+/* 2 goldfish-rtc (and timer) */
+#define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff007fff */
+#define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */
+#define VIRT_GF_RTC_NB 2
+
+/* 1 goldfish-tty */
+#define VIRT_GF_TTY_MMIO_BASE 0xff008000 /* MMIO: 0xff008000 - 0xff008fff */
+#define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */
+
+/* 1 virt-ctrl */
+#define VIRT_CTRL_MMIO_BASE 0xff009000 /* MMIO: 0xff009000 - 0xff009fff */
+#define VIRT_CTRL_IRQ_BASE PIC_IRQ(1, 1) /* PIC: #1, IRQ: #1 */
+
+/*
+ * virtio-mmio size is 0x200 bytes
+ * we use 4 goldfish-pic to attach them,
+ * we can attach 32 virtio devices / goldfish-pic
+ * -> we can manage 32 * 4 = 128 virtio devices
+ */
+#define VIRT_VIRTIO_MMIO_BASE 0xff010000 /* MMIO: 0xff010000 - 0xff01ffff */
+#define VIRT_VIRTIO_IRQ_BASE PIC_IRQ(2, 1) /* PIC: 2, 3, 4, 5, IRQ: ALL */
+
+static void main_cpu_reset(void *opaque)
+{
+ M68kCPU *cpu = opaque;
+ CPUState *cs = CPU(cpu);
+
+ cpu_reset(cs);
+ cpu->env.aregs[7] = ldl_phys(cs->as, 0);
+ cpu->env.pc = ldl_phys(cs->as, 4);
+}
+
+static void virt_init(MachineState *machine)
+{
+ M68kCPU *cpu = NULL;
+ int32_t kernel_size;
+ uint64_t elf_entry;
+ ram_addr_t initrd_base;
+ int32_t initrd_size;
+ ram_addr_t ram_size = machine->ram_size;
+ const char *kernel_filename = machine->kernel_filename;
+ const char *initrd_filename = machine->initrd_filename;
+ const char *kernel_cmdline = machine->kernel_cmdline;
+ hwaddr parameters_base;
+ DeviceState *dev;
+ DeviceState *irqc_dev;
+ DeviceState *pic_dev[VIRT_GF_PIC_NB];
+ SysBusDevice *sysbus;
+ hwaddr io_base;
+ int i;
+
+ if (ram_size > 3399672 * KiB) {
+ /*
+ * The physical memory can be up to 4 GiB - 16 MiB, but linux
+ * kernel crashes after this limit (~ 3.2 GiB)
+ */
+ error_report("Too much memory for this machine: %" PRId64 " KiB, "
+ "maximum 3399672 KiB", ram_size / KiB);
+ exit(1);
+ }
+
+ /* init CPUs */
+ cpu = M68K_CPU(cpu_create(machine->cpu_type));
+ qemu_register_reset(main_cpu_reset, cpu);
+
+ /* RAM */
+ memory_region_add_subregion(get_system_memory(), 0, machine->ram);
+
+ /* IRQ Controller */
+
+ irqc_dev = qdev_new(TYPE_M68K_IRQC);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(irqc_dev), &error_fatal);
+
+ /*
+ * 6 goldfish-pic
+ *
+ * map: 0xff000000 - 0xff006fff = 28 KiB
+ * IRQ: #1 (lower priority) -> #6 (higher priority)
+ *
+ */
+ io_base = VIRT_GF_PIC_MMIO_BASE;
+ for (i = 0; i < VIRT_GF_PIC_NB; i++) {
+ pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC);
+ sysbus = SYS_BUS_DEVICE(pic_dev[i]);
+ qdev_prop_set_uint8(pic_dev[i], "index", i);
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+
+ sysbus_mmio_map(sysbus, 0, io_base);
+ sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(irqc_dev, i));
+
+ io_base += 0x1000;
+ }
+
+ /* goldfish-rtc */
+ io_base = VIRT_GF_RTC_MMIO_BASE;
+ for (i = 0; i < VIRT_GF_RTC_NB; i++) {
+ dev = qdev_new(TYPE_GOLDFISH_RTC);
+ sysbus = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+ sysbus_mmio_map(sysbus, 0, io_base);
+ sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE + i));
+
+ io_base += 0x1000;
+ }
+
+ /* goldfish-tty */
+ dev = qdev_new(TYPE_GOLDFISH_TTY);
+ sysbus = SYS_BUS_DEVICE(dev);
+ qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+ sysbus_mmio_map(sysbus, 0, VIRT_GF_TTY_MMIO_BASE);
+ sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_TTY_IRQ_BASE));
+
+ /* virt controller */
+ dev = qdev_new(TYPE_VIRT_CTRL);
+ sysbus = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+ sysbus_mmio_map(sysbus, 0, VIRT_CTRL_MMIO_BASE);
+ sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_CTRL_IRQ_BASE));
+
+ /* virtio-mmio */
+ io_base = VIRT_VIRTIO_MMIO_BASE;
+ for (i = 0; i < 128; i++) {
+ dev = qdev_new(TYPE_VIRTIO_MMIO);
+ qdev_prop_set_bit(dev, "force-legacy", false);
+ sysbus = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+ sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_VIRTIO_IRQ_BASE + i));
+ sysbus_mmio_map(sysbus, 0, io_base);
+ io_base += 0x200;
+ }
+
+ if (kernel_filename) {
+ CPUState *cs = CPU(cpu);
+ uint64_t high;
+
+ kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
+ &elf_entry, NULL, &high, NULL, 1,
+ EM_68K, 0, 0);
+ if (kernel_size < 0) {
+ error_report("could not load kernel '%s'", kernel_filename);
+ exit(1);
+ }
+ stl_phys(cs->as, 4, elf_entry); /* reset initial PC */
+ parameters_base = (high + 1) & ~1;
+
+ BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_VIRT);
+ BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, FPU_68040);
+ BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, MMU_68040);
+ BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, CPU_68040);
+ BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size);
+
+ BOOTINFO1(cs->as, parameters_base, BI_VIRT_QEMU_VERSION,
+ ((QEMU_VERSION_MAJOR << 24) | (QEMU_VERSION_MINOR << 16) |
+ (QEMU_VERSION_MICRO << 8)));
+ BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_PIC_BASE,
+ VIRT_GF_PIC_MMIO_BASE, VIRT_GF_PIC_IRQ_BASE);
+ BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_RTC_BASE,
+ VIRT_GF_RTC_MMIO_BASE, VIRT_GF_RTC_IRQ_BASE);
+ BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_TTY_BASE,
+ VIRT_GF_TTY_MMIO_BASE, VIRT_GF_TTY_IRQ_BASE);
+ BOOTINFO2(cs->as, parameters_base, BI_VIRT_CTRL_BASE,
+ VIRT_CTRL_MMIO_BASE, VIRT_CTRL_IRQ_BASE);
+ BOOTINFO2(cs->as, parameters_base, BI_VIRT_VIRTIO_BASE,
+ VIRT_VIRTIO_MMIO_BASE, VIRT_VIRTIO_IRQ_BASE);
+
+ if (kernel_cmdline) {
+ BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE,
+ kernel_cmdline);
+ }
+
+ /* load initrd */
+ if (initrd_filename) {
+ initrd_size = get_image_size(initrd_filename);
+ if (initrd_size < 0) {
+ error_report("could not load initial ram disk '%s'",
+ initrd_filename);
+ exit(1);
+ }
+
+ initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
+ load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
+ BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base,
+ initrd_size);
+ } else {
+ initrd_base = 0;
+ initrd_size = 0;
+ }
+ BOOTINFO0(cs->as, parameters_base, BI_LAST);
+ }
+}
+
+static void virt_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ mc->desc = "QEMU M68K Virtual Machine";
+ mc->init = virt_init;
+ mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
+ mc->max_cpus = 1;
+ mc->no_floppy = 1;
+ mc->no_parallel = 1;
+ mc->default_ram_id = "m68k_virt.ram";
+}
+
+static const TypeInfo virt_machine_info = {
+ .name = MACHINE_TYPE_NAME("virt"),
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .class_init = virt_machine_class_init,
+};
+
+static void virt_machine_register_types(void)
+{
+ type_register_static(&virt_machine_info);
+}
+
+type_init(virt_machine_register_types)
+
+#define DEFINE_VIRT_MACHINE(major, minor, latest) \
+ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+ void *data) \
+ { \
+ MachineClass *mc = MACHINE_CLASS(oc); \
+ virt_machine_##major##_##minor##_options(mc); \
+ mc->desc = "QEMU " # major "." # minor " M68K Virtual Machine"; \
+ if (latest) { \
+ mc->alias = "virt"; \
+ } \
+ } \
+ static const TypeInfo machvirt_##major##_##minor##_info = { \
+ .name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+ .parent = MACHINE_TYPE_NAME("virt"), \
+ .class_init = virt_##major##_##minor##_class_init, \
+ }; \
+ static void machvirt_machine_##major##_##minor##_init(void) \
+ { \
+ type_register_static(&machvirt_##major##_##minor##_info); \
+ } \
+ type_init(machvirt_machine_##major##_##minor##_init);
+
+static void virt_machine_6_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE(6, 0, true)
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
index 588e6f9930..43349d6837 100644
--- a/hw/mips/gt64xxx_pci.c
+++ b/hw/mips/gt64xxx_pci.c
@@ -385,13 +385,13 @@ static void gt64120_writel(void *opaque, hwaddr addr,
{
GT64120State *s = opaque;
PCIHostState *phb = PCI_HOST_BRIDGE(s);
- uint32_t saddr;
+ uint32_t saddr = addr >> 2;
+ trace_gt64120_write(addr, val);
if (!(s->regs[GT_CPU] & 0x00001000)) {
val = bswap32(val);
}
- saddr = (addr & 0xfff) >> 2;
switch (saddr) {
/* CPU Configuration */
@@ -464,7 +464,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* Read-only registers, do nothing */
qemu_log_mask(LOG_GUEST_ERROR,
"gt64120: Read-only register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
@@ -474,7 +474,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* Read-only registers, do nothing */
qemu_log_mask(LOG_GUEST_ERROR,
"gt64120: Read-only register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
@@ -516,7 +516,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* Not implemented */
qemu_log_mask(LOG_UNIMP,
"gt64120: Unimplemented device register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
@@ -529,7 +529,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* Read-only registers, do nothing */
qemu_log_mask(LOG_GUEST_ERROR,
"gt64120: Read-only register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
@@ -566,7 +566,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* Not implemented */
qemu_log_mask(LOG_UNIMP,
"gt64120: Unimplemented DMA register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
@@ -579,7 +579,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* Not implemented */
qemu_log_mask(LOG_UNIMP,
"gt64120: Unimplemented timer register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
@@ -622,8 +622,8 @@ static void gt64120_writel(void *opaque, hwaddr addr,
case GT_PCI1_CFGDATA:
/* not implemented */
qemu_log_mask(LOG_UNIMP,
- "gt64120: Unimplemented timer register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "gt64120: Unimplemented PCI register write "
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
case GT_PCI0_CFGADDR:
@@ -643,19 +643,19 @@ static void gt64120_writel(void *opaque, hwaddr addr,
/* not really implemented */
s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
- trace_gt64120_write("INTRCAUSE", size, val);
+ trace_gt64120_write_intreg("INTRCAUSE", size, val);
break;
case GT_INTRMASK:
s->regs[saddr] = val & 0x3c3ffffe;
- trace_gt64120_write("INTRMASK", size, val);
+ trace_gt64120_write_intreg("INTRMASK", size, val);
break;
case GT_PCI0_ICMASK:
s->regs[saddr] = val & 0x03fffffe;
- trace_gt64120_write("ICMASK", size, val);
+ trace_gt64120_write_intreg("ICMASK", size, val);
break;
case GT_PCI0_SERR0MASK:
s->regs[saddr] = val & 0x0000003f;
- trace_gt64120_write("SERR0MASK", size, val);
+ trace_gt64120_write_intreg("SERR0MASK", size, val);
break;
/* Reserved when only PCI_0 is configured. */
@@ -683,7 +683,7 @@ static void gt64120_writel(void *opaque, hwaddr addr,
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gt64120: Illegal register write "
- "reg:0x03%x size:%u value:0x%0*" PRIx64 "\n",
+ "reg:0x%03x size:%u value:0x%0*" PRIx64 "\n",
saddr << 2, size, size << 1, val);
break;
}
@@ -695,9 +695,8 @@ static uint64_t gt64120_readl(void *opaque,
GT64120State *s = opaque;
PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t val;
- uint32_t saddr;
+ uint32_t saddr = addr >> 2;
- saddr = (addr & 0xfff) >> 2;
switch (saddr) {
/* CPU Configuration */
@@ -931,19 +930,19 @@ static uint64_t gt64120_readl(void *opaque,
/* Interrupts */
case GT_INTRCAUSE:
val = s->regs[saddr];
- trace_gt64120_read("INTRCAUSE", size, val);
+ trace_gt64120_read_intreg("INTRCAUSE", size, val);
break;
case GT_INTRMASK:
val = s->regs[saddr];
- trace_gt64120_read("INTRMASK", size, val);
+ trace_gt64120_read_intreg("INTRMASK", size, val);
break;
case GT_PCI0_ICMASK:
val = s->regs[saddr];
- trace_gt64120_read("ICMASK", size, val);
+ trace_gt64120_read_intreg("ICMASK", size, val);
break;
case GT_PCI0_SERR0MASK:
val = s->regs[saddr];
- trace_gt64120_read("SERR0MASK", size, val);
+ trace_gt64120_read_intreg("SERR0MASK", size, val);
break;
/* Reserved when only PCI_0 is configured. */
@@ -960,7 +959,7 @@ static uint64_t gt64120_readl(void *opaque,
val = s->regs[saddr];
qemu_log_mask(LOG_GUEST_ERROR,
"gt64120: Illegal register read "
- "reg:0x03%x size:%u value:0x%0*x\n",
+ "reg:0x%03x size:%u value:0x%0*x\n",
saddr << 2, size, size << 1, val);
break;
}
@@ -968,6 +967,7 @@ static uint64_t gt64120_readl(void *opaque,
if (!(s->regs[GT_CPU] & 0x00001000)) {
val = bswap32(val);
}
+ trace_gt64120_read(addr, val);
return val;
}
@@ -976,6 +976,10 @@ static const MemoryRegionOps isd_mem_ops = {
.read = gt64120_readl,
.write = gt64120_writel,
.endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
};
static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -1196,6 +1200,14 @@ static void gt64120_reset(DeviceState *dev)
gt64120_pci_mapping(s);
}
+static void gt64120_realize(DeviceState *dev, Error **errp)
+{
+ GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
+
+ memory_region_init_io(&s->ISD_mem, OBJECT(dev), &isd_mem_ops, s,
+ "gt64120-isd", 0x1000);
+}
+
PCIBus *gt64120_register(qemu_irq *pic)
{
GT64120State *d;
@@ -1214,8 +1226,6 @@ PCIBus *gt64120_register(qemu_irq *pic)
get_system_io(),
PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- memory_region_init_io(&d->ISD_mem, OBJECT(dev), &isd_mem_ops, d,
- "isd-mem", 0x1000);
pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
return phb->bus;
@@ -1270,6 +1280,7 @@ static void gt64120_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->realize = gt64120_realize;
dc->reset = gt64120_reset;
dc->vmsd = &vmstate_gt64120;
}
diff --git a/hw/mips/trace-events b/hw/mips/trace-events
index 915139d981..13ee731a48 100644
--- a/hw/mips/trace-events
+++ b/hw/mips/trace-events
@@ -1,4 +1,6 @@
# gt64xxx_pci.c
-gt64120_read(const char *regname, unsigned size, uint64_t value) "gt64120 read %s size:%u value:0x%08" PRIx64
-gt64120_write(const char *regname, unsigned size, uint64_t value) "gt64120 write %s size:%u value:0x%08" PRIx64
+gt64120_read(uint64_t addr, uint64_t value) "gt64120 read 0x%03"PRIx64" value:0x%08" PRIx64
+gt64120_write(uint64_t addr, uint64_t value) "gt64120 write 0x%03"PRIx64" value:0x%08" PRIx64
+gt64120_read_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 read %s size:%u value:0x%08" PRIx64
+gt64120_write_intreg(const char *regname, unsigned size, uint64_t value) "gt64120 write %s size:%u value:0x%08" PRIx64
gt64120_isd_remap(uint64_t from_length, uint64_t from_addr, uint64_t to_length, uint64_t to_addr) "ISD: 0x%08" PRIx64 "@0x%08" PRIx64 " -> 0x%08" PRIx64 "@0x%08" PRIx64
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 5426b9b1a1..c71ed25820 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -183,4 +183,7 @@ config SIFIVE_U_OTP
config SIFIVE_U_PRCI
bool
+config VIRT_CTRL
+ bool
+
source macio/Kconfig
diff --git a/hw/misc/led.c b/hw/misc/led.c
index 5266d026d0..f552b8b648 100644
--- a/hw/misc/led.c
+++ b/hw/misc/led.c
@@ -20,6 +20,7 @@ static const char * const led_color_name[] = {
[LED_COLOR_BLUE] = "blue",
[LED_COLOR_CYAN] = "cyan",
[LED_COLOR_GREEN] = "green",
+ [LED_COLOR_YELLOW] = "yellow",
[LED_COLOR_AMBER] = "amber",
[LED_COLOR_ORANGE] = "orange",
[LED_COLOR_RED] = "red",
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 7a2b0d031a..21034dc60a 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -24,6 +24,9 @@ softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
# Mac devices
softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c'))
+# virt devices
+softmmu_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c'))
+
# RISC-V devices
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c'))
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c'))
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index b87d0b4c90..3d44978cca 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -255,3 +255,10 @@ pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, u
bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
+
+# virt_ctrl.c
+virt_ctrl_read(void *dev, unsigned int addr, unsigned int size, uint64_t value) "ctrl: %p reg: 0x%02x size: %d value: 0x%"PRIx64
+virt_ctrl_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) "ctrl: %p reg: 0x%02x size: %d value: 0x%"PRIx64
+virt_ctrl_reset(void *dev) "ctrl: %p"
+virt_ctrl_realize(void *dev) "ctrl: %p"
+virt_ctrl_instance_init(void *dev) "ctrl: %p"
diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c
new file mode 100644
index 0000000000..2ea01bd7a1
--- /dev/null
+++ b/hw/misc/virt_ctrl.c
@@ -0,0 +1,151 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * Virt system Controller
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "sysemu/runstate.h"
+#include "hw/misc/virt_ctrl.h"
+
+enum {
+ REG_FEATURES = 0x00,
+ REG_CMD = 0x04,
+};
+
+#define FEAT_POWER_CTRL 0x00000001
+
+enum {
+ CMD_NOOP,
+ CMD_RESET,
+ CMD_HALT,
+ CMD_PANIC,
+};
+
+static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size)
+{
+ VirtCtrlState *s = opaque;
+ uint64_t value = 0;
+
+ switch (addr) {
+ case REG_FEATURES:
+ value = FEAT_POWER_CTRL;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
+ __func__, addr);
+ break;
+ }
+
+ trace_virt_ctrl_write(s, addr, size, value);
+
+ return value;
+}
+
+static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ VirtCtrlState *s = opaque;
+
+ trace_virt_ctrl_write(s, addr, size, value);
+
+ switch (addr) {
+ case REG_CMD:
+ switch (value) {
+ case CMD_NOOP:
+ break;
+ case CMD_RESET:
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ break;
+ case CMD_HALT:
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+ break;
+ case CMD_PANIC:
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC);
+ break;
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
+ __func__, addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps virt_ctrl_ops = {
+ .read = virt_ctrl_read,
+ .write = virt_ctrl_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.max_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void virt_ctrl_reset(DeviceState *dev)
+{
+ VirtCtrlState *s = VIRT_CTRL(dev);
+
+ trace_virt_ctrl_reset(s);
+}
+
+static void virt_ctrl_realize(DeviceState *dev, Error **errp)
+{
+ VirtCtrlState *s = VIRT_CTRL(dev);
+
+ trace_virt_ctrl_instance_init(s);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &virt_ctrl_ops, s,
+ "virt-ctrl", 0x100);
+}
+
+static const VMStateDescription vmstate_virt_ctrl = {
+ .name = "virt-ctrl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_enabled, VirtCtrlState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void virt_ctrl_instance_init(Object *obj)
+{
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+ VirtCtrlState *s = VIRT_CTRL(obj);
+
+ trace_virt_ctrl_instance_init(s);
+
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+}
+
+static void virt_ctrl_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->reset = virt_ctrl_reset;
+ dc->realize = virt_ctrl_realize;
+ dc->vmsd = &vmstate_virt_ctrl;
+}
+
+static const TypeInfo virt_ctrl_info = {
+ .name = TYPE_VIRT_CTRL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = virt_ctrl_class_init,
+ .instance_init = virt_ctrl_instance_init,
+ .instance_size = sizeof(VirtCtrlState),
+};
+
+static void virt_ctrl_register_types(void)
+{
+ type_register_static(&virt_ctrl_info);
+}
+
+type_init(virt_ctrl_register_types)
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 9a4474a084..24b3a0ff66 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -1275,8 +1275,8 @@ static void gem_transmit(CadenceGEMState *s)
/* Send the packet somewhere */
if (s->phy_loop || (s->regs[GEM_NWCTRL] &
GEM_NWCTRL_LOCALLOOP)) {
- gem_receive(qemu_get_queue(s->nic), s->tx_packet,
- total_bytes);
+ qemu_receive_packet(qemu_get_queue(s->nic), s->tx_packet,
+ total_bytes);
} else {
qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet,
total_bytes);
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 205c0decc5..533a8304d0 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -506,7 +506,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
if (nc->info->can_receive(nc)) {
s->loopback_packet = 1;
- nc->info->receive(nc, s->tx_buffer, tx_len);
+ qemu_receive_packet(nc, s->tx_buffer, tx_len);
}
} else {
/* Transmit packet */
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index d8da2f6528..4f75b44cfc 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -546,7 +546,7 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
NetClientState *nc = qemu_get_queue(s->nic);
if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
- nc->info->receive(nc, buf, size);
+ qemu_receive_packet(nc, buf, size);
} else {
qemu_send_packet(nc, buf, size);
}
@@ -670,6 +670,9 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
msh = tp->tso_props.hdr_len + tp->tso_props.mss;
do {
bytes = split_size;
+ if (tp->size >= msh) {
+ goto eop;
+ }
if (tp->size + bytes > msh)
bytes = msh - tp->size;
@@ -695,6 +698,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
tp->size += split_size;
}
+eop:
if (!(txd_lower & E1000_TXD_CMD_EOP))
return;
if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) {
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index abc796285a..6aff424cbe 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -680,7 +680,7 @@ static void do_tx_packet(lan9118_state *s)
/* FIXME: Honor TX disable, and allow queueing of packets. */
if (s->phy_control & 0x4000) {
/* This assumes the receive routine doesn't touch the VLANClient. */
- lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
+ qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
} else {
qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
}
diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c
index 32ba9e8412..3e6206044f 100644
--- a/hw/net/msf2-emac.c
+++ b/hw/net/msf2-emac.c
@@ -158,7 +158,7 @@ static void msf2_dma_tx(MSF2EmacState *s)
* R_CFG1 bit 0 is set.
*/
if (s->regs[R_CFG1] & R_CFG1_LB_EN_MASK) {
- nc->info->receive(nc, buf, size);
+ qemu_receive_packet(nc, buf, size);
} else {
qemu_send_packet(nc, buf, size);
}
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index da262edc3e..1f9aa59eca 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -553,7 +553,7 @@ static inline void net_tx_pkt_sendv(struct NetTxPkt *pkt,
NetClientState *nc, const struct iovec *iov, int iov_cnt)
{
if (pkt->is_loopback) {
- nc->info->receive_iov(nc, iov, iov_cnt);
+ qemu_receive_packet_iov(nc, iov, iov_cnt);
} else {
qemu_sendv_packet(nc, iov, iov_cnt);
}
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index f3f18d8598..dcd3fc4948 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -1250,7 +1250,7 @@ txagain:
if (BCR_SWSTYLE(s) == 1)
add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
- pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos);
+ qemu_receive_packet(qemu_get_queue(s->nic), s->buffer, s->xmit_pos);
s->looptest = 0;
} else {
if (s->nic) {
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 4675ac878e..90b4fc63ce 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -1795,7 +1795,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
}
DPRINTF("+++ transmit loopback mode\n");
- rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt);
+ qemu_receive_packet(qemu_get_queue(s->nic), buf, size);
if (iov) {
g_free(buf2);
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
index 33c3722df6..3684a4d733 100644
--- a/hw/net/sungem.c
+++ b/hw/net/sungem.c
@@ -306,7 +306,7 @@ static void sungem_send_packet(SunGEMState *s, const uint8_t *buf,
NetClientState *nc = qemu_get_queue(s->nic);
if (s->macregs[MAC_XIFCFG >> 2] & MAC_XIFCFG_LBCK) {
- nc->info->receive(nc, buf, size);
+ qemu_receive_packet(nc, buf, size);
} else {
qemu_send_packet(nc, buf, size);
}
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 5c815b4f0c..8431808ea0 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -296,9 +296,8 @@ static int net_init(struct XenLegacyDevice *xendev)
netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
"xen", NULL, netdev);
- snprintf(qemu_get_queue(netdev->nic)->info_str,
- sizeof(qemu_get_queue(netdev->nic)->info_str),
- "nic: xenbus vif macaddr=%s", netdev->mac);
+ qemu_get_queue(netdev->nic)->info_str = g_strdup_printf(
+ "nic: xenbus vif macaddr=%s", netdev->mac);
/* fill info */
xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
diff --git a/hw/rdma/vmw/pvrdma.h b/hw/rdma/vmw/pvrdma.h
index 1d36a76f1e..d08965d3e2 100644
--- a/hw/rdma/vmw/pvrdma.h
+++ b/hw/rdma/vmw/pvrdma.h
@@ -26,7 +26,6 @@
#include "../rdma_backend_defs.h"
#include "../rdma_rm_defs.h"
-#include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h"
#include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h"
#include "pvrdma_dev_ring.h"
#include "qom/object.h"
@@ -64,10 +63,10 @@ typedef struct DSRInfo {
union pvrdma_cmd_req *req;
union pvrdma_cmd_resp *rsp;
- struct pvrdma_ring *async_ring_state;
+ PvrdmaRingState *async_ring_state;
PvrdmaRing async;
- struct pvrdma_ring *cq_ring_state;
+ PvrdmaRingState *cq_ring_state;
PvrdmaRing cq;
} DSRInfo;
diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c
index 692125ac26..f59879e257 100644
--- a/hw/rdma/vmw/pvrdma_cmd.c
+++ b/hw/rdma/vmw/pvrdma_cmd.c
@@ -262,7 +262,7 @@ static int create_cq_ring(PCIDevice *pci_dev , PvrdmaRing **ring,
r = g_malloc(sizeof(*r));
*ring = r;
- r->ring_state = (struct pvrdma_ring *)
+ r->ring_state = (PvrdmaRingState *)
rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
if (!r->ring_state) {
@@ -398,7 +398,7 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
*rings = sr;
/* Create send ring */
- sr->ring_state = (struct pvrdma_ring *)
+ sr->ring_state = (PvrdmaRingState *)
rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
if (!sr->ring_state) {
rdma_error_report("Failed to map to QP ring state");
@@ -639,7 +639,7 @@ static int create_srq_ring(PCIDevice *pci_dev, PvrdmaRing **ring,
r = g_malloc(sizeof(*r));
*ring = r;
- r->ring_state = (struct pvrdma_ring *)
+ r->ring_state = (PvrdmaRingState *)
rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
if (!r->ring_state) {
rdma_error_report("Failed to map tp SRQ ring state");
diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c
index f0bcde74b0..074ac59b84 100644
--- a/hw/rdma/vmw/pvrdma_dev_ring.c
+++ b/hw/rdma/vmw/pvrdma_dev_ring.c
@@ -22,11 +22,10 @@
#include "trace.h"
#include "../rdma_utils.h"
-#include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h"
#include "pvrdma_dev_ring.h"
int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev,
- struct pvrdma_ring *ring_state, uint32_t max_elems,
+ PvrdmaRingState *ring_state, uint32_t max_elems,
size_t elem_sz, dma_addr_t *tbl, uint32_t npages)
{
int i;
@@ -73,48 +72,54 @@ out:
void *pvrdma_ring_next_elem_read(PvrdmaRing *ring)
{
- int e;
- unsigned int idx = 0, offset;
+ unsigned int idx, offset;
+ const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail);
+ const uint32_t head = qatomic_read(&ring->ring_state->cons_head);
- e = pvrdma_idx_ring_has_data(ring->ring_state, ring->max_elems, &idx);
- if (e <= 0) {
+ if (tail & ~((ring->max_elems << 1) - 1) ||
+ head & ~((ring->max_elems << 1) - 1) ||
+ tail == head) {
trace_pvrdma_ring_next_elem_read_no_data(ring->name);
return NULL;
}
+ idx = head & (ring->max_elems - 1);
offset = idx * ring->elem_sz;
return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE);
}
void pvrdma_ring_read_inc(PvrdmaRing *ring)
{
- pvrdma_idx_ring_inc(&ring->ring_state->cons_head, ring->max_elems);
+ uint32_t idx = qatomic_read(&ring->ring_state->cons_head);
+
+ idx = (idx + 1) & ((ring->max_elems << 1) - 1);
+ qatomic_set(&ring->ring_state->cons_head, idx);
}
void *pvrdma_ring_next_elem_write(PvrdmaRing *ring)
{
- int idx;
- unsigned int offset, tail;
+ unsigned int idx, offset;
+ const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail);
+ const uint32_t head = qatomic_read(&ring->ring_state->cons_head);
- idx = pvrdma_idx_ring_has_space(ring->ring_state, ring->max_elems, &tail);
- if (idx <= 0) {
+ if (tail & ~((ring->max_elems << 1) - 1) ||
+ head & ~((ring->max_elems << 1) - 1) ||
+ tail == (head ^ ring->max_elems)) {
rdma_error_report("CQ is full");
return NULL;
}
- idx = pvrdma_idx(&ring->ring_state->prod_tail, ring->max_elems);
- if (idx < 0 || tail != idx) {
- rdma_error_report("Invalid idx %d", idx);
- return NULL;
- }
-
+ idx = tail & (ring->max_elems - 1);
offset = idx * ring->elem_sz;
return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE);
}
void pvrdma_ring_write_inc(PvrdmaRing *ring)
{
- pvrdma_idx_ring_inc(&ring->ring_state->prod_tail, ring->max_elems);
+ uint32_t idx = qatomic_read(&ring->ring_state->prod_tail);
+
+ idx = (idx + 1) & ((ring->max_elems << 1) - 1);
+ qatomic_set(&ring->ring_state->prod_tail, idx);
}
void pvrdma_ring_free(PvrdmaRing *ring)
diff --git a/hw/rdma/vmw/pvrdma_dev_ring.h b/hw/rdma/vmw/pvrdma_dev_ring.h
index 5f2a0cf9b9..d231588ce0 100644
--- a/hw/rdma/vmw/pvrdma_dev_ring.h
+++ b/hw/rdma/vmw/pvrdma_dev_ring.h
@@ -19,18 +19,23 @@
#define MAX_RING_NAME_SZ 32
+typedef struct PvrdmaRingState {
+ int prod_tail; /* producer tail */
+ int cons_head; /* consumer head */
+} PvrdmaRingState;
+
typedef struct PvrdmaRing {
char name[MAX_RING_NAME_SZ];
PCIDevice *dev;
uint32_t max_elems;
size_t elem_sz;
- struct pvrdma_ring *ring_state; /* used only for unmap */
+ PvrdmaRingState *ring_state; /* used only for unmap */
int npages;
void **pages;
} PvrdmaRing;
int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev,
- struct pvrdma_ring *ring_state, uint32_t max_elems,
+ PvrdmaRingState *ring_state, uint32_t max_elems,
size_t elem_sz, dma_addr_t *tbl, uint32_t npages);
void *pvrdma_ring_next_elem_read(PvrdmaRing *ring);
void pvrdma_ring_read_inc(PvrdmaRing *ring);
diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c
index 8593570332..84ae8024fc 100644
--- a/hw/rdma/vmw/pvrdma_main.c
+++ b/hw/rdma/vmw/pvrdma_main.c
@@ -85,7 +85,7 @@ static void free_dev_ring(PCIDevice *pci_dev, PvrdmaRing *ring,
rdma_pci_dma_unmap(pci_dev, ring_state, TARGET_PAGE_SIZE);
}
-static int init_dev_ring(PvrdmaRing *ring, struct pvrdma_ring **ring_state,
+static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state,
const char *name, PCIDevice *pci_dev,
dma_addr_t dir_addr, uint32_t num_pages)
{
@@ -114,7 +114,7 @@ static int init_dev_ring(PvrdmaRing *ring, struct pvrdma_ring **ring_state,
/* RX ring is the second */
(*ring_state)++;
rc = pvrdma_ring_init(ring, name, pci_dev,
- (struct pvrdma_ring *)*ring_state,
+ (PvrdmaRingState *)*ring_state,
(num_pages - 1) * TARGET_PAGE_SIZE /
sizeof(struct pvrdma_cqne),
sizeof(struct pvrdma_cqne),
diff --git a/hw/tricore/Kconfig b/hw/tricore/Kconfig
index 9313409309..506e6183c1 100644
--- a/hw/tricore/Kconfig
+++ b/hw/tricore/Kconfig
@@ -1,2 +1,10 @@
config TRICORE
bool
+
+config TRIBOARD
+ bool
+ select TRICORE
+ select TC27X_SOC
+
+config TC27X_SOC
+ bool
diff --git a/hw/tricore/meson.build b/hw/tricore/meson.build
index 579aa13c78..77ff6fd137 100644
--- a/hw/tricore/meson.build
+++ b/hw/tricore/meson.build
@@ -1,4 +1,6 @@
tricore_ss = ss.source_set()
tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testboard.c'))
+tricore_ss.add(when: 'CONFIG_TRIBOARD', if_true: files('triboard.c'))
+tricore_ss.add(when: 'CONFIG_TC27X_SOC', if_true: files('tc27x_soc.c'))
hw_arch += {'tricore': tricore_ss}
diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c
new file mode 100644
index 0000000000..8af079e6b2
--- /dev/null
+++ b/hw/tricore/tc27x_soc.c
@@ -0,0 +1,246 @@
+/*
+ * Infineon tc27x SoC System emulation.
+ *
+ * Copyright (c) 2020 Andreas Konopik <andreas.konopik@efs-auto.de>
+ * Copyright (c) 2020 David Brenken <david.brenken@efs-auto.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "qemu/units.h"
+#include "hw/misc/unimp.h"
+#include "exec/address-spaces.h"
+#include "qemu/log.h"
+#include "cpu.h"
+
+#include "hw/tricore/tc27x_soc.h"
+#include "hw/tricore/triboard.h"
+
+const MemmapEntry tc27x_soc_memmap[] = {
+ [TC27XD_DSPR2] = { 0x50000000, 120 * KiB },
+ [TC27XD_DCACHE2] = { 0x5001E000, 8 * KiB },
+ [TC27XD_DTAG2] = { 0x500C0000, 0xC00 },
+ [TC27XD_PSPR2] = { 0x50100000, 32 * KiB },
+ [TC27XD_PCACHE2] = { 0x50108000, 16 * KiB },
+ [TC27XD_PTAG2] = { 0x501C0000, 0x1800 },
+ [TC27XD_DSPR1] = { 0x60000000, 120 * KiB },
+ [TC27XD_DCACHE1] = { 0x6001E000, 8 * KiB },
+ [TC27XD_DTAG1] = { 0x600C0000, 0xC00 },
+ [TC27XD_PSPR1] = { 0x60100000, 32 * KiB },
+ [TC27XD_PCACHE1] = { 0x60108000, 16 * KiB },
+ [TC27XD_PTAG1] = { 0x601C0000, 0x1800 },
+ [TC27XD_DSPR0] = { 0x70000000, 112 * KiB },
+ [TC27XD_PSPR0] = { 0x70100000, 24 * KiB },
+ [TC27XD_PCACHE0] = { 0x70106000, 8 * KiB },
+ [TC27XD_PTAG0] = { 0x701C0000, 0xC00 },
+ [TC27XD_PFLASH0_C] = { 0x80000000, 2 * MiB },
+ [TC27XD_PFLASH1_C] = { 0x80200000, 2 * MiB },
+ [TC27XD_OLDA_C] = { 0x8FE70000, 32 * KiB },
+ [TC27XD_BROM_C] = { 0x8FFF8000, 32 * KiB },
+ [TC27XD_LMURAM_C] = { 0x90000000, 32 * KiB },
+ [TC27XD_EMEM_C] = { 0x9F000000, 1 * MiB },
+ [TC27XD_PFLASH0_U] = { 0xA0000000, 0x0 },
+ [TC27XD_PFLASH1_U] = { 0xA0200000, 0x0 },
+ [TC27XD_DFLASH0] = { 0xAF000000, 1 * MiB + 16 * KiB },
+ [TC27XD_DFLASH1] = { 0xAF110000, 64 * KiB },
+ [TC27XD_OLDA_U] = { 0xAFE70000, 0x0 },
+ [TC27XD_BROM_U] = { 0xAFFF8000, 0x0 },
+ [TC27XD_LMURAM_U] = { 0xB0000000, 0x0 },
+ [TC27XD_EMEM_U] = { 0xBF000000, 0x0 },
+ [TC27XD_PSPRX] = { 0xC0000000, 0x0 },
+ [TC27XD_DSPRX] = { 0xD0000000, 0x0 },
+};
+
+/*
+ * Initialize the auxiliary ROM region @mr and map it into
+ * the memory map at @base.
+ */
+static void make_rom(MemoryRegion *mr, const char *name,
+ hwaddr base, hwaddr size)
+{
+ memory_region_init_rom(mr, NULL, name, size, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+/*
+ * Initialize the auxiliary RAM region @mr and map it into
+ * the memory map at @base.
+ */
+static void make_ram(MemoryRegion *mr, const char *name,
+ hwaddr base, hwaddr size)
+{
+ memory_region_init_ram(mr, NULL, name, size, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+/*
+ * Create an alias of an entire original MemoryRegion @orig
+ * located at @base in the memory map.
+ */
+static void make_alias(MemoryRegion *mr, const char *name,
+ MemoryRegion *orig, hwaddr base)
+{
+ memory_region_init_alias(mr, NULL, name, orig, 0,
+ memory_region_size(orig));
+ memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+static void tc27x_soc_init_memory_mapping(DeviceState *dev_soc)
+{
+ TC27XSoCState *s = TC27X_SOC(dev_soc);
+ TC27XSoCClass *sc = TC27X_SOC_GET_CLASS(s);
+
+ make_ram(&s->cpu0mem.dspr, "CPU0.DSPR",
+ sc->memmap[TC27XD_DSPR0].base, sc->memmap[TC27XD_DSPR0].size);
+ make_ram(&s->cpu0mem.pspr, "CPU0.PSPR",
+ sc->memmap[TC27XD_PSPR0].base, sc->memmap[TC27XD_PSPR0].size);
+ make_ram(&s->cpu1mem.dspr, "CPU1.DSPR",
+ sc->memmap[TC27XD_DSPR1].base, sc->memmap[TC27XD_DSPR1].size);
+ make_ram(&s->cpu1mem.pspr, "CPU1.PSPR",
+ sc->memmap[TC27XD_PSPR1].base, sc->memmap[TC27XD_PSPR1].size);
+ make_ram(&s->cpu2mem.dspr, "CPU2.DSPR",
+ sc->memmap[TC27XD_DSPR2].base, sc->memmap[TC27XD_DSPR2].size);
+ make_ram(&s->cpu2mem.pspr, "CPU2.PSPR",
+ sc->memmap[TC27XD_PSPR2].base, sc->memmap[TC27XD_PSPR2].size);
+
+ /* TODO: Control Cache mapping with Memory Test Unit (MTU) */
+ make_ram(&s->cpu2mem.dcache, "CPU2.DCACHE",
+ sc->memmap[TC27XD_DCACHE2].base, sc->memmap[TC27XD_DCACHE2].size);
+ make_ram(&s->cpu2mem.dtag, "CPU2.DTAG",
+ sc->memmap[TC27XD_DTAG2].base, sc->memmap[TC27XD_DTAG2].size);
+ make_ram(&s->cpu2mem.pcache, "CPU2.PCACHE",
+ sc->memmap[TC27XD_PCACHE2].base, sc->memmap[TC27XD_PCACHE2].size);
+ make_ram(&s->cpu2mem.ptag, "CPU2.PTAG",
+ sc->memmap[TC27XD_PTAG2].base, sc->memmap[TC27XD_PTAG2].size);
+
+ make_ram(&s->cpu1mem.dcache, "CPU1.DCACHE",
+ sc->memmap[TC27XD_DCACHE1].base, sc->memmap[TC27XD_DCACHE1].size);
+ make_ram(&s->cpu1mem.dtag, "CPU1.DTAG",
+ sc->memmap[TC27XD_DTAG1].base, sc->memmap[TC27XD_DTAG1].size);
+ make_ram(&s->cpu1mem.pcache, "CPU1.PCACHE",
+ sc->memmap[TC27XD_PCACHE1].base, sc->memmap[TC27XD_PCACHE1].size);
+ make_ram(&s->cpu1mem.ptag, "CPU1.PTAG",
+ sc->memmap[TC27XD_PTAG1].base, sc->memmap[TC27XD_PTAG1].size);
+
+ make_ram(&s->cpu0mem.pcache, "CPU0.PCACHE",
+ sc->memmap[TC27XD_PCACHE0].base, sc->memmap[TC27XD_PCACHE0].size);
+ make_ram(&s->cpu0mem.ptag, "CPU0.PTAG",
+ sc->memmap[TC27XD_PTAG0].base, sc->memmap[TC27XD_PTAG0].size);
+
+ /*
+ * TriCore QEMU executes CPU0 only, thus it is sufficient to map
+ * LOCAL.PSPR/LOCAL.DSPR exclusively onto PSPR0/DSPR0.
+ */
+ make_alias(&s->psprX, "LOCAL.PSPR", &s->cpu0mem.pspr,
+ sc->memmap[TC27XD_PSPRX].base);
+ make_alias(&s->dsprX, "LOCAL.DSPR", &s->cpu0mem.dspr,
+ sc->memmap[TC27XD_DSPRX].base);
+
+ make_ram(&s->flashmem.pflash0_c, "PF0",
+ sc->memmap[TC27XD_PFLASH0_C].base, sc->memmap[TC27XD_PFLASH0_C].size);
+ make_ram(&s->flashmem.pflash1_c, "PF1",
+ sc->memmap[TC27XD_PFLASH1_C].base, sc->memmap[TC27XD_PFLASH1_C].size);
+ make_ram(&s->flashmem.dflash0, "DF0",
+ sc->memmap[TC27XD_DFLASH0].base, sc->memmap[TC27XD_DFLASH0].size);
+ make_ram(&s->flashmem.dflash1, "DF1",
+ sc->memmap[TC27XD_DFLASH1].base, sc->memmap[TC27XD_DFLASH1].size);
+ make_ram(&s->flashmem.olda_c, "OLDA",
+ sc->memmap[TC27XD_OLDA_C].base, sc->memmap[TC27XD_OLDA_C].size);
+ make_rom(&s->flashmem.brom_c, "BROM",
+ sc->memmap[TC27XD_BROM_C].base, sc->memmap[TC27XD_BROM_C].size);
+ make_ram(&s->flashmem.lmuram_c, "LMURAM",
+ sc->memmap[TC27XD_LMURAM_C].base, sc->memmap[TC27XD_LMURAM_C].size);
+ make_ram(&s->flashmem.emem_c, "EMEM",
+ sc->memmap[TC27XD_EMEM_C].base, sc->memmap[TC27XD_EMEM_C].size);
+
+ make_alias(&s->flashmem.pflash0_u, "PF0.U", &s->flashmem.pflash0_c,
+ sc->memmap[TC27XD_PFLASH0_U].base);
+ make_alias(&s->flashmem.pflash1_u, "PF1.U", &s->flashmem.pflash1_c,
+ sc->memmap[TC27XD_PFLASH1_U].base);
+ make_alias(&s->flashmem.olda_u, "OLDA.U", &s->flashmem.olda_c,
+ sc->memmap[TC27XD_OLDA_U].base);
+ make_alias(&s->flashmem.brom_u, "BROM.U", &s->flashmem.brom_c,
+ sc->memmap[TC27XD_BROM_U].base);
+ make_alias(&s->flashmem.lmuram_u, "LMURAM.U", &s->flashmem.lmuram_c,
+ sc->memmap[TC27XD_LMURAM_U].base);
+ make_alias(&s->flashmem.emem_u, "EMEM.U", &s->flashmem.emem_c,
+ sc->memmap[TC27XD_EMEM_U].base);
+}
+
+static void tc27x_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+ TC27XSoCState *s = TC27X_SOC(dev_soc);
+ Error *err = NULL;
+
+ qdev_realize(DEVICE(&s->cpu), NULL, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ tc27x_soc_init_memory_mapping(dev_soc);
+}
+
+static void tc27x_soc_init(Object *obj)
+{
+ TC27XSoCState *s = TC27X_SOC(obj);
+ TC27XSoCClass *sc = TC27X_SOC_GET_CLASS(s);
+
+ object_initialize_child(obj, "tc27x", &s->cpu, sc->cpu_type);
+}
+
+static Property tc27x_soc_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tc27x_soc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = tc27x_soc_realize;
+ device_class_set_props(dc, tc27x_soc_properties);
+}
+
+static void tc277d_soc_class_init(ObjectClass *oc, void *data)
+{
+ TC27XSoCClass *sc = TC27X_SOC_CLASS(oc);
+
+ sc->name = "tc277d-soc";
+ sc->cpu_type = TRICORE_CPU_TYPE_NAME("tc27x");
+ sc->memmap = tc27x_soc_memmap;
+ sc->num_cpus = 1;
+}
+
+static const TypeInfo tc27x_soc_types[] = {
+ {
+ .name = "tc277d-soc",
+ .parent = TYPE_TC27X_SOC,
+ .class_init = tc277d_soc_class_init,
+ }, {
+ .name = TYPE_TC27X_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TC27XSoCState),
+ .instance_init = tc27x_soc_init,
+ .class_size = sizeof(TC27XSoCClass),
+ .class_init = tc27x_soc_class_init,
+ .abstract = true,
+ },
+};
+
+DEFINE_TYPES(tc27x_soc_types)
diff --git a/hw/tricore/triboard.c b/hw/tricore/triboard.c
new file mode 100644
index 0000000000..16e2fd7e27
--- /dev/null
+++ b/hw/tricore/triboard.c
@@ -0,0 +1,98 @@
+/*
+ * Infineon TriBoard System emulation.
+ *
+ * Copyright (c) 2020 Andreas Konopik <andreas.konopik@efs-auto.de>
+ * Copyright (c) 2020 David Brenken <david.brenken@efs-auto.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "cpu.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "exec/address-spaces.h"
+#include "elf.h"
+#include "hw/tricore/tricore.h"
+#include "qemu/error-report.h"
+
+#include "hw/tricore/triboard.h"
+#include "hw/tricore/tc27x_soc.h"
+
+static void tricore_load_kernel(const char *kernel_filename)
+{
+ uint64_t entry;
+ long kernel_size;
+ TriCoreCPU *cpu;
+ CPUTriCoreState *env;
+
+ kernel_size = load_elf(kernel_filename, NULL,
+ NULL, NULL, &entry, NULL,
+ NULL, NULL, 0,
+ EM_TRICORE, 1, 0);
+ if (kernel_size <= 0) {
+ error_report("no kernel file '%s'", kernel_filename);
+ exit(1);
+ }
+ cpu = TRICORE_CPU(first_cpu);
+ env = &cpu->env;
+ env->PC = entry;
+}
+
+
+static void triboard_machine_init(MachineState *machine)
+{
+ TriBoardMachineState *ms = TRIBOARD_MACHINE(machine);
+ TriBoardMachineClass *amc = TRIBOARD_MACHINE_GET_CLASS(machine);
+
+ object_initialize_child(OBJECT(machine), "soc", &ms->tc27x_soc,
+ amc->soc_name);
+ sysbus_realize(SYS_BUS_DEVICE(&ms->tc27x_soc), &error_fatal);
+
+ if (machine->kernel_filename) {
+ tricore_load_kernel(machine->kernel_filename);
+ }
+}
+
+static void triboard_machine_tc277d_class_init(ObjectClass *oc,
+ void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ TriBoardMachineClass *amc = TRIBOARD_MACHINE_CLASS(oc);
+
+ mc->init = triboard_machine_init;
+ mc->desc = "Infineon AURIX TriBoard TC277 (D-Step)";
+ mc->max_cpus = 1;
+ amc->soc_name = "tc277d-soc";
+};
+
+static const TypeInfo triboard_machine_types[] = {
+ {
+ .name = MACHINE_TYPE_NAME("KIT_AURIX_TC277_TRB"),
+ .parent = TYPE_TRIBOARD_MACHINE,
+ .class_init = triboard_machine_tc277d_class_init,
+ }, {
+ .name = TYPE_TRIBOARD_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(TriBoardMachineState),
+ .class_size = sizeof(TriBoardMachineClass),
+ .abstract = true,
+ },
+};
+
+DEFINE_TYPES(triboard_machine_types)
diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
index 40093d7ea6..53f8283ffd 100644
--- a/hw/usb/Kconfig
+++ b/hw/usb/Kconfig
@@ -66,11 +66,22 @@ config USB_TABLET_WACOM
default y
depends on USB
+config USB_STORAGE_CORE
+ bool
+ depends on USB
+ select SCSI
+
+config USB_STORAGE_CLASSIC
+ bool
+ default y
+ depends on USB
+ select USB_STORAGE_CORE
+
config USB_STORAGE_BOT
bool
default y
depends on USB
- select SCSI
+ select USB_STORAGE_CORE
config USB_STORAGE_UAS
bool
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 064f94e9c3..07083349f5 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -19,8 +19,6 @@ static void usb_qdev_unrealize(DeviceState *qdev);
static Property usb_props[] = {
DEFINE_PROP_STRING("port", USBDevice, port_path),
DEFINE_PROP_STRING("serial", USBDevice, serial),
- DEFINE_PROP_BIT("full-path", USBDevice, flags,
- USB_DEV_FLAG_FULL_PATH, true),
DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
DEFINE_PROP_STRING("pcap", USBDevice, pcap_filename),
@@ -312,13 +310,13 @@ typedef struct LegacyUSBFactory
{
const char *name;
const char *usbdevice_name;
- USBDevice *(*usbdevice_init)(const char *params);
+ USBDevice *(*usbdevice_init)(void);
} LegacyUSBFactory;
static GSList *legacy_usb_factory;
void usb_legacy_register(const char *typename, const char *usbdevice_name,
- USBDevice *(*usbdevice_init)(const char *params))
+ USBDevice *(*usbdevice_init)(void))
{
if (usbdevice_name) {
LegacyUSBFactory *f = g_malloc0(sizeof(*f));
@@ -596,11 +594,8 @@ static char *usb_get_dev_path(DeviceState *qdev)
{
USBDevice *dev = USB_DEVICE(qdev);
DeviceState *hcd = qdev->parent_bus->parent;
- char *id = NULL;
+ char *id = qdev_get_dev_path(hcd);
- if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
- id = qdev_get_dev_path(hcd);
- }
if (id) {
char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
g_free(id);
@@ -663,27 +658,17 @@ void hmp_info_usb(Monitor *mon, const QDict *qdict)
}
/* handle legacy -usbdevice cmd line option */
-USBDevice *usbdevice_create(const char *cmdline)
+USBDevice *usbdevice_create(const char *driver)
{
USBBus *bus = usb_bus_find(-1 /* any */);
LegacyUSBFactory *f = NULL;
Error *err = NULL;
GSList *i;
- char driver[32];
- const char *params;
- int len;
USBDevice *dev;
- params = strchr(cmdline,':');
- if (params) {
- params++;
- len = params - cmdline;
- if (len > sizeof(driver))
- len = sizeof(driver);
- pstrcpy(driver, len, cmdline);
- } else {
- params = "";
- pstrcpy(driver, sizeof(driver), cmdline);
+ if (strchr(driver, ':')) {
+ error_report("usbdevice parameters are not supported anymore");
+ return NULL;
}
for (i = legacy_usb_factory; i; i = i->next) {
@@ -707,15 +692,7 @@ USBDevice *usbdevice_create(const char *cmdline)
return NULL;
}
- if (f->usbdevice_init) {
- dev = f->usbdevice_init(params);
- } else {
- if (*params) {
- error_report("usbdevice %s accepts no params", driver);
- return NULL;
- }
- dev = usb_new(f->name);
- }
+ dev = f->usbdevice_init ? f->usbdevice_init() : usb_new(f->name);
if (!dev) {
error_report("Failed to create USB device '%s'", f->name);
return NULL;
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index e1486f81e0..f5cb246792 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -1024,7 +1024,6 @@ static const TypeInfo usb_audio_info = {
static void usb_audio_register_types(void)
{
type_register_static(&usb_audio_info);
- usb_legacy_register(TYPE_USB_AUDIO, "audio", NULL);
}
type_init(usb_audio_register_types)
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index b58c4eb908..63047d79cf 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -614,7 +614,7 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
}
-static USBDevice *usb_braille_init(const char *unused)
+static USBDevice *usb_braille_init(void)
{
USBDevice *dev;
Chardev *cdrv;
diff --git a/hw/usb/dev-storage-bot.c b/hw/usb/dev-storage-bot.c
new file mode 100644
index 0000000000..6aad026d11
--- /dev/null
+++ b/hw/usb/dev-storage-bot.c
@@ -0,0 +1,63 @@
+/*
+ * USB Mass Storage Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/typedefs.h"
+#include "qapi/error.h"
+#include "hw/usb.h"
+#include "hw/usb/desc.h"
+#include "hw/usb/msd.h"
+
+static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
+ .tcq = false,
+ .max_target = 0,
+ .max_lun = 15,
+
+ .transfer_data = usb_msd_transfer_data,
+ .complete = usb_msd_command_complete,
+ .cancel = usb_msd_request_cancelled,
+ .load_request = usb_msd_load_request,
+};
+
+static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
+{
+ MSDState *s = USB_STORAGE_DEV(dev);
+ DeviceState *d = DEVICE(dev);
+
+ usb_desc_create_serial(dev);
+ usb_desc_init(dev);
+ if (d->hotplugged) {
+ s->dev.auto_attach = 0;
+ }
+
+ scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
+ &usb_msd_scsi_info_bot, NULL);
+ usb_msd_handle_reset(dev);
+}
+
+static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->realize = usb_msd_bot_realize;
+ uc->attached_settable = true;
+}
+
+static const TypeInfo bot_info = {
+ .name = "usb-bot",
+ .parent = TYPE_USB_STORAGE,
+ .class_init = usb_msd_class_bot_initfn,
+};
+
+static void register_types(void)
+{
+ type_register_static(&bot_info);
+}
+
+type_init(register_types)
diff --git a/hw/usb/dev-storage-classic.c b/hw/usb/dev-storage-classic.c
new file mode 100644
index 0000000000..00cb34b22f
--- /dev/null
+++ b/hw/usb/dev-storage-classic.c
@@ -0,0 +1,156 @@
+/*
+ * USB Mass Storage Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/typedefs.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "hw/usb.h"
+#include "hw/usb/desc.h"
+#include "hw/usb/msd.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/block-backend.h"
+
+static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
+ .tcq = false,
+ .max_target = 0,
+ .max_lun = 0,
+
+ .transfer_data = usb_msd_transfer_data,
+ .complete = usb_msd_command_complete,
+ .cancel = usb_msd_request_cancelled,
+ .load_request = usb_msd_load_request,
+};
+
+static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
+{
+ MSDState *s = USB_STORAGE_DEV(dev);
+ BlockBackend *blk = s->conf.blk;
+ SCSIDevice *scsi_dev;
+
+ if (!blk) {
+ error_setg(errp, "drive property not set");
+ return;
+ }
+
+ if (!blkconf_blocksizes(&s->conf, errp)) {
+ return;
+ }
+
+ if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk),
+ true, errp)) {
+ return;
+ }
+
+ /*
+ * Hack alert: this pretends to be a block device, but it's really
+ * a SCSI bus that can serve only a single device, which it
+ * creates automatically. But first it needs to detach from its
+ * blockdev, or else scsi_bus_legacy_add_drive() dies when it
+ * attaches again. We also need to take another reference so that
+ * blk_detach_dev() doesn't free blk while we still need it.
+ *
+ * The hack is probably a bad idea.
+ */
+ blk_ref(blk);
+ blk_detach_dev(blk, DEVICE(s));
+ s->conf.blk = NULL;
+
+ usb_desc_create_serial(dev);
+ usb_desc_init(dev);
+ scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
+ &usb_msd_scsi_info_storage, NULL);
+ scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
+ s->conf.bootindex, s->conf.share_rw,
+ s->conf.rerror, s->conf.werror,
+ dev->serial,
+ errp);
+ blk_unref(blk);
+ if (!scsi_dev) {
+ return;
+ }
+ usb_msd_handle_reset(dev);
+ s->scsi_dev = scsi_dev;
+}
+
+static Property msd_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+ DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
+ DEFINE_PROP_BOOL("removable", MSDState, removable, false),
+ DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->realize = usb_msd_storage_realize;
+ device_class_set_props(dc, msd_properties);
+}
+
+static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ USBDevice *dev = USB_DEVICE(obj);
+ MSDState *s = USB_STORAGE_DEV(dev);
+
+ visit_type_int32(v, name, &s->conf.bootindex, errp);
+}
+
+static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ USBDevice *dev = USB_DEVICE(obj);
+ MSDState *s = USB_STORAGE_DEV(dev);
+ int32_t boot_index;
+ Error *local_err = NULL;
+
+ if (!visit_type_int32(v, name, &boot_index, errp)) {
+ return;
+ }
+ /* check whether bootindex is present in fw_boot_order list */
+ check_boot_index(boot_index, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ /* change bootindex to a new one */
+ s->conf.bootindex = boot_index;
+
+ if (s->scsi_dev) {
+ object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index,
+ &error_abort);
+ }
+
+out:
+ error_propagate(errp, local_err);
+}
+
+static void usb_msd_instance_init(Object *obj)
+{
+ object_property_add(obj, "bootindex", "int32",
+ usb_msd_get_bootindex,
+ usb_msd_set_bootindex, NULL, NULL);
+ object_property_set_int(obj, "bootindex", -1, NULL);
+}
+
+static const TypeInfo msd_info = {
+ .name = "usb-storage",
+ .parent = TYPE_USB_STORAGE,
+ .class_init = usb_msd_class_storage_initfn,
+ .instance_init = usb_msd_instance_init,
+};
+
+static void register_types(void)
+{
+ type_register_static(&msd_info);
+}
+
+type_init(register_types)
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index a5f76fc001..dca62d544f 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -14,13 +14,11 @@
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "hw/usb.h"
+#include "hw/usb/msd.h"
#include "desc.h"
#include "hw/qdev-properties.h"
#include "hw/scsi/scsi.h"
#include "migration/vmstate.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
-#include "qapi/visitor.h"
#include "qemu/cutils.h"
#include "qom/object.h"
#include "trace.h"
@@ -29,43 +27,6 @@
#define MassStorageReset 0xff
#define GetMaxLun 0xfe
-enum USBMSDMode {
- USB_MSDM_CBW, /* Command Block. */
- USB_MSDM_DATAOUT, /* Transfer data to device. */
- USB_MSDM_DATAIN, /* Transfer data from device. */
- USB_MSDM_CSW /* Command Status. */
-};
-
-struct usb_msd_csw {
- uint32_t sig;
- uint32_t tag;
- uint32_t residue;
- uint8_t status;
-};
-
-struct MSDState {
- USBDevice dev;
- enum USBMSDMode mode;
- uint32_t scsi_off;
- uint32_t scsi_len;
- uint32_t data_len;
- struct usb_msd_csw csw;
- SCSIRequest *req;
- SCSIBus bus;
- /* For async completion. */
- USBPacket *packet;
- /* usb-storage only */
- BlockConf conf;
- bool removable;
- bool commandlog;
- SCSIDevice *scsi_dev;
-};
-typedef struct MSDState MSDState;
-
-#define TYPE_USB_STORAGE "usb-storage-dev"
-DECLARE_INSTANCE_CHECKER(MSDState, USB_STORAGE_DEV,
- TYPE_USB_STORAGE)
-
struct usb_msd_cbw {
uint32_t sig;
uint32_t tag;
@@ -259,7 +220,7 @@ static void usb_msd_packet_complete(MSDState *s)
usb_packet_complete(&s->dev, p);
}
-static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
+void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
@@ -277,7 +238,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
}
}
-static void usb_msd_command_complete(SCSIRequest *req, size_t resid)
+void usb_msd_command_complete(SCSIRequest *req, size_t resid)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
@@ -320,7 +281,7 @@ static void usb_msd_command_complete(SCSIRequest *req, size_t resid)
s->req = NULL;
}
-static void usb_msd_request_cancelled(SCSIRequest *req)
+void usb_msd_request_cancelled(SCSIRequest *req)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
@@ -337,7 +298,7 @@ static void usb_msd_request_cancelled(SCSIRequest *req)
}
}
-static void usb_msd_handle_reset(USBDevice *dev)
+void usb_msd_handle_reset(USBDevice *dev)
{
MSDState *s = (MSDState *)dev;
@@ -352,6 +313,7 @@ static void usb_msd_handle_reset(USBDevice *dev)
usb_msd_packet_complete(s);
}
+ memset(&s->csw, 0, sizeof(s->csw));
s->mode = USB_MSDM_CBW;
}
@@ -565,7 +527,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
+void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
@@ -576,95 +538,6 @@ static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
return NULL;
}
-static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
- .tcq = false,
- .max_target = 0,
- .max_lun = 0,
-
- .transfer_data = usb_msd_transfer_data,
- .complete = usb_msd_command_complete,
- .cancel = usb_msd_request_cancelled,
- .load_request = usb_msd_load_request,
-};
-
-static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
- .tcq = false,
- .max_target = 0,
- .max_lun = 15,
-
- .transfer_data = usb_msd_transfer_data,
- .complete = usb_msd_command_complete,
- .cancel = usb_msd_request_cancelled,
- .load_request = usb_msd_load_request,
-};
-
-static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
- BlockBackend *blk = s->conf.blk;
- SCSIDevice *scsi_dev;
-
- if (!blk) {
- error_setg(errp, "drive property not set");
- return;
- }
-
- if (!blkconf_blocksizes(&s->conf, errp)) {
- return;
- }
-
- if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk),
- true, errp)) {
- return;
- }
-
- /*
- * Hack alert: this pretends to be a block device, but it's really
- * a SCSI bus that can serve only a single device, which it
- * creates automatically. But first it needs to detach from its
- * blockdev, or else scsi_bus_legacy_add_drive() dies when it
- * attaches again. We also need to take another reference so that
- * blk_detach_dev() doesn't free blk while we still need it.
- *
- * The hack is probably a bad idea.
- */
- blk_ref(blk);
- blk_detach_dev(blk, DEVICE(s));
- s->conf.blk = NULL;
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &usb_msd_scsi_info_storage, NULL);
- scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
- s->conf.bootindex, s->conf.share_rw,
- s->conf.rerror, s->conf.werror,
- dev->serial,
- errp);
- blk_unref(blk);
- if (!scsi_dev) {
- return;
- }
- usb_msd_handle_reset(dev);
- s->scsi_dev = scsi_dev;
-}
-
-static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
- DeviceState *d = DEVICE(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- if (d->hotplugged) {
- s->dev.auto_attach = 0;
- }
-
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &usb_msd_scsi_info_bot, NULL);
- usb_msd_handle_reset(dev);
-}
-
static const VMStateDescription vmstate_usb_msd = {
.name = "usb-storage",
.version_id = 1,
@@ -683,14 +556,6 @@ static const VMStateDescription vmstate_usb_msd = {
}
};
-static Property msd_properties[] = {
- DEFINE_BLOCK_PROPERTIES(MSDState, conf),
- DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
- DEFINE_PROP_BOOL("removable", MSDState, removable, false),
- DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -708,52 +573,6 @@ static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_usb_msd;
}
-static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_msd_storage_realize;
- device_class_set_props(dc, msd_properties);
-}
-
-static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(obj);
- MSDState *s = USB_STORAGE_DEV(dev);
-
- visit_type_int32(v, name, &s->conf.bootindex, errp);
-}
-
-static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(obj);
- MSDState *s = USB_STORAGE_DEV(dev);
- int32_t boot_index;
- Error *local_err = NULL;
-
- if (!visit_type_int32(v, name, &boot_index, errp)) {
- return;
- }
- /* check whether bootindex is present in fw_boot_order list */
- check_boot_index(boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* change bootindex to a new one */
- s->conf.bootindex = boot_index;
-
- if (s->scsi_dev) {
- object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index,
- &error_abort);
- }
-
-out:
- error_propagate(errp, local_err);
-}
-
static const TypeInfo usb_storage_dev_type_info = {
.name = TYPE_USB_STORAGE,
.parent = TYPE_USB_DEVICE,
@@ -762,40 +581,9 @@ static const TypeInfo usb_storage_dev_type_info = {
.class_init = usb_msd_class_initfn_common,
};
-static void usb_msd_instance_init(Object *obj)
-{
- object_property_add(obj, "bootindex", "int32",
- usb_msd_get_bootindex,
- usb_msd_set_bootindex, NULL, NULL);
- object_property_set_int(obj, "bootindex", -1, NULL);
-}
-
-static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_msd_bot_realize;
- uc->attached_settable = true;
-}
-
-static const TypeInfo msd_info = {
- .name = "usb-storage",
- .parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_storage_initfn,
- .instance_init = usb_msd_instance_init,
-};
-
-static const TypeInfo bot_info = {
- .name = "usb-bot",
- .parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_bot_initfn,
-};
-
static void usb_msd_register_types(void)
{
type_register_static(&usb_storage_dev_type_info);
- type_register_static(&msd_info);
- type_register_static(&bot_info);
}
type_init(usb_msd_register_types)
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 5969eb86b3..0cb02a6432 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -40,6 +40,7 @@
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qom/object.h"
+#include "hcd-uhci.h"
#define FRAME_TIMER_FREQ 1000
@@ -50,8 +51,6 @@
#define MAX_FRAMES_PER_TICK (QH_VALID / 2)
-#define NB_PORTS 2
-
enum {
TD_RESULT_STOP_FRAME = 10,
TD_RESULT_COMPLETE,
@@ -62,20 +61,8 @@ enum {
typedef struct UHCIState UHCIState;
typedef struct UHCIAsync UHCIAsync;
-typedef struct UHCIQueue UHCIQueue;
-typedef struct UHCIInfo UHCIInfo;
typedef struct UHCIPCIDeviceClass UHCIPCIDeviceClass;
-struct UHCIInfo {
- const char *name;
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint8_t irq_pin;
- void (*realize)(PCIDevice *dev, Error **errp);
- bool unplug;
-};
-
struct UHCIPCIDeviceClass {
PCIDeviceClass parent_class;
UHCIInfo info;
@@ -107,43 +94,6 @@ struct UHCIQueue {
int8_t valid;
};
-typedef struct UHCIPort {
- USBPort port;
- uint16_t ctrl;
-} UHCIPort;
-
-struct UHCIState {
- PCIDevice dev;
- MemoryRegion io_bar;
- USBBus bus; /* Note unused when we're a companion controller */
- uint16_t cmd; /* cmd register */
- uint16_t status;
- uint16_t intr; /* interrupt enable register */
- uint16_t frnum; /* frame number */
- uint32_t fl_base_addr; /* frame list base address */
- uint8_t sof_timing;
- uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
- int64_t expire_time;
- QEMUTimer *frame_timer;
- QEMUBH *bh;
- uint32_t frame_bytes;
- uint32_t frame_bandwidth;
- bool completions_only;
- UHCIPort ports[NB_PORTS];
-
- /* Interrupts that should be raised at the end of the current frame. */
- uint32_t pending_int_mask;
-
- /* Active packets */
- QTAILQ_HEAD(, UHCIQueue) queues;
- uint8_t num_ports_vmstate;
-
- /* Properties */
- char *masterbus;
- uint32_t firstport;
- uint32_t maxframes;
-};
-
typedef struct UHCI_TD {
uint32_t link;
uint32_t ctrl; /* see TD_CTRL_xxx */
@@ -160,10 +110,6 @@ static void uhci_async_cancel(UHCIAsync *async);
static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td);
static void uhci_resume(void *opaque);
-#define TYPE_UHCI "pci-uhci-usb"
-DECLARE_INSTANCE_CHECKER(UHCIState, UHCI,
- TYPE_UHCI)
-
static inline int32_t uhci_queue_token(UHCI_TD *td)
{
if ((td->token & (0xf << 15)) == 0) {
@@ -1213,7 +1159,7 @@ static USBPortOps uhci_port_ops = {
static USBBusOps uhci_bus_ops = {
};
-static void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
+void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
{
Error *err = NULL;
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
@@ -1261,21 +1207,6 @@ static void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
}
-static void usb_uhci_vt82c686b_realize(PCIDevice *dev, Error **errp)
-{
- UHCIState *s = UHCI(dev);
- uint8_t *pci_conf = s->dev.config;
-
- /* USB misc control 1/2 */
- pci_set_long(pci_conf + 0x40,0x00001000);
- /* PM capability */
- pci_set_long(pci_conf + 0x80,0x00020001);
- /* USB legacy support */
- pci_set_long(pci_conf + 0xc0,0x00002000);
-
- usb_uhci_common_realize(dev, errp);
-}
-
static void usb_uhci_exit(PCIDevice *dev)
{
UHCIState *s = UHCI(dev);
@@ -1335,7 +1266,7 @@ static const TypeInfo uhci_pci_type_info = {
},
};
-static void uhci_data_class_init(ObjectClass *klass, void *data)
+void uhci_data_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1373,14 +1304,6 @@ static UHCIInfo uhci_info[] = {
.irq_pin = 3,
.unplug = true,
},{
- .name = "vt82c686b-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_UHCI,
- .revision = 0x01,
- .irq_pin = 3,
- .realize = usb_uhci_vt82c686b_realize,
- .unplug = true,
- },{
.name = "ich9-usb-uhci1", /* 00:1d.0 */
.vendor_id = PCI_VENDOR_ID_INTEL,
.device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
diff --git a/hw/usb/hcd-uhci.h b/hw/usb/hcd-uhci.h
new file mode 100644
index 0000000000..e61d8fcb19
--- /dev/null
+++ b/hw/usb/hcd-uhci.h
@@ -0,0 +1,93 @@
+/*
+ * USB UHCI controller emulation
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ * Magor rewrite of the UHCI data structures parser and frame processor
+ * Support for fully async operation and multiple outstanding transactions
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HW_USB_HCD_UHCI_H
+#define HW_USB_HCD_UHCI_H
+
+#include "exec/memory.h"
+#include "qemu/timer.h"
+#include "hw/pci/pci.h"
+#include "hw/usb.h"
+
+typedef struct UHCIQueue UHCIQueue;
+
+#define NB_PORTS 2
+
+typedef struct UHCIPort {
+ USBPort port;
+ uint16_t ctrl;
+} UHCIPort;
+
+typedef struct UHCIState {
+ PCIDevice dev;
+ MemoryRegion io_bar;
+ USBBus bus; /* Note unused when we're a companion controller */
+ uint16_t cmd; /* cmd register */
+ uint16_t status;
+ uint16_t intr; /* interrupt enable register */
+ uint16_t frnum; /* frame number */
+ uint32_t fl_base_addr; /* frame list base address */
+ uint8_t sof_timing;
+ uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
+ int64_t expire_time;
+ QEMUTimer *frame_timer;
+ QEMUBH *bh;
+ uint32_t frame_bytes;
+ uint32_t frame_bandwidth;
+ bool completions_only;
+ UHCIPort ports[NB_PORTS];
+
+ /* Interrupts that should be raised at the end of the current frame. */
+ uint32_t pending_int_mask;
+
+ /* Active packets */
+ QTAILQ_HEAD(, UHCIQueue) queues;
+ uint8_t num_ports_vmstate;
+
+ /* Properties */
+ char *masterbus;
+ uint32_t firstport;
+ uint32_t maxframes;
+} UHCIState;
+
+#define TYPE_UHCI "pci-uhci-usb"
+DECLARE_INSTANCE_CHECKER(UHCIState, UHCI, TYPE_UHCI)
+
+typedef struct UHCIInfo {
+ const char *name;
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint8_t revision;
+ uint8_t irq_pin;
+ void (*realize)(PCIDevice *dev, Error **errp);
+ bool unplug;
+} UHCIInfo;
+
+void uhci_data_class_init(ObjectClass *klass, void *data);
+void usb_uhci_common_realize(PCIDevice *dev, Error **errp);
+
+#endif
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index 653192cff6..fb7a74e73a 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -32,6 +32,7 @@ softmmu_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c'))
softmmu_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c'))
softmmu_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c'))
+softmmu_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c'))
specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c'))
specific_ss.add(when: 'CONFIG_XLNX_USB_SUBSYS', if_true: files('xlnx-usb-subsystem.c'))
@@ -39,7 +40,9 @@ specific_ss.add(when: 'CONFIG_XLNX_USB_SUBSYS', if_true: files('xlnx-usb-subsyst
softmmu_ss.add(when: 'CONFIG_USB', if_true: files('dev-hub.c'))
softmmu_ss.add(when: 'CONFIG_USB', if_true: files('dev-hid.c'))
softmmu_ss.add(when: 'CONFIG_USB_TABLET_WACOM', if_true: files('dev-wacom.c'))
-softmmu_ss.add(when: 'CONFIG_USB_STORAGE_BOT', if_true: files('dev-storage.c'))
+softmmu_ss.add(when: 'CONFIG_USB_STORAGE_CORE', if_true: files('dev-storage.c'))
+softmmu_ss.add(when: 'CONFIG_USB_STORAGE_BOT', if_true: files('dev-storage-bot.c'))
+softmmu_ss.add(when: 'CONFIG_USB_STORAGE_CLASSIC', if_true: files('dev-storage-classic.c'))
softmmu_ss.add(when: 'CONFIG_USB_STORAGE_UAS', if_true: files('dev-uas.c'))
softmmu_ss.add(when: 'CONFIG_USB_AUDIO', if_true: files('dev-audio.c'))
softmmu_ss.add(when: 'CONFIG_USB_SERIAL', if_true: files('dev-serial.c'))
diff --git a/hw/usb/u2f.c b/hw/usb/u2f.c
index bc09191f06..56001249a4 100644
--- a/hw/usb/u2f.c
+++ b/hw/usb/u2f.c
@@ -346,7 +346,6 @@ static const TypeInfo u2f_key_info = {
static void u2f_key_register_types(void)
{
type_register_static(&u2f_key_info);
- usb_legacy_register(TYPE_U2F_KEY, "u2f-key", NULL);
}
type_init(u2f_key_register_types)
diff --git a/hw/usb/vt82c686-uhci-pci.c b/hw/usb/vt82c686-uhci-pci.c
new file mode 100644
index 0000000000..b109c21603
--- /dev/null
+++ b/hw/usb/vt82c686-uhci-pci.c
@@ -0,0 +1,43 @@
+#include "qemu/osdep.h"
+#include "hcd-uhci.h"
+
+static void usb_uhci_vt82c686b_realize(PCIDevice *dev, Error **errp)
+{
+ UHCIState *s = UHCI(dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ /* USB misc control 1/2 */
+ pci_set_long(pci_conf + 0x40, 0x00001000);
+ /* PM capability */
+ pci_set_long(pci_conf + 0x80, 0x00020001);
+ /* USB legacy support */
+ pci_set_long(pci_conf + 0xc0, 0x00002000);
+
+ usb_uhci_common_realize(dev, errp);
+}
+
+static UHCIInfo uhci_info[] = {
+ {
+ .name = "vt82c686b-usb-uhci",
+ .vendor_id = PCI_VENDOR_ID_VIA,
+ .device_id = PCI_DEVICE_ID_VIA_UHCI,
+ .revision = 0x01,
+ .irq_pin = 3,
+ .realize = usb_uhci_vt82c686b_realize,
+ .unplug = true,
+ }
+};
+
+static const TypeInfo vt82c686b_usb_uhci_type_info = {
+ .parent = TYPE_UHCI,
+ .name = "vt82c686b-usb-uhci",
+ .class_init = uhci_data_class_init,
+ .class_data = uhci_info,
+};
+
+static void vt82c686b_usb_uhci_register_types(void)
+{
+ type_register_static(&vt82c686b_usb_uhci_type_info);
+}
+
+type_init(vt82c686b_usb_uhci_register_types)
diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c
index 292d13d278..aa0b3caecb 100644
--- a/hw/virtio/virtio-net-pci.c
+++ b/hw/virtio/virtio-net-pci.c
@@ -41,7 +41,8 @@ struct VirtIONetPCI {
static Property virtio_net_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
DEFINE_PROP_END_OF_LIST(),
};
@@ -50,6 +51,13 @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
DeviceState *qdev = DEVICE(vpci_dev);
VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIONet *net = VIRTIO_NET(vdev);
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = 2 * MAX(net->nic_conf.peers.queues, 1)
+ + 1 /* Config interrupt */
+ + 1 /* Control vq */;
+ }
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev)));
diff --git a/include/hw/char/goldfish_tty.h b/include/hw/char/goldfish_tty.h
new file mode 100644
index 0000000000..b9dd67362a
--- /dev/null
+++ b/include/hw/char/goldfish_tty.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * Goldfish TTY
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#ifndef HW_CHAR_GOLDFISH_TTY_H
+#define HW_CHAR_GOLDFISH_TTY_H
+
+#include "qemu/fifo8.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_GOLDFISH_TTY "goldfish_tty"
+OBJECT_DECLARE_SIMPLE_TYPE(GoldfishTTYState, GOLDFISH_TTY)
+
+#define GOLFISH_TTY_BUFFER_SIZE 128
+
+struct GoldfishTTYState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+ CharBackend chr;
+
+ uint32_t data_len;
+ uint64_t data_ptr;
+ bool int_enabled;
+
+ Fifo8 rx_fifo;
+};
+
+#endif
diff --git a/include/hw/intc/goldfish_pic.h b/include/hw/intc/goldfish_pic.h
new file mode 100644
index 0000000000..ad13ab37fc
--- /dev/null
+++ b/include/hw/intc/goldfish_pic.h
@@ -0,0 +1,33 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * Goldfish PIC
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#ifndef HW_INTC_GOLDFISH_PIC_H
+#define HW_INTC_GOLDFISH_PIC_H
+
+#define TYPE_GOLDFISH_PIC "goldfish_pic"
+OBJECT_DECLARE_SIMPLE_TYPE(GoldfishPICState, GOLDFISH_PIC)
+
+#define GOLDFISH_PIC_IRQ_NB 32
+
+struct GoldfishPICState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ uint32_t pending;
+ uint32_t enabled;
+
+ /* statistics */
+ uint64_t stats_irq_count[32];
+ /* for tracing */
+ uint8_t idx;
+};
+
+#endif
diff --git a/include/hw/intc/m68k_irqc.h b/include/hw/intc/m68k_irqc.h
new file mode 100644
index 0000000000..dbcfcfc2e0
--- /dev/null
+++ b/include/hw/intc/m68k_irqc.h
@@ -0,0 +1,41 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * QEMU Motorola 680x0 IRQ Controller
+ *
+ * (c) 2020 Laurent Vivier <laurent@vivier.eu>
+ *
+ */
+
+#ifndef M68K_IRQC_H
+#define M68K_IRQC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_M68K_IRQC "m68k-irq-controller"
+#define M68K_IRQC(obj) OBJECT_CHECK(M68KIRQCState, (obj), \
+ TYPE_M68K_IRQC)
+
+#define M68K_IRQC_AUTOVECTOR_BASE 25
+
+enum {
+ M68K_IRQC_LEVEL_1 = 0,
+ M68K_IRQC_LEVEL_2,
+ M68K_IRQC_LEVEL_3,
+ M68K_IRQC_LEVEL_4,
+ M68K_IRQC_LEVEL_5,
+ M68K_IRQC_LEVEL_6,
+ M68K_IRQC_LEVEL_7,
+};
+#define M68K_IRQC_LEVEL_NUM (M68K_IRQC_LEVEL_7 - M68K_IRQC_LEVEL_1 + 1)
+
+typedef struct M68KIRQCState {
+ SysBusDevice parent_obj;
+
+ uint8_t ipr;
+
+ /* statistics */
+ uint64_t stats_irq_count[M68K_IRQC_LEVEL_NUM];
+} M68KIRQCState;
+
+#endif
diff --git a/include/hw/misc/led.h b/include/hw/misc/led.h
index aa359b87c2..29c0879570 100644
--- a/include/hw/misc/led.h
+++ b/include/hw/misc/led.h
@@ -27,6 +27,7 @@ typedef enum { /* Coarse wavelength range */
LED_COLOR_BLUE, /* 475 nm */
LED_COLOR_CYAN, /* 500 nm */
LED_COLOR_GREEN, /* 535 nm */
+ LED_COLOR_YELLOW, /* 567 nm */
LED_COLOR_AMBER, /* 590 nm */
LED_COLOR_ORANGE, /* 615 nm */
LED_COLOR_RED, /* 630 nm */
diff --git a/include/hw/misc/virt_ctrl.h b/include/hw/misc/virt_ctrl.h
new file mode 100644
index 0000000000..edfadc4695
--- /dev/null
+++ b/include/hw/misc/virt_ctrl.h
@@ -0,0 +1,22 @@
+/*
+ * SPDX-License-Identifer: GPL-2.0-or-later
+ *
+ * Virt system Controller
+ */
+
+#ifndef VIRT_CTRL_H
+#define VIRT_CTRL_H
+
+#define TYPE_VIRT_CTRL "virt-ctrl"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtCtrlState, VIRT_CTRL)
+
+struct VirtCtrlState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ uint32_t irq_enabled;
+};
+
+#endif
diff --git a/include/hw/tricore/tc27x_soc.h b/include/hw/tricore/tc27x_soc.h
new file mode 100644
index 0000000000..6a7e5b54f5
--- /dev/null
+++ b/include/hw/tricore/tc27x_soc.h
@@ -0,0 +1,129 @@
+/*
+ * Infineon tc27x SoC System emulation.
+ *
+ * Copyright (c) 2020 Andreas Konopik <andreas.konopik@efs-auto.de>
+ * Copyright (c) 2020 David Brenken <david.brenken@efs-auto.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TC27X_SoC_H
+#define TC27X_SoC_H
+
+#include "hw/sysbus.h"
+#include "target/tricore/cpu.h"
+#include "qom/object.h"
+
+#define TYPE_TC27X_SOC ("tc27x-soc")
+OBJECT_DECLARE_TYPE(TC27XSoCState, TC27XSoCClass, TC27X_SOC)
+
+typedef struct TC27XSoCCPUMemState {
+
+ MemoryRegion dspr;
+ MemoryRegion pspr;
+
+ MemoryRegion dcache;
+ MemoryRegion dtag;
+ MemoryRegion pcache;
+ MemoryRegion ptag;
+
+} TC27XSoCCPUMemState;
+
+typedef struct TC27XSoCFlashMemState {
+
+ MemoryRegion pflash0_c;
+ MemoryRegion pflash1_c;
+ MemoryRegion pflash0_u;
+ MemoryRegion pflash1_u;
+ MemoryRegion dflash0;
+ MemoryRegion dflash1;
+ MemoryRegion olda_c;
+ MemoryRegion olda_u;
+ MemoryRegion brom_c;
+ MemoryRegion brom_u;
+ MemoryRegion lmuram_c;
+ MemoryRegion lmuram_u;
+ MemoryRegion emem_c;
+ MemoryRegion emem_u;
+
+} TC27XSoCFlashMemState;
+
+typedef struct TC27XSoCState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ TriCoreCPU cpu;
+
+ MemoryRegion dsprX;
+ MemoryRegion psprX;
+
+ TC27XSoCCPUMemState cpu0mem;
+ TC27XSoCCPUMemState cpu1mem;
+ TC27XSoCCPUMemState cpu2mem;
+
+ TC27XSoCFlashMemState flashmem;
+
+} TC27XSoCState;
+
+typedef struct MemmapEntry {
+ hwaddr base;
+ hwaddr size;
+} MemmapEntry;
+
+typedef struct TC27XSoCClass {
+ DeviceClass parent_class;
+
+ const char *name;
+ const char *cpu_type;
+ const MemmapEntry *memmap;
+ uint32_t num_cpus;
+} TC27XSoCClass;
+
+enum {
+ TC27XD_DSPR2,
+ TC27XD_DCACHE2,
+ TC27XD_DTAG2,
+ TC27XD_PSPR2,
+ TC27XD_PCACHE2,
+ TC27XD_PTAG2,
+ TC27XD_DSPR1,
+ TC27XD_DCACHE1,
+ TC27XD_DTAG1,
+ TC27XD_PSPR1,
+ TC27XD_PCACHE1,
+ TC27XD_PTAG1,
+ TC27XD_DSPR0,
+ TC27XD_PSPR0,
+ TC27XD_PCACHE0,
+ TC27XD_PTAG0,
+ TC27XD_PFLASH0_C,
+ TC27XD_PFLASH1_C,
+ TC27XD_OLDA_C,
+ TC27XD_BROM_C,
+ TC27XD_LMURAM_C,
+ TC27XD_EMEM_C,
+ TC27XD_PFLASH0_U,
+ TC27XD_PFLASH1_U,
+ TC27XD_DFLASH0,
+ TC27XD_DFLASH1,
+ TC27XD_OLDA_U,
+ TC27XD_BROM_U,
+ TC27XD_LMURAM_U,
+ TC27XD_EMEM_U,
+ TC27XD_PSPRX,
+ TC27XD_DSPRX,
+};
+
+#endif
diff --git a/include/hw/tricore/triboard.h b/include/hw/tricore/triboard.h
new file mode 100644
index 0000000000..f3844be447
--- /dev/null
+++ b/include/hw/tricore/triboard.h
@@ -0,0 +1,50 @@
+/*
+ * Infineon TriBoard System emulation.
+ *
+ * Copyright (c) 2020 Andreas Konopik <andreas.konopik@efs-auto.de>
+ * Copyright (c) 2020 David Brenken <david.brenken@efs-auto.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/arm/boot.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+#include "qom/object.h"
+
+#include "hw/tricore/tc27x_soc.h"
+
+#define TYPE_TRIBOARD_MACHINE MACHINE_TYPE_NAME("triboard")
+typedef struct TriBoardMachineState TriBoardMachineState;
+typedef struct TriBoardMachineClass TriBoardMachineClass;
+DECLARE_OBJ_CHECKERS(TriBoardMachineState, TriBoardMachineClass,
+ TRIBOARD_MACHINE, TYPE_TRIBOARD_MACHINE)
+
+
+struct TriBoardMachineState {
+ MachineState parent;
+
+ TC27XSoCState tc27x_soc;
+};
+
+struct TriBoardMachineClass {
+ MachineClass parent_obj;
+
+ const char *name;
+ const char *desc;
+ const char *soc_name;
+};
diff --git a/include/hw/usb.h b/include/hw/usb.h
index abfbfc5284..436e07b304 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -216,7 +216,6 @@ struct USBEndpoint {
};
enum USBDeviceFlags {
- USB_DEV_FLAG_FULL_PATH,
USB_DEV_FLAG_IS_HOST,
USB_DEV_FLAG_MSOS_DESC_ENABLE,
USB_DEV_FLAG_MSOS_DESC_IN_USE,
@@ -500,7 +499,7 @@ void usb_bus_new(USBBus *bus, size_t bus_size,
void usb_bus_release(USBBus *bus);
USBBus *usb_bus_find(int busnr);
void usb_legacy_register(const char *typename, const char *usbdevice_name,
- USBDevice *(*usbdevice_init)(const char *params));
+ USBDevice *(*usbdevice_init)(void));
USBDevice *usb_new(const char *name);
bool usb_realize_and_unref(USBDevice *dev, USBBus *bus, Error **errp);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
diff --git a/include/hw/usb/msd.h b/include/hw/usb/msd.h
new file mode 100644
index 0000000000..7538c54569
--- /dev/null
+++ b/include/hw/usb/msd.h
@@ -0,0 +1,54 @@
+/*
+ * USB Mass Storage Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "hw/usb.h"
+#include "hw/scsi/scsi.h"
+
+enum USBMSDMode {
+ USB_MSDM_CBW, /* Command Block. */
+ USB_MSDM_DATAOUT, /* Transfer data to device. */
+ USB_MSDM_DATAIN, /* Transfer data from device. */
+ USB_MSDM_CSW /* Command Status. */
+};
+
+struct usb_msd_csw {
+ uint32_t sig;
+ uint32_t tag;
+ uint32_t residue;
+ uint8_t status;
+};
+
+struct MSDState {
+ USBDevice dev;
+ enum USBMSDMode mode;
+ uint32_t scsi_off;
+ uint32_t scsi_len;
+ uint32_t data_len;
+ struct usb_msd_csw csw;
+ SCSIRequest *req;
+ SCSIBus bus;
+ /* For async completion. */
+ USBPacket *packet;
+ /* usb-storage only */
+ BlockConf conf;
+ bool removable;
+ bool commandlog;
+ SCSIDevice *scsi_dev;
+};
+
+typedef struct MSDState MSDState;
+#define TYPE_USB_STORAGE "usb-storage-dev"
+DECLARE_INSTANCE_CHECKER(MSDState, USB_STORAGE_DEV,
+ TYPE_USB_STORAGE)
+
+void usb_msd_transfer_data(SCSIRequest *req, uint32_t len);
+void usb_msd_command_complete(SCSIRequest *req, size_t resid);
+void usb_msd_request_cancelled(SCSIRequest *req);
+void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req);
+void usb_msd_handle_reset(USBDevice *dev);
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 214ab74822..29655a406d 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -41,6 +41,7 @@ struct VirtIOBlkConf
uint16_t num_queues;
uint16_t queue_size;
bool seg_max_adjust;
+ bool report_discard_granularity;
uint32_t max_discard_sectors;
uint32_t max_write_zeroes_sectors;
bool x_enable_wce_if_config_wce;
diff --git a/include/net/net.h b/include/net/net.h
index 919facaad2..a02949f6db 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -5,6 +5,8 @@
#include "qapi/qapi-types-net.h"
#include "net/queue.h"
#include "hw/qdev-properties-system.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-net.h"
#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
#define MAC_ARG(x) ((uint8_t *)(x))[0], ((uint8_t *)(x))[1], \
@@ -92,7 +94,8 @@ struct NetClientState {
NetQueue *incoming_queue;
char *model;
char *name;
- char info_str[256];
+ char *info_str;
+ NetdevInfo *stored_config;
unsigned receive_disabled : 1;
NetClientDestructor *destructor;
unsigned int queue_index;
@@ -144,12 +147,17 @@ void *qemu_get_nic_opaque(NetClientState *nc);
void qemu_del_net_client(NetClientState *nc);
typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque);
void qemu_foreach_nic(qemu_nic_foreach func, void *opaque);
+int qemu_can_receive_packet(NetClientState *nc);
int qemu_can_send_packet(NetClientState *nc);
ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov,
int iovcnt);
ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov,
int iovcnt, NetPacketSent *sent_cb);
ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size);
+ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size);
+ssize_t qemu_receive_packet_iov(NetClientState *nc,
+ const struct iovec *iov,
+ int iovcnt);
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf,
int size, NetPacketSent *sent_cb);
diff --git a/include/net/queue.h b/include/net/queue.h
index c0269bb1dc..9f2f289d77 100644
--- a/include/net/queue.h
+++ b/include/net/queue.h
@@ -55,6 +55,14 @@ void qemu_net_queue_append_iov(NetQueue *queue,
void qemu_del_net_queue(NetQueue *queue);
+ssize_t qemu_net_queue_receive(NetQueue *queue,
+ const uint8_t *data,
+ size_t size);
+
+ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
+ const struct iovec *iov,
+ int iovcnt);
+
ssize_t qemu_net_queue_send(NetQueue *queue,
NetClientState *sender,
unsigned flags,
diff --git a/include/qapi/hmp-output-visitor.h b/include/qapi/hmp-output-visitor.h
new file mode 100644
index 0000000000..541e4002e3
--- /dev/null
+++ b/include/qapi/hmp-output-visitor.h
@@ -0,0 +1,30 @@
+/*
+ * HMP string output Visitor
+ *
+ * Copyright Yandex N.V., 2021
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HMP_OUTPUT_VISITOR_H
+#define HMP_OUTPUT_VISITOR_H
+
+#include "qapi/visitor.h"
+
+typedef struct HMPOutputVisitor HMPOutputVisitor;
+
+/**
+ * Create a HMP string output visitor for @obj
+ *
+ * Flattens dicts/structures, only shows arrays borders.
+ *
+ * Errors are not expected to happen.
+ *
+ * The caller is responsible for freeing the visitor with
+ * visit_free().
+ */
+Visitor *hmp_output_visitor_new(char **result);
+
+#endif
diff --git a/include/standard-headers/asm-m68k/bootinfo-virt.h b/include/standard-headers/asm-m68k/bootinfo-virt.h
new file mode 100644
index 0000000000..81be1e0924
--- /dev/null
+++ b/include/standard-headers/asm-m68k/bootinfo-virt.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+** asm/bootinfo-virt.h -- Virtual-m68k-specific boot information definitions
+*/
+
+#ifndef _UAPI_ASM_M68K_BOOTINFO_VIRT_H
+#define _UAPI_ASM_M68K_BOOTINFO_VIRT_H
+
+#define BI_VIRT_QEMU_VERSION 0x8000
+#define BI_VIRT_GF_PIC_BASE 0x8001
+#define BI_VIRT_GF_RTC_BASE 0x8002
+#define BI_VIRT_GF_TTY_BASE 0x8003
+#define BI_VIRT_VIRTIO_BASE 0x8004
+#define BI_VIRT_CTRL_BASE 0x8005
+
+#define VIRT_BOOTI_VERSION MK_BI_VERSION(2, 0)
+
+#endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */
diff --git a/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h b/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h
deleted file mode 100644
index 7b4062a1a1..0000000000
--- a/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2012-2016 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of EITHER the GNU General Public License
- * version 2 as published by the Free Software Foundation or the BSD
- * 2-Clause License. This program is distributed in the hope that 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 version 2 for more details at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program available in the file COPYING in the main
- * directory of this source tree.
- *
- * The BSD 2-Clause License
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __PVRDMA_RING_H__
-#define __PVRDMA_RING_H__
-
-#include "standard-headers/linux/types.h"
-
-#define PVRDMA_INVALID_IDX -1 /* Invalid index. */
-
-struct pvrdma_ring {
- int prod_tail; /* Producer tail. */
- int cons_head; /* Consumer head. */
-};
-
-struct pvrdma_ring_state {
- struct pvrdma_ring tx; /* Tx ring. */
- struct pvrdma_ring rx; /* Rx ring. */
-};
-
-static inline int pvrdma_idx_valid(uint32_t idx, uint32_t max_elems)
-{
- /* Generates fewer instructions than a less-than. */
- return (idx & ~((max_elems << 1) - 1)) == 0;
-}
-
-static inline int32_t pvrdma_idx(int *var, uint32_t max_elems)
-{
- const unsigned int idx = qatomic_read(var);
-
- if (pvrdma_idx_valid(idx, max_elems))
- return idx & (max_elems - 1);
- return PVRDMA_INVALID_IDX;
-}
-
-static inline void pvrdma_idx_ring_inc(int *var, uint32_t max_elems)
-{
- uint32_t idx = qatomic_read(var) + 1; /* Increment. */
-
- idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */
- qatomic_set(var, idx);
-}
-
-static inline int32_t pvrdma_idx_ring_has_space(const struct pvrdma_ring *r,
- uint32_t max_elems, uint32_t *out_tail)
-{
- const uint32_t tail = qatomic_read(&r->prod_tail);
- const uint32_t head = qatomic_read(&r->cons_head);
-
- if (pvrdma_idx_valid(tail, max_elems) &&
- pvrdma_idx_valid(head, max_elems)) {
- *out_tail = tail & (max_elems - 1);
- return tail != (head ^ max_elems);
- }
- return PVRDMA_INVALID_IDX;
-}
-
-static inline int32_t pvrdma_idx_ring_has_data(const struct pvrdma_ring *r,
- uint32_t max_elems, uint32_t *out_head)
-{
- const uint32_t tail = qatomic_read(&r->prod_tail);
- const uint32_t head = qatomic_read(&r->cons_head);
-
- if (pvrdma_idx_valid(tail, max_elems) &&
- pvrdma_idx_valid(head, max_elems)) {
- *out_head = head & (max_elems - 1);
- return tail != head;
- }
- return PVRDMA_INVALID_IDX;
-}
-
-#endif /* __PVRDMA_RING_H__ */
diff --git a/migration/migration.c b/migration/migration.c
index a5ddf43559..36768391b6 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -323,7 +323,7 @@ static int migrate_send_rp_message(MigrationIncomingState *mis,
int ret = 0;
trace_migrate_send_rp_message((int)message_type, len);
- qemu_mutex_lock(&mis->rp_mutex);
+ QEMU_LOCK_GUARD(&mis->rp_mutex);
/*
* It's possible that the file handle got lost due to network
@@ -331,7 +331,7 @@ static int migrate_send_rp_message(MigrationIncomingState *mis,
*/
if (!mis->to_src_file) {
ret = -EIO;
- goto error;
+ return ret;
}
qemu_put_be16(mis->to_src_file, (unsigned int)message_type);
@@ -342,8 +342,6 @@ static int migrate_send_rp_message(MigrationIncomingState *mis,
/* It's possible that qemu file got error during sending */
ret = qemu_file_get_error(mis->to_src_file);
-error:
- qemu_mutex_unlock(&mis->rp_mutex);
return ret;
}
diff --git a/migration/multifd.c b/migration/multifd.c
index 1a1e589064..03527c564c 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -739,7 +739,16 @@ static void multifd_tls_outgoing_handshake(QIOTask *task,
} else {
trace_multifd_tls_outgoing_handshake_complete(ioc);
}
- multifd_channel_connect(p, ioc, err);
+
+ if (!multifd_channel_connect(p, ioc, err)) {
+ /*
+ * Error happen, mark multifd_send_thread status as 'quit' although it
+ * is not created, and then tell who pay attention to me.
+ */
+ p->quit = true;
+ qemu_sem_post(&multifd_send_state->channels_ready);
+ qemu_sem_post(&p->sem_sync);
+ }
}
static void *multifd_tls_handshake_thread(void *opaque)
@@ -798,9 +807,9 @@ static bool multifd_channel_connect(MultiFDSendParams *p,
* function after the TLS handshake,
* so we mustn't call multifd_send_thread until then
*/
- return false;
- } else {
return true;
+ } else {
+ return false;
}
} else {
/* update for tls qio channel */
@@ -808,10 +817,10 @@ static bool multifd_channel_connect(MultiFDSendParams *p,
qemu_thread_create(&p->thread, p->name, multifd_send_thread, p,
QEMU_THREAD_JOINABLE);
}
- return false;
+ return true;
}
- return true;
+ return false;
}
static void multifd_new_send_channel_cleanup(MultiFDSendParams *p,
@@ -844,7 +853,7 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque)
p->c = QIO_CHANNEL(sioc);
qio_channel_set_delay(p->c, false);
p->running = true;
- if (multifd_channel_connect(p, sioc, local_err)) {
+ if (!multifd_channel_connect(p, sioc, local_err)) {
goto cleanup;
}
return;
diff --git a/migration/ram.c b/migration/ram.c
index 72143da0ac..52537f14ac 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -819,7 +819,7 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
{
bool ret;
- qemu_mutex_lock(&rs->bitmap_mutex);
+ QEMU_LOCK_GUARD(&rs->bitmap_mutex);
/*
* Clear dirty bitmap if needed. This _must_ be called before we
@@ -852,7 +852,6 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
if (ret) {
rs->migration_dirty_pages--;
}
- qemu_mutex_unlock(&rs->bitmap_mutex);
return ret;
}
@@ -3275,7 +3274,7 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
int idx, thread_count;
thread_count = migrate_decompress_threads();
- qemu_mutex_lock(&decomp_done_lock);
+ QEMU_LOCK_GUARD(&decomp_done_lock);
while (true) {
for (idx = 0; idx < thread_count; idx++) {
if (decomp_param[idx].done) {
@@ -3295,7 +3294,6 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
qemu_cond_wait(&decomp_done_cond, &decomp_done_lock);
}
}
- qemu_mutex_unlock(&decomp_done_lock);
}
/*
diff --git a/monitor/monitor.c b/monitor/monitor.c
index e94f532cf5..640496e562 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -349,7 +349,7 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
evconf = &monitor_qapi_event_conf[event];
trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
- qemu_mutex_lock(&monitor_lock);
+ QEMU_LOCK_GUARD(&monitor_lock);
if (!evconf->rate) {
/* Unthrottled event */
@@ -391,8 +391,6 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
timer_mod_ns(evstate->timer, now + evconf->rate);
}
}
-
- qemu_mutex_unlock(&monitor_lock);
}
void qapi_event_emit(QAPIEvent event, QDict *qdict)
@@ -447,7 +445,7 @@ static void monitor_qapi_event_handler(void *opaque)
MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
- qemu_mutex_lock(&monitor_lock);
+ QEMU_LOCK_GUARD(&monitor_lock);
if (evstate->qdict) {
int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
@@ -462,8 +460,6 @@ static void monitor_qapi_event_handler(void *opaque)
timer_free(evstate->timer);
g_free(evstate);
}
-
- qemu_mutex_unlock(&monitor_lock);
}
static unsigned int qapi_event_throttle_hash(const void *key)
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 2326bd7f9b..2b0308f933 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -76,7 +76,7 @@ static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon)
static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
{
- qemu_mutex_lock(&mon->qmp_queue_lock);
+ QEMU_LOCK_GUARD(&mon->qmp_queue_lock);
/*
* Same condition as in monitor_qmp_dispatcher_co(), but before
@@ -103,7 +103,6 @@ static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
monitor_resume(&mon->common);
}
- qemu_mutex_unlock(&mon->qmp_queue_lock);
}
void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
@@ -179,7 +178,7 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
Monitor *mon;
MonitorQMP *qmp_mon;
- qemu_mutex_lock(&monitor_lock);
+ QEMU_LOCK_GUARD(&monitor_lock);
QTAILQ_FOREACH(mon, &mon_list, entry) {
if (!monitor_is_qmp(mon)) {
@@ -205,8 +204,6 @@ static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
QTAILQ_INSERT_TAIL(&mon_list, mon, entry);
}
- qemu_mutex_unlock(&monitor_lock);
-
return req_obj;
}
@@ -376,30 +373,30 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
req_obj->err = err;
/* Protect qmp_requests and fetching its length. */
- qemu_mutex_lock(&mon->qmp_queue_lock);
+ WITH_QEMU_LOCK_GUARD(&mon->qmp_queue_lock) {
- /*
- * Suspend the monitor when we can't queue more requests after
- * this one. Dequeuing in monitor_qmp_dispatcher_co() or
- * monitor_qmp_cleanup_queue_and_resume() will resume it.
- * Note that when OOB is disabled, we queue at most one command,
- * for backward compatibility.
- */
- if (!qmp_oob_enabled(mon) ||
- mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
- monitor_suspend(&mon->common);
- }
+ /*
+ * Suspend the monitor when we can't queue more requests after
+ * this one. Dequeuing in monitor_qmp_dispatcher_co() or
+ * monitor_qmp_cleanup_queue_and_resume() will resume it.
+ * Note that when OOB is disabled, we queue at most one command,
+ * for backward compatibility.
+ */
+ if (!qmp_oob_enabled(mon) ||
+ mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
+ monitor_suspend(&mon->common);
+ }
- /*
- * Put the request to the end of queue so that requests will be
- * handled in time order. Ownership for req_obj, req,
- * etc. will be delivered to the handler side.
- */
- trace_monitor_qmp_in_band_enqueue(req_obj, mon,
- mon->qmp_requests->length);
- assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
- g_queue_push_tail(mon->qmp_requests, req_obj);
- qemu_mutex_unlock(&mon->qmp_queue_lock);
+ /*
+ * Put the request to the end of queue so that requests will be
+ * handled in time order. Ownership for req_obj, req,
+ * etc. will be delivered to the handler side.
+ */
+ trace_monitor_qmp_in_band_enqueue(req_obj, mon,
+ mon->qmp_requests->length);
+ assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
+ g_queue_push_tail(mon->qmp_requests, req_obj);
+ }
/* Kick the dispatcher routine */
if (!qatomic_xchg(&qmp_dispatcher_co_busy, true)) {
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index e4d4218db6..b7e1d84674 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -723,8 +723,12 @@ int net_init_l2tpv3(const Netdev *netdev,
l2tpv3_read_poll(s, true);
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "l2tpv3: connected");
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_L2TPV3;
+
+ QAPI_CLONE_MEMBERS(NetdevL2TPv3Options,
+ &nc->stored_config->u.l2tpv3, l2tpv3);
return 0;
outerr:
qemu_del_net_client(nc);
diff --git a/net/net.c b/net/net.c
index 9a2a4c99a5..725a4e1450 100644
--- a/net/net.c
+++ b/net/net.c
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu-common.h"
#include "net/net.h"
#include "clients.h"
@@ -35,7 +36,6 @@
#include "monitor/monitor.h"
#include "qemu/help_option.h"
#include "qapi/qapi-commands-net.h"
-#include "qapi/qapi-visit-net.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
@@ -55,6 +55,7 @@
#include "sysemu/sysemu.h"
#include "net/filter.h"
#include "qapi/string-output-visitor.h"
+#include "qapi/hmp-output-visitor.h"
/* Net bridge is currently not supported for W32. */
#if !defined(_WIN32)
@@ -129,11 +130,12 @@ char *qemu_mac_strdup_printf(const uint8_t *macaddr)
void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6])
{
- snprintf(nc->info_str, sizeof(nc->info_str),
- "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
- nc->model,
- macaddr[0], macaddr[1], macaddr[2],
- macaddr[3], macaddr[4], macaddr[5]);
+ g_free(nc->info_str);
+ nc->info_str = g_strdup_printf(
+ "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ nc->model,
+ macaddr[0], macaddr[1], macaddr[2],
+ macaddr[3], macaddr[4], macaddr[5]);
}
static int mac_table[256] = {0};
@@ -352,6 +354,8 @@ static void qemu_free_net_client(NetClientState *nc)
}
g_free(nc->name);
g_free(nc->model);
+ g_free(nc->info_str);
+ qapi_free_NetdevInfo(nc->stored_config);
if (nc->destructor) {
nc->destructor(nc);
}
@@ -528,6 +532,17 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be)
#endif
}
+int qemu_can_receive_packet(NetClientState *nc)
+{
+ if (nc->receive_disabled) {
+ return 0;
+ } else if (nc->info->can_receive &&
+ !nc->info->can_receive(nc)) {
+ return 0;
+ }
+ return 1;
+}
+
int qemu_can_send_packet(NetClientState *sender)
{
int vm_running = runstate_is_running();
@@ -540,13 +555,7 @@ int qemu_can_send_packet(NetClientState *sender)
return 1;
}
- if (sender->peer->receive_disabled) {
- return 0;
- } else if (sender->peer->info->can_receive &&
- !sender->peer->info->can_receive(sender->peer)) {
- return 0;
- }
- return 1;
+ return qemu_can_receive_packet(sender->peer);
}
static ssize_t filter_receive_iov(NetClientState *nc,
@@ -679,6 +688,25 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
return qemu_send_packet_async(nc, buf, size, NULL);
}
+ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size)
+{
+ if (!qemu_can_receive_packet(nc)) {
+ return 0;
+ }
+
+ return qemu_net_queue_receive(nc->incoming_queue, buf, size);
+}
+
+ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov,
+ int iovcnt)
+{
+ if (!qemu_can_receive_packet(nc)) {
+ return 0;
+ }
+
+ return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt);
+}
+
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size)
{
return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW,
@@ -1133,6 +1161,11 @@ void netdev_add(QemuOpts *opts, Error **errp)
void qmp_netdev_add(Netdev *netdev, Error **errp)
{
+ if (!id_wellformed(netdev->id)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+ return;
+ }
+
net_client_init1(netdev, true, errp);
}
@@ -1189,14 +1222,42 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
monitor_printf(mon, "\n");
}
+static char *generate_info_str(NetClientState *nc)
+{
+ NetdevInfo *ni = nc->stored_config;
+ char *ret_out = NULL;
+ Visitor *v;
+
+ /* Use legacy field info_str for NIC and hubports */
+ if ((nc->info->type == NET_CLIENT_DRIVER_NIC) ||
+ (nc->info->type == NET_CLIENT_DRIVER_HUBPORT)) {
+ return g_strdup(nc->info_str ? nc->info_str : "");
+ }
+
+ if (!ni) {
+ return g_malloc0(1);
+ }
+
+ v = hmp_output_visitor_new(&ret_out);
+ if (visit_type_NetdevInfo(v, "", &ni, NULL)) {
+ visit_complete(v, &ret_out);
+ }
+ visit_free(v);
+
+ return ret_out;
+}
+
void print_net_client(Monitor *mon, NetClientState *nc)
{
NetFilterState *nf;
+ char *info_str = generate_info_str(nc);
monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name,
nc->queue_index,
NetClientDriver_str(nc->info->type),
- nc->info_str);
+ info_str);
+ g_free(info_str);
+
if (!QTAILQ_EMPTY(&nc->filters)) {
monitor_printf(mon, "filters:\n");
}
@@ -1259,6 +1320,34 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
return filter_list;
}
+NetdevInfoList *qmp_query_netdev(Error **errp)
+{
+ NetdevInfoList *list = NULL;
+ NetClientState *nc;
+
+ QTAILQ_FOREACH(nc, &net_clients, next) {
+ /*
+ * Only look at netdevs (backend network devices), not for each queue
+ * or NIC / hubport
+ */
+ if (nc->stored_config) {
+ NetdevInfo *element = QAPI_CLONE(NetdevInfo, nc->stored_config);
+
+ g_free(element->id); /* Need to dealloc empty id after clone */
+ element->id = g_strdup(nc->name);
+
+ element->has_peer_id = nc->peer != NULL;
+ if (element->has_peer_id) {
+ element->peer_id = g_strdup(nc->peer->name);
+ }
+
+ QAPI_LIST_PREPEND(list, element);
+ }
+ }
+
+ return list;
+}
+
void hmp_info_network(Monitor *mon, const QDict *qdict)
{
NetClientState *nc, *peer;
diff --git a/net/netmap.c b/net/netmap.c
index 350f097f91..ad59d4ade4 100644
--- a/net/netmap.c
+++ b/net/netmap.c
@@ -427,6 +427,13 @@ int net_init_netmap(const Netdev *netdev,
pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname);
netmap_read_poll(s, true); /* Initially only poll for reads. */
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_NETMAP;
+
+ QAPI_CLONE_MEMBERS(NetdevNetmapOptions,
+ &nc->stored_config->u.netmap, netmap_opts);
+
return 0;
}
diff --git a/net/queue.c b/net/queue.c
index 19e32c80fd..c872d51df8 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -182,6 +182,28 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
return ret;
}
+ssize_t qemu_net_queue_receive(NetQueue *queue,
+ const uint8_t *data,
+ size_t size)
+{
+ if (queue->delivering) {
+ return 0;
+ }
+
+ return qemu_net_queue_deliver(queue, NULL, 0, data, size);
+}
+
+ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
+ const struct iovec *iov,
+ int iovcnt)
+{
+ if (queue->delivering) {
+ return 0;
+ }
+
+ return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt);
+}
+
ssize_t qemu_net_queue_send(NetQueue *queue,
NetClientState *sender,
unsigned flags,
diff --git a/net/slirp.c b/net/slirp.c
index be914c0be0..9454a673d6 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -377,6 +377,9 @@ static int net_slirp_init(NetClientState *peer, const char *model,
int shift;
char *end;
struct slirp_config_str *config;
+ NetdevUserOptions *stored;
+ StringList **stored_hostfwd;
+ StringList **stored_guestfwd;
if (!ipv4 && (vnetwork || vhost || vnameserver)) {
error_setg(errp, "IPv4 disabled but netmask/host/dns provided");
@@ -552,9 +555,114 @@ static int net_slirp_init(NetClientState *peer, const char *model,
nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
- snprintf(nc->info_str, sizeof(nc->info_str),
- "net=%s,restrict=%s", inet_ntoa(net),
- restricted ? "on" : "off");
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_USER;
+ stored = &nc->stored_config->u.user;
+
+ if (vhostname) {
+ stored->has_hostname = true;
+ stored->hostname = g_strdup(vhostname);
+ }
+
+ stored->has_q_restrict = true;
+ stored->q_restrict = restricted;
+
+ stored->has_ipv4 = true;
+ stored->ipv4 = ipv4;
+
+ stored->has_ipv6 = true;
+ stored->ipv6 = ipv6;
+
+ if (ipv4) {
+ uint8_t *net_bytes = (uint8_t *)&net;
+ uint8_t *mask_bytes = (uint8_t *)&mask;
+
+ stored->has_net = true;
+ stored->net = g_strdup_printf("%d.%d.%d.%d/%d.%d.%d.%d",
+ net_bytes[0], net_bytes[1],
+ net_bytes[2], net_bytes[3],
+ mask_bytes[0], mask_bytes[1],
+ mask_bytes[2], mask_bytes[3]);
+
+ stored->has_host = true;
+ stored->host = g_strdup(inet_ntoa(host));
+ }
+
+ if (tftp_export) {
+ stored->has_tftp = true;
+ stored->tftp = g_strdup(tftp_export);
+ }
+
+ if (bootfile) {
+ stored->has_bootfile = true;
+ stored->bootfile = g_strdup(bootfile);
+ }
+
+ if (vdhcp_start) {
+ stored->has_dhcpstart = true;
+ stored->dhcpstart = g_strdup(vdhcp_start);
+ }
+
+ if (ipv4) {
+ stored->has_dns = true;
+ stored->dns = g_strdup(inet_ntoa(dns));
+ }
+
+ if (dnssearch) {
+ stored->has_dnssearch = true;
+ StringList **stored_list = &stored->dnssearch;
+
+ for (int i = 0; dnssearch[i]; i++) {
+ String *element = g_new0(String, 1);
+
+ element->str = g_strdup(dnssearch[i]);
+ QAPI_LIST_APPEND(stored_list, element);
+ }
+ }
+
+ if (vdomainname) {
+ stored->has_domainname = true;
+ stored->domainname = g_strdup(vdomainname);
+ }
+
+ if (ipv6) {
+ char addrstr[INET6_ADDRSTRLEN];
+ const char *res;
+
+ stored->has_ipv6_prefix = true;
+ stored->ipv6_prefix = g_strdup(vprefix6);
+
+ stored->has_ipv6_prefixlen = true;
+ stored->ipv6_prefixlen = vprefix6_len;
+
+ res = inet_ntop(AF_INET6, &ip6_host,
+ addrstr, sizeof(addrstr));
+
+ stored->has_ipv6_host = true;
+ stored->ipv6_host = g_strdup(res);
+
+ res = inet_ntop(AF_INET6, &ip6_dns,
+ addrstr, sizeof(addrstr));
+
+ stored->has_ipv6_dns = true;
+ stored->ipv6_dns = g_strdup(res);
+ }
+
+ if (smb_export) {
+ stored->has_smb = true;
+ stored->smb = g_strdup(smb_export);
+ }
+
+ if (vsmbserver) {
+ stored->has_smbserver = true;
+ stored->smbserver = g_strdup(vsmbserver);
+ }
+
+ if (tftp_server_name) {
+ stored->has_tftp_server_name = true;
+ stored->tftp_server_name = g_strdup(tftp_server_name);
+ }
s = DO_UPCAST(SlirpState, nc, nc);
@@ -581,15 +689,25 @@ static int net_slirp_init(NetClientState *peer, const char *model,
s->poll_notifier.notify = net_slirp_poll_notify;
main_loop_poll_add_notifier(&s->poll_notifier);
+ stored_hostfwd = &stored->hostfwd;
+ stored_guestfwd = &stored->guestfwd;
+
for (config = slirp_configs; config; config = config->next) {
+ String *element = g_new0(String, 1);
+
+ element->str = g_strdup(config->str);
if (config->flags & SLIRP_CFG_HOSTFWD) {
if (slirp_hostfwd(s, config->str, errp) < 0) {
goto error;
}
+ stored->has_hostfwd = true;
+ QAPI_LIST_APPEND(stored_hostfwd, element);
} else {
if (slirp_guestfwd(s, config->str, errp) < 0) {
goto error;
}
+ stored->has_guestfwd = true;
+ QAPI_LIST_APPEND(stored_guestfwd, element);
}
}
#ifndef _WIN32
diff --git a/net/socket.c b/net/socket.c
index 15b410e8d8..c0de10c0c0 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -180,7 +180,6 @@ static void net_socket_send(void *opaque)
s->fd = -1;
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
s->nc.link_down = true;
- memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
return;
}
@@ -342,6 +341,7 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
NetSocketState *s;
SocketAddress *sa;
SocketAddressType sa_type;
+ NetdevSocketOptions *stored;
sa = socket_local_address(fd, errp);
if (!sa) {
@@ -385,19 +385,24 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
net_socket_read_poll(s, true);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_SOCKET;
+ stored = &nc->stored_config->u.socket;
+
+ stored->has_fd = true;
+ stored->fd = g_strdup_printf("%d", fd);
+
/* mcast: save bound address as dst */
if (is_connected && mcast != NULL) {
+ stored->has_mcast = true;
+ stored->mcast = g_strdup(mcast);
+
s->dgram_dst = saddr;
- snprintf(nc->info_str, sizeof(nc->info_str),
- "socket: fd=%d (cloned mcast=%s:%d)",
- fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
} else {
if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) {
s->dgram_dst.sin_family = AF_UNIX;
}
-
- snprintf(nc->info_str, sizeof(nc->info_str),
- "socket: fd=%d %s", fd, SocketAddressType_str(sa_type));
}
return s;
@@ -428,11 +433,10 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
{
NetClientState *nc;
NetSocketState *s;
+ NetdevSocketOptions *stored;
nc = qemu_new_net_client(&net_socket_info, peer, model, name);
- snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
-
s = DO_UPCAST(NetSocketState, nc, nc);
s->fd = fd;
@@ -447,6 +451,15 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
} else {
qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
}
+
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_SOCKET;
+ stored = &nc->stored_config->u.socket;
+
+ stored->has_fd = true;
+ stored->fd = g_strdup_printf("%d", fd);
+
return s;
}
@@ -483,6 +496,7 @@ static void net_socket_accept(void *opaque)
struct sockaddr_in saddr;
socklen_t len;
int fd;
+ NetdevSocketOptions *stored;
for(;;) {
len = sizeof(saddr);
@@ -498,9 +512,12 @@ static void net_socket_accept(void *opaque)
s->fd = fd;
s->nc.link_down = false;
net_socket_connect(s);
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "socket: connection from %s:%d",
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+
+ /* Store additional startup parameters (extend net_socket_listen_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ stored->has_fd = true;
+ stored->fd = g_strdup_printf("%d", fd);
}
static int net_socket_listen_init(NetClientState *peer,
@@ -513,6 +530,7 @@ static int net_socket_listen_init(NetClientState *peer,
NetSocketState *s;
struct sockaddr_in saddr;
int fd, ret;
+ NetdevSocketOptions *stored;
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
@@ -549,6 +567,15 @@ static int net_socket_listen_init(NetClientState *peer,
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
+
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_SOCKET;
+ stored = &nc->stored_config->u.socket;
+
+ stored->has_listen = true;
+ stored->listen = g_strdup(host_str);
+
return 0;
}
@@ -561,6 +588,7 @@ static int net_socket_connect_init(NetClientState *peer,
NetSocketState *s;
int fd, connected, ret;
struct sockaddr_in saddr;
+ NetdevSocketOptions *stored;
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
@@ -598,9 +626,12 @@ static int net_socket_connect_init(NetClientState *peer,
return -1;
}
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "socket: connect to %s:%d",
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+ /* Store additional startup parameters (extend net_socket_fd_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ stored->has_connect = true;
+ stored->connect = g_strdup(host_str);
+
return 0;
}
@@ -615,6 +646,7 @@ static int net_socket_mcast_init(NetClientState *peer,
int fd;
struct sockaddr_in saddr;
struct in_addr localaddr, *param_localaddr;
+ NetdevSocketOptions *stored;
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
@@ -643,11 +675,20 @@ static int net_socket_mcast_init(NetClientState *peer,
s->dgram_dst = saddr;
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "socket: mcast=%s:%d",
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
- return 0;
+ /* Store additional startup parameters (extend net_socket_fd_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ if (!stored->has_mcast) {
+ stored->has_mcast = true;
+ stored->mcast = g_strdup(host_str);
+ }
+ if (localaddr_str) {
+ stored->has_localaddr = true;
+ stored->localaddr = g_strdup(localaddr_str);
+ }
+
+ return 0;
}
static int net_socket_udp_init(NetClientState *peer,
@@ -660,6 +701,7 @@ static int net_socket_udp_init(NetClientState *peer,
NetSocketState *s;
int fd, ret;
struct sockaddr_in laddr, raddr;
+ NetdevSocketOptions *stored;
if (parse_host_port(&laddr, lhost, errp) < 0) {
return -1;
@@ -698,9 +740,15 @@ static int net_socket_udp_init(NetClientState *peer,
s->dgram_dst = raddr;
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "socket: udp=%s:%d",
- inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
+ /* Store additional startup parameters (extend net_socket_fd_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ stored->has_localaddr = true;
+ stored->localaddr = g_strdup(lhost);
+
+ stored->has_udp = true;
+ stored->udp = g_strdup(rhost);
+
return 0;
}
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 2b5dcda36e..21e451107b 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -768,6 +768,7 @@ static int tap_win32_init(NetClientState *peer, const char *model,
NetClientState *nc;
TAPState *s;
tap_win32_overlapped_t *handle;
+ NetdevTapOptions *stored;
if (tap_win32_open(&handle, ifname) < 0) {
printf("tap: Could not open '%s'\n", ifname);
@@ -778,8 +779,13 @@ static int tap_win32_init(NetClientState *peer, const char *model,
s = DO_UPCAST(TAPState, nc, nc);
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "tap: ifname=%s", ifname);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_TAP;
+ stored = &nc->stored_config->u.tap;
+
+ stored->has_ifname = true;
+ stored->ifname = g_strdup(ifname);
s->handle = handle;
diff --git a/net/tap.c b/net/tap.c
index b7512853f4..12a08d54fe 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -590,6 +590,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
const char *helper, *br;
TAPState *s;
int fd, vnet_hdr;
+ NetdevBridgeOptions *stored;
assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE);
bridge = &netdev->u.bridge;
@@ -609,8 +610,20 @@ int net_init_bridge(const Netdev *netdev, const char *name,
}
s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
- snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper,
- br);
+ /* Store startup parameters */
+ s->nc.stored_config = g_new0(NetdevInfo, 1);
+ s->nc.stored_config->type = NET_BACKEND_BRIDGE;
+ stored = &s->nc.stored_config->u.bridge;
+
+ if (br) {
+ stored->has_br = true;
+ stored->br = g_strdup(br);
+ }
+
+ if (helper) {
+ stored->has_helper = true;
+ stored->helper = g_strdup(helper);
+ }
return 0;
}
@@ -656,11 +669,13 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
const char *model, const char *name,
const char *ifname, const char *script,
const char *downscript, const char *vhostfdname,
- int vnet_hdr, int fd, Error **errp)
+ int vnet_hdr, int fd, NetdevInfo **common_stored,
+ Error **errp)
{
Error *err = NULL;
TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr);
int vhostfd;
+ NetdevTapOptions *stored;
tap_set_sndbuf(s->fd, tap, &err);
if (err) {
@@ -668,15 +683,59 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
return;
}
+ /* Store startup parameters */
+ if (!*common_stored) {
+ *common_stored = g_new0(NetdevInfo, 1);
+ (*common_stored)->type = NET_BACKEND_TAP;
+ s->nc.stored_config = *common_stored;
+ }
+ stored = &(*common_stored)->u.tap;
+
+ if (tap->has_sndbuf && !stored->has_sndbuf) {
+ stored->has_sndbuf = true;
+ stored->sndbuf = tap->sndbuf;
+ }
+
+ if (vnet_hdr && !stored->has_vnet_hdr) {
+ stored->has_vnet_hdr = true;
+ stored->vnet_hdr = true;
+ }
+
if (tap->has_fd || tap->has_fds) {
- snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
+ if (!stored->has_fds) {
+ stored->has_fds = true;
+ stored->fds = g_strdup_printf("%d", fd);
+ } else {
+ char *tmp_s = stored->fds;
+ stored->fds = g_strdup_printf("%s:%d", stored->fds, fd);
+ g_free(tmp_s);
+ }
} else if (tap->has_helper) {
- snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s",
- tap->helper);
+ if (!stored->has_helper) {
+ stored->has_helper = true;
+ stored->helper = g_strdup(tap->helper);
+ }
+
+ if (!stored->has_br) {
+ stored->has_br = true;
+ stored->br = tap->has_br ? g_strdup(tap->br) :
+ g_strdup(DEFAULT_BRIDGE_INTERFACE);
+ }
} else {
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
- "ifname=%s,script=%s,downscript=%s", ifname, script,
- downscript);
+ if (ifname && !stored->has_ifname) {
+ stored->has_ifname = true;
+ stored->ifname = g_strdup(ifname);
+ }
+
+ if (script && !stored->has_script) {
+ stored->has_script = true;
+ stored->script = g_strdup(script);
+ }
+
+ if (downscript && !stored->has_downscript) {
+ stored->has_downscript = true;
+ stored->downscript = g_strdup(downscript);
+ }
if (strcmp(downscript, "no") != 0) {
snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
@@ -689,9 +748,20 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
VhostNetOptions options;
+ stored->has_vhost = true;
+ stored->vhost = true;
+
+ if (tap->has_vhostforce && tap->vhostforce) {
+ stored->has_vhostforce = true;
+ stored->vhostforce = true;
+ }
+
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
options.net_backend = &s->nc;
if (tap->has_poll_us) {
+ stored->has_poll_us = true;
+ stored->poll_us = tap->poll_us;
+
options.busyloop_timeout = tap->poll_us;
} else {
options.busyloop_timeout = 0;
@@ -731,6 +801,15 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
}
options.opaque = (void *)(uintptr_t)vhostfd;
+ if (!stored->has_vhostfds) {
+ stored->has_vhostfds = true;
+ stored->vhostfds = g_strdup_printf("%d", vhostfd);
+ } else {
+ char *tmp_s = stored->vhostfds;
+ stored->vhostfds = g_strdup_printf("%s:%d", stored->fds, vhostfd);
+ g_free(tmp_s);
+ }
+
s->vhost_net = vhost_net_init(&options);
if (!s->vhost_net) {
if (tap->has_vhostforce && tap->vhostforce) {
@@ -783,6 +862,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
const char *vhostfdname;
char ifname[128];
int ret = 0;
+ NetdevInfo *common_stored = NULL; /* will store configuration */
assert(netdev->type == NET_CLIENT_DRIVER_TAP);
tap = &netdev->u.tap;
@@ -829,7 +909,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
net_init_tap_one(tap, peer, "tap", name, NULL,
script, downscript,
- vhostfdname, vnet_hdr, fd, &err);
+ vhostfdname, vnet_hdr, fd, &common_stored, &err);
if (err) {
error_propagate(errp, err);
close(fd);
@@ -892,7 +972,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
net_init_tap_one(tap, peer, "tap", name, ifname,
script, downscript,
tap->has_vhostfds ? vhost_fds[i] : NULL,
- vnet_hdr, fd, &err);
+ vnet_hdr, fd, &common_stored, &err);
if (err) {
error_propagate(errp, err);
ret = -1;
@@ -935,7 +1015,7 @@ free_fail:
net_init_tap_one(tap, peer, "bridge", name, ifname,
script, downscript, vhostfdname,
- vnet_hdr, fd, &err);
+ vnet_hdr, fd, &common_stored, &err);
if (err) {
error_propagate(errp, err);
close(fd);
@@ -981,7 +1061,8 @@ free_fail:
net_init_tap_one(tap, peer, "tap", name, ifname,
i >= 1 ? "no" : script,
i >= 1 ? "no" : downscript,
- vhostfdname, vnet_hdr, fd, &err);
+ vhostfdname, vnet_hdr, fd,
+ &common_stored, &err);
if (err) {
error_propagate(errp, err);
close(fd);
diff --git a/net/vde.c b/net/vde.c
index 99189cccb6..64bdb937ca 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -84,6 +84,7 @@ static int net_vde_init(NetClientState *peer, const char *model,
VDECONN *vde;
char *init_group = (char *)group;
char *init_sock = (char *)sock;
+ NetdevVdeOptions *stored;
struct vde_open_args args = {
.port = port,
@@ -99,15 +100,33 @@ static int net_vde_init(NetClientState *peer, const char *model,
nc = qemu_new_net_client(&net_vde_info, peer, model, name);
- snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d",
- sock, vde_datafd(vde));
-
s = DO_UPCAST(VDEState, nc, nc);
s->vde = vde;
qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_VDE;
+ stored = &nc->stored_config->u.vde;
+
+ if (sock) {
+ stored->has_sock = true;
+ stored->sock = g_strdup(sock);
+ }
+
+ stored->has_port = true;
+ stored->port = port;
+
+ if (group) {
+ stored->has_group = true;
+ stored->group = g_strdup(group);
+ }
+
+ stored->has_mode = true;
+ stored->mode = mode;
+
return 0;
}
diff --git a/net/vhost-user.c b/net/vhost-user.c
index ffbd94d944..e443c4b2b5 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -311,14 +311,15 @@ static void net_vhost_user_event(void *opaque, QEMUChrEvent event)
}
static int net_vhost_user_init(NetClientState *peer, const char *device,
- const char *name, Chardev *chr,
- int queues)
+ const char *name, const char *chardev,
+ Chardev *chr, int queues)
{
Error *err = NULL;
NetClientState *nc, *nc0 = NULL;
NetVhostUserState *s = NULL;
VhostUserState *user;
int i;
+ NetdevVhostUserOptions *stored;
assert(name);
assert(queues > 0);
@@ -326,8 +327,6 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
user = g_new0(struct VhostUserState, 1);
for (i = 0; i < queues; i++) {
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
- snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
- i, chr->label);
nc->queue_index = i;
if (!nc0) {
nc0 = nc;
@@ -355,6 +354,16 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
assert(s->vhost_net);
+ /* Store startup parameters */
+ nc0->stored_config = g_new0(NetdevInfo, 1);
+ nc0->stored_config->type = NET_BACKEND_VHOST_USER;
+ stored = &nc0->stored_config->u.vhost_user;
+
+ stored->chardev = g_strdup(chardev);
+
+ stored->has_queues = true;
+ stored->queues = queues;
+
return 0;
err:
@@ -446,5 +455,6 @@ int net_init_vhost_user(const Netdev *netdev, const char *name,
return -1;
}
- return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
+ return net_vhost_user_init(peer, "vhost_user", name,
+ vhost_user_opts->chardev, chr, queues);
}
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index fe659ec9e2..5a28bbcd7b 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -184,9 +184,22 @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device,
VhostVDPAState *s;
int vdpa_device_fd = -1;
int ret = 0;
+ NetdevVhostVDPAOptions *stored;
+
assert(name);
nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name);
- snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA);
+
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_BACKEND_VHOST_VDPA;
+ stored = &nc->stored_config->u.vhost_vdpa;
+
+ stored->has_vhostdev = true;
+ stored->vhostdev = g_strdup(vhostdev);
+
+ stored->has_queues = true;
+ stored->queues = 1; /* TODO: change when support multiqueue */
+
nc->queue_index = 0;
s = DO_UPCAST(VhostVDPAState, nc, nc);
vdpa_device_fd = qemu_open_old(vhostdev, O_RDWR);
diff --git a/qapi/hmp-output-visitor.c b/qapi/hmp-output-visitor.c
new file mode 100644
index 0000000000..8036605f97
--- /dev/null
+++ b/qapi/hmp-output-visitor.c
@@ -0,0 +1,193 @@
+/*
+ * HMP string output Visitor
+ *
+ * Copyright Yandex N.V., 2021
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qapi/hmp-output-visitor.h"
+#include "qapi/visitor-impl.h"
+
+struct HMPOutputVisitor {
+ Visitor visitor;
+ char **result;
+ GString *buffer;
+ bool is_continue;
+};
+
+static HMPOutputVisitor *to_hov(Visitor *v)
+{
+ return container_of(v, HMPOutputVisitor, visitor);
+}
+
+static void hmp_output_append_formatted(Visitor *v, const char *fmt, ...)
+{
+ HMPOutputVisitor *ov = to_hov(v);
+ va_list args;
+
+ if (ov->is_continue) {
+ g_string_append(ov->buffer, ",");
+ } else {
+ ov->is_continue = true;
+ }
+
+ va_start(args, fmt);
+ g_string_append_vprintf(ov->buffer, fmt, args);
+ va_end(args);
+}
+
+static void hmp_output_skip_comma(Visitor *v)
+{
+ HMPOutputVisitor *ov = to_hov(v);
+
+ ov->is_continue = false;
+}
+
+static bool hmp_output_start_struct(Visitor *v, const char *name,
+ void **obj, size_t unused, Error **errp)
+{
+ return true;
+}
+
+static void hmp_output_end_struct(Visitor *v, void **obj) {}
+
+static bool hmp_output_start_list(Visitor *v, const char *name,
+ GenericList **listp, size_t size,
+ Error **errp)
+{
+ hmp_output_append_formatted(v, "%s=[", name);
+ /* First element in array without comma before it */
+ hmp_output_skip_comma(v);
+
+ return true;
+}
+
+static GenericList *hmp_output_next_list(Visitor *v, GenericList *tail,
+ size_t size)
+{
+ return tail->next;
+}
+
+static void hmp_output_end_list(Visitor *v, void **obj)
+{
+ /* Don't need comma after last array element */
+ hmp_output_skip_comma(v);
+ hmp_output_append_formatted(v, "]");
+}
+
+static bool hmp_output_type_int64(Visitor *v, const char *name,
+ int64_t *obj, Error **errp)
+{
+ hmp_output_append_formatted(v, "%s=%" PRId64, name, *obj);
+
+ return true;
+}
+
+static bool hmp_output_type_uint64(Visitor *v, const char *name,
+ uint64_t *obj, Error **errp)
+{
+ hmp_output_append_formatted(v, "%s=%" PRIu64, name, *obj);
+
+ return true;
+}
+
+static bool hmp_output_type_bool(Visitor *v, const char *name, bool *obj,
+ Error **errp)
+{
+ hmp_output_append_formatted(v, "%s=%s", name, *obj ? "true" : "false");
+
+ return true;
+}
+
+static bool hmp_output_type_str(Visitor *v, const char *name, char **obj,
+ Error **errp)
+{
+ /* Skip already printed or unused fields */
+ if (!*obj || g_str_equal(name, "id") || g_str_equal(name, "type")) {
+ return true;
+ }
+
+ /* Do not print stub name for StringList elements */
+ if (g_str_equal(name, "str")) {
+ hmp_output_append_formatted(v, "%s", *obj);
+ } else {
+ hmp_output_append_formatted(v, "%s=%s", name, *obj);
+ }
+
+ return true;
+}
+
+static bool hmp_output_type_number(Visitor *v, const char *name,
+ double *obj, Error **errp)
+{
+ hmp_output_append_formatted(v, "%s=%.17g", name, *obj);
+
+ return true;
+}
+
+/* TODO: remove this function? */
+static bool hmp_output_type_any(Visitor *v, const char *name,
+ QObject **obj, Error **errp)
+{
+ return true;
+}
+
+static bool hmp_output_type_null(Visitor *v, const char *name,
+ QNull **obj, Error **errp)
+{
+ hmp_output_append_formatted(v, "%s=NULL", name);
+
+ return true;
+}
+
+static void hmp_output_complete(Visitor *v, void *opaque)
+{
+ HMPOutputVisitor *ov = to_hov(v);
+
+ *ov->result = g_string_free(ov->buffer, false);
+ ov->buffer = NULL;
+}
+
+static void hmp_output_free(Visitor *v)
+{
+ HMPOutputVisitor *ov = to_hov(v);
+
+ if (ov->buffer) {
+ g_string_free(ov->buffer, true);
+ }
+ g_free(v);
+}
+
+Visitor *hmp_output_visitor_new(char **result)
+{
+ HMPOutputVisitor *v;
+
+ v = g_malloc0(sizeof(*v));
+
+ v->visitor.type = VISITOR_OUTPUT;
+ v->visitor.start_struct = hmp_output_start_struct;
+ v->visitor.end_struct = hmp_output_end_struct;
+ v->visitor.start_list = hmp_output_start_list;
+ v->visitor.next_list = hmp_output_next_list;
+ v->visitor.end_list = hmp_output_end_list;
+ v->visitor.type_int64 = hmp_output_type_int64;
+ v->visitor.type_uint64 = hmp_output_type_uint64;
+ v->visitor.type_bool = hmp_output_type_bool;
+ v->visitor.type_str = hmp_output_type_str;
+ v->visitor.type_number = hmp_output_type_number;
+ v->visitor.type_any = hmp_output_type_any;
+ v->visitor.type_null = hmp_output_type_null;
+ v->visitor.complete = hmp_output_complete;
+ v->visitor.free = hmp_output_free;
+
+ v->result = result;
+ v->buffer = g_string_new("");
+ v->is_continue = false;
+
+ return &v->visitor;
+}
diff --git a/qapi/meson.build b/qapi/meson.build
index fcb15a78f1..d4424ae6e7 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -8,6 +8,7 @@ util_ss.add(files(
'qobject-output-visitor.c',
'string-input-visitor.c',
'string-output-visitor.c',
+ 'hmp-output-visitor.c',
))
if have_system or have_tools
util_ss.add(files(
diff --git a/qapi/net.json b/qapi/net.json
index c31748c87f..87361ebd9a 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -714,3 +714,83 @@
##
{ 'event': 'FAILOVER_NEGOTIATED',
'data': {'device-id': 'str'} }
+
+##
+# @NetBackend:
+#
+# Available netdev backend drivers.
+#
+# Since: 6.0
+##
+{ 'enum': 'NetBackend',
+ 'data': [ 'bridge', 'l2tpv3', 'netmap', 'socket', 'tap', 'user', 'vde',
+ 'vhost-user', 'vhost-vdpa' ] }
+
+##
+# @NetdevInfo:
+#
+# Configuration of a network backend device (netdev).
+#
+# @id: Device identifier.
+#
+# @type: Specify the driver used for interpreting remaining arguments.
+#
+# @peer-id: The connected frontend network device name (absent if no frontend
+# is connected).
+#
+# Since: 6.0
+##
+{ 'union': 'NetdevInfo',
+ 'base': { 'id': 'str',
+ 'type': 'NetBackend',
+ '*peer-id': 'str' },
+ 'discriminator': 'type',
+ 'data': {
+ 'bridge': 'NetdevBridgeOptions',
+ 'l2tpv3': 'NetdevL2TPv3Options',
+ 'netmap': 'NetdevNetmapOptions',
+ 'socket': 'NetdevSocketOptions',
+ 'tap': 'NetdevTapOptions',
+ 'user': 'NetdevUserOptions',
+ 'vde': 'NetdevVdeOptions',
+ 'vhost-user': 'NetdevVhostUserOptions',
+ 'vhost-vdpa': 'NetdevVhostVDPAOptions' } }
+
+##
+# @query-netdev:
+#
+# Get a list of @NetdevInfo for all virtual network backend devices (netdevs).
+#
+# Returns: a list of @NetdevInfo describing each netdev.
+#
+# Since: 6.0
+#
+# Example:
+#
+# -> { "execute": "query-netdev" }
+# <- { "return": [
+# {
+# "ipv6": true,
+# "ipv4": true,
+# "host": "10.0.2.2",
+# "ipv6-dns": "fec0::3",
+# "ipv6-prefix": "fec0::",
+# "net": "10.0.2.0/255.255.255.0",
+# "ipv6-host": "fec0::2",
+# "type": "user",
+# "peer-id": "net0",
+# "dns": "10.0.2.3",
+# "hostfwd": [
+# {
+# "str": "tcp::20004-:22"
+# }
+# ],
+# "ipv6-prefixlen": 64,
+# "id": "netdev0",
+# "restrict": false
+# }
+# ]
+# }
+#
+##
+{ 'command': 'query-netdev', 'returns': ['NetdevInfo'] }
diff --git a/qemu-options.hx b/qemu-options.hx
index 4da3f4f48c..9128dec510 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1705,7 +1705,7 @@ ERST
DEFHEADING()
-DEFHEADING(USB options:)
+DEFHEADING(USB convenience options:)
DEF("usb", 0, QEMU_OPTION_usb,
"-usb enable on-board USB host controller (if not enabled by default)\n",
@@ -1723,9 +1723,31 @@ DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice,
QEMU_ARCH_ALL)
SRST
``-usbdevice devname``
- Add the USB device devname. Note that this option is deprecated,
- please use ``-device usb-...`` instead. See the chapter about
+ Add the USB device devname, and enable an on-board USB controller
+ if possible and necessary (just like it can be done via
+ ``-machine usb=on``). Note that this option is mainly intended for
+ the user's convenience only. More fine-grained control can be
+ achieved by selecting a USB host controller (if necessary) and the
+ desired USB device via the ``-device`` option instead. For example,
+ instead of using ``-usbdevice mouse`` it is possible to use
+ ``-device qemu-xhci -device usb-mouse`` to connect the USB mouse
+ to a USB 3.0 controller instead (at least on machines that support
+ PCI and do not have an USB controller enabled by default yet).
+ For more details, see the chapter about
:ref:`Connecting USB devices` in the System Emulation Users Guide.
+ Possible devices for devname are:
+
+ ``braille``
+ Braille device. This will use BrlAPI to display the braille
+ output on a real or fake device (i.e. it also creates a
+ corresponding ``braille`` chardev automatically beside the
+ ``usb-braille`` USB device).
+
+ ``ccid``
+ Smartcard reader device
+
+ ``keyboard``
+ Standard USB keyboard. Will override the PS/2 keyboard (if present).
``mouse``
Virtual Mouse. This will override the PS/2 mouse emulation when
@@ -1737,9 +1759,10 @@ SRST
position without having to grab the mouse. Also overrides the
PS/2 mouse emulation when activated.
- ``braille``
- Braille device. This will use BrlAPI to display the braille
- output on a real or fake device.
+ ``wacom-tablet``
+ Wacom PenPartner USB tablet.
+
+
ERST
DEFHEADING()
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index fa6f2b6272..1050e36169 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -215,8 +215,7 @@ sed -e '1h;2,$H;$!d;g' -e 's/[^};]*pvrdma[^(| ]*([^)]*);//g' \
"$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h" > \
"$tmp_pvrdma_verbs";
-for i in "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h" \
- "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h" \
+for i in "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h" \
"$tmp_pvrdma_verbs"; do \
cp_portable "$i" \
"$output/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/"
diff --git a/softmmu/vl.c b/softmmu/vl.c
index b7673b9613..a750dae6b1 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -3180,8 +3180,6 @@ void qemu_init(int argc, char **argv, char **envp)
qemu_opts_parse_noisily(olist, "usb=on", false);
break;
case QEMU_OPTION_usbdevice:
- error_report("'-usbdevice' is deprecated, please use "
- "'-device usb-...' instead");
olist = qemu_find_opts("machine");
qemu_opts_parse_noisily(olist, "usb=on", false);
add_device_config(DEV_USB, optarg);
diff --git a/target/avr/helper.c b/target/avr/helper.c
index 65880b9928..35e1019594 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -49,7 +49,9 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
cc->tcg_ops->do_interrupt(cs);
env->intsrc &= env->intsrc - 1; /* clear the interrupt */
- cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ if (!env->intsrc) {
+ cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ }
ret = true;
}
@@ -98,7 +100,7 @@ int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf,
hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
- return addr; /* I assume 1:1 address correspondance */
+ return addr; /* I assume 1:1 address correspondence */
}
bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
@@ -299,7 +301,7 @@ void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data)
}
/*
- * this function implements LD instruction when there is a posibility to read
+ * this function implements LD instruction when there is a possibility to read
* from a CPU register
*/
target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr)
@@ -323,7 +325,7 @@ target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr)
}
/*
- * this function implements ST instruction when there is a posibility to write
+ * this function implements ST instruction when there is a possibility to write
* into a CPU register
*/
void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr)
diff --git a/target/mips/meson.build b/target/mips/meson.build
index 9741545440..3b131c4a7f 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -3,15 +3,17 @@ gen = [
decodetree.process('mips64r6.decode', extra_args: '--static-decode=decode_mips64r6'),
decodetree.process('msa32.decode', extra_args: '--static-decode=decode_msa32'),
decodetree.process('msa64.decode', extra_args: '--static-decode=decode_msa64'),
+ decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'),
]
mips_ss = ss.source_set()
-mips_ss.add(gen)
mips_ss.add(files(
'cpu.c',
'gdbstub.c',
))
-mips_ss.add(when: 'CONFIG_TCG', if_true: files(
+mips_tcg_ss = ss.source_set()
+mips_tcg_ss.add(gen)
+mips_tcg_ss.add(files(
'dsp_helper.c',
'fpu_helper.c',
'lmmi_helper.c',
@@ -22,7 +24,15 @@ mips_ss.add(when: 'CONFIG_TCG', if_true: files(
'tlb_helper.c',
'translate.c',
'translate_addr_const.c',
+ 'txx9_translate.c',
))
+mips_ss.add(when: ['CONFIG_TCG', 'TARGET_MIPS64'], if_true: files(
+ 'tx79_translate.c',
+))
+mips_tcg_ss.add(when: 'TARGET_MIPS64', if_false: files(
+ 'mxu_translate.c',
+))
+
mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'))
mips_softmmu_ss = ss.source_set()
@@ -30,11 +40,13 @@ mips_softmmu_ss.add(files(
'addr.c',
'cp0_timer.c',
'machine.c',
- 'mips-semi.c',
))
mips_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files(
'cp0_helper.c',
+ 'mips-semi.c',
))
+mips_ss.add_all(when: 'CONFIG_TCG', if_true: [mips_tcg_ss])
+
target_arch += {'mips': mips_ss}
target_softmmu_arch += {'mips': mips_softmmu_ss}
diff --git a/target/mips/mxu_translate.c b/target/mips/mxu_translate.c
new file mode 100644
index 0000000000..afc008eeee
--- /dev/null
+++ b/target/mips/mxu_translate.c
@@ -0,0 +1,1609 @@
+/*
+ * Ingenic XBurst Media eXtension Unit (MXU) translation routines.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ * Copyright (c) 2006 Marius Groeger (FPU operations)
+ * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
+ * Copyright (c) 2012 Jia Liu & Dongxue Zhang (MIPS ASE DSP support)
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Datasheet:
+ *
+ * "XBurst® Instruction Set Architecture MIPS eXtension/enhanced Unit
+ * Programming Manual", Ingenic Semiconductor Co, Ltd., revision June 2, 2017
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "exec/helper-gen.h"
+#include "translate.h"
+
+/*
+ *
+ * AN OVERVIEW OF MXU EXTENSION INSTRUCTION SET
+ * ============================================
+ *
+ *
+ * MXU (full name: MIPS eXtension/enhanced Unit) is a SIMD extension of MIPS32
+ * instructions set. It is designed to fit the needs of signal, graphical and
+ * video processing applications. MXU instruction set is used in Xburst family
+ * of microprocessors by Ingenic.
+ *
+ * MXU unit contains 17 registers called X0-X16. X0 is always zero, and X16 is
+ * the control register.
+ *
+ *
+ * The notation used in MXU assembler mnemonics
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Register operands:
+ *
+ * XRa, XRb, XRc, XRd - MXU registers
+ * Rb, Rc, Rd, Rs, Rt - general purpose MIPS registers
+ *
+ * Non-register operands:
+ *
+ * aptn1 - 1-bit accumulate add/subtract pattern
+ * aptn2 - 2-bit accumulate add/subtract pattern
+ * eptn2 - 2-bit execute add/subtract pattern
+ * optn2 - 2-bit operand pattern
+ * optn3 - 3-bit operand pattern
+ * sft4 - 4-bit shift amount
+ * strd2 - 2-bit stride amount
+ *
+ * Prefixes:
+ *
+ * Level of parallelism: Operand size:
+ * S - single operation at a time 32 - word
+ * D - two operations in parallel 16 - half word
+ * Q - four operations in parallel 8 - byte
+ *
+ * Operations:
+ *
+ * ADD - Add or subtract
+ * ADDC - Add with carry-in
+ * ACC - Accumulate
+ * ASUM - Sum together then accumulate (add or subtract)
+ * ASUMC - Sum together then accumulate (add or subtract) with carry-in
+ * AVG - Average between 2 operands
+ * ABD - Absolute difference
+ * ALN - Align data
+ * AND - Logical bitwise 'and' operation
+ * CPS - Copy sign
+ * EXTR - Extract bits
+ * I2M - Move from GPR register to MXU register
+ * LDD - Load data from memory to XRF
+ * LDI - Load data from memory to XRF (and increase the address base)
+ * LUI - Load unsigned immediate
+ * MUL - Multiply
+ * MULU - Unsigned multiply
+ * MADD - 64-bit operand add 32x32 product
+ * MSUB - 64-bit operand subtract 32x32 product
+ * MAC - Multiply and accumulate (add or subtract)
+ * MAD - Multiply and add or subtract
+ * MAX - Maximum between 2 operands
+ * MIN - Minimum between 2 operands
+ * M2I - Move from MXU register to GPR register
+ * MOVZ - Move if zero
+ * MOVN - Move if non-zero
+ * NOR - Logical bitwise 'nor' operation
+ * OR - Logical bitwise 'or' operation
+ * STD - Store data from XRF to memory
+ * SDI - Store data from XRF to memory (and increase the address base)
+ * SLT - Set of less than comparison
+ * SAD - Sum of absolute differences
+ * SLL - Logical shift left
+ * SLR - Logical shift right
+ * SAR - Arithmetic shift right
+ * SAT - Saturation
+ * SFL - Shuffle
+ * SCOP - Calculate x’s scope (-1, means x<0; 0, means x==0; 1, means x>0)
+ * XOR - Logical bitwise 'exclusive or' operation
+ *
+ * Suffixes:
+ *
+ * E - Expand results
+ * F - Fixed point multiplication
+ * L - Low part result
+ * R - Doing rounding
+ * V - Variable instead of immediate
+ * W - Combine above L and V
+ *
+ *
+ * The list of MXU instructions grouped by functionality
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Load/Store instructions Multiplication instructions
+ * ----------------------- ---------------------------
+ *
+ * S32LDD XRa, Rb, s12 S32MADD XRa, XRd, Rs, Rt
+ * S32STD XRa, Rb, s12 S32MADDU XRa, XRd, Rs, Rt
+ * S32LDDV XRa, Rb, rc, strd2 S32MSUB XRa, XRd, Rs, Rt
+ * S32STDV XRa, Rb, rc, strd2 S32MSUBU XRa, XRd, Rs, Rt
+ * S32LDI XRa, Rb, s12 S32MUL XRa, XRd, Rs, Rt
+ * S32SDI XRa, Rb, s12 S32MULU XRa, XRd, Rs, Rt
+ * S32LDIV XRa, Rb, rc, strd2 D16MUL XRa, XRb, XRc, XRd, optn2
+ * S32SDIV XRa, Rb, rc, strd2 D16MULE XRa, XRb, XRc, optn2
+ * S32LDDR XRa, Rb, s12 D16MULF XRa, XRb, XRc, optn2
+ * S32STDR XRa, Rb, s12 D16MAC XRa, XRb, XRc, XRd, aptn2, optn2
+ * S32LDDVR XRa, Rb, rc, strd2 D16MACE XRa, XRb, XRc, XRd, aptn2, optn2
+ * S32STDVR XRa, Rb, rc, strd2 D16MACF XRa, XRb, XRc, XRd, aptn2, optn2
+ * S32LDIR XRa, Rb, s12 D16MADL XRa, XRb, XRc, XRd, aptn2, optn2
+ * S32SDIR XRa, Rb, s12 S16MAD XRa, XRb, XRc, XRd, aptn1, optn2
+ * S32LDIVR XRa, Rb, rc, strd2 Q8MUL XRa, XRb, XRc, XRd
+ * S32SDIVR XRa, Rb, rc, strd2 Q8MULSU XRa, XRb, XRc, XRd
+ * S16LDD XRa, Rb, s10, eptn2 Q8MAC XRa, XRb, XRc, XRd, aptn2
+ * S16STD XRa, Rb, s10, eptn2 Q8MACSU XRa, XRb, XRc, XRd, aptn2
+ * S16LDI XRa, Rb, s10, eptn2 Q8MADL XRa, XRb, XRc, XRd, aptn2
+ * S16SDI XRa, Rb, s10, eptn2
+ * S8LDD XRa, Rb, s8, eptn3
+ * S8STD XRa, Rb, s8, eptn3 Addition and subtraction instructions
+ * S8LDI XRa, Rb, s8, eptn3 -------------------------------------
+ * S8SDI XRa, Rb, s8, eptn3
+ * LXW Rd, Rs, Rt, strd2 D32ADD XRa, XRb, XRc, XRd, eptn2
+ * LXH Rd, Rs, Rt, strd2 D32ADDC XRa, XRb, XRc, XRd
+ * LXHU Rd, Rs, Rt, strd2 D32ACC XRa, XRb, XRc, XRd, eptn2
+ * LXB Rd, Rs, Rt, strd2 D32ACCM XRa, XRb, XRc, XRd, eptn2
+ * LXBU Rd, Rs, Rt, strd2 D32ASUM XRa, XRb, XRc, XRd, eptn2
+ * S32CPS XRa, XRb, XRc
+ * Q16ADD XRa, XRb, XRc, XRd, eptn2, optn2
+ * Comparison instructions Q16ACC XRa, XRb, XRc, XRd, eptn2
+ * ----------------------- Q16ACCM XRa, XRb, XRc, XRd, eptn2
+ * D16ASUM XRa, XRb, XRc, XRd, eptn2
+ * S32MAX XRa, XRb, XRc D16CPS XRa, XRb,
+ * S32MIN XRa, XRb, XRc D16AVG XRa, XRb, XRc
+ * S32SLT XRa, XRb, XRc D16AVGR XRa, XRb, XRc
+ * S32MOVZ XRa, XRb, XRc Q8ADD XRa, XRb, XRc, eptn2
+ * S32MOVN XRa, XRb, XRc Q8ADDE XRa, XRb, XRc, XRd, eptn2
+ * D16MAX XRa, XRb, XRc Q8ACCE XRa, XRb, XRc, XRd, eptn2
+ * D16MIN XRa, XRb, XRc Q8ABD XRa, XRb, XRc
+ * D16SLT XRa, XRb, XRc Q8SAD XRa, XRb, XRc, XRd
+ * D16MOVZ XRa, XRb, XRc Q8AVG XRa, XRb, XRc
+ * D16MOVN XRa, XRb, XRc Q8AVGR XRa, XRb, XRc
+ * Q8MAX XRa, XRb, XRc D8SUM XRa, XRb, XRc, XRd
+ * Q8MIN XRa, XRb, XRc D8SUMC XRa, XRb, XRc, XRd
+ * Q8SLT XRa, XRb, XRc
+ * Q8SLTU XRa, XRb, XRc
+ * Q8MOVZ XRa, XRb, XRc Shift instructions
+ * Q8MOVN XRa, XRb, XRc ------------------
+ *
+ * D32SLL XRa, XRb, XRc, XRd, sft4
+ * Bitwise instructions D32SLR XRa, XRb, XRc, XRd, sft4
+ * -------------------- D32SAR XRa, XRb, XRc, XRd, sft4
+ * D32SARL XRa, XRb, XRc, sft4
+ * S32NOR XRa, XRb, XRc D32SLLV XRa, XRb, Rb
+ * S32AND XRa, XRb, XRc D32SLRV XRa, XRb, Rb
+ * S32XOR XRa, XRb, XRc D32SARV XRa, XRb, Rb
+ * S32OR XRa, XRb, XRc D32SARW XRa, XRb, XRc, Rb
+ * Q16SLL XRa, XRb, XRc, XRd, sft4
+ * Q16SLR XRa, XRb, XRc, XRd, sft4
+ * Miscellaneous instructions Q16SAR XRa, XRb, XRc, XRd, sft4
+ * ------------------------- Q16SLLV XRa, XRb, Rb
+ * Q16SLRV XRa, XRb, Rb
+ * S32SFL XRa, XRb, XRc, XRd, optn2 Q16SARV XRa, XRb, Rb
+ * S32ALN XRa, XRb, XRc, Rb
+ * S32ALNI XRa, XRb, XRc, s3
+ * S32LUI XRa, s8, optn3 Move instructions
+ * S32EXTR XRa, XRb, Rb, bits5 -----------------
+ * S32EXTRV XRa, XRb, Rs, Rt
+ * Q16SCOP XRa, XRb, XRc, XRd S32M2I XRa, Rb
+ * Q16SAT XRa, XRb, XRc S32I2M XRa, Rb
+ *
+ *
+ * The opcode organization of MXU instructions
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The bits 31..26 of all MXU instructions are equal to 0x1C (also referred
+ * as opcode SPECIAL2 in the base MIPS ISA). The organization and meaning of
+ * other bits up to the instruction level is as follows:
+ *
+ * bits
+ * 05..00
+ *
+ * ┌─ 000000 ─ OPC_MXU_S32MADD
+ * ├─ 000001 ─ OPC_MXU_S32MADDU
+ * ├─ 000010 ─ <not assigned> (non-MXU OPC_MUL)
+ * │
+ * │ 20..18
+ * ├─ 000011 ─ OPC_MXU__POOL00 ─┬─ 000 ─ OPC_MXU_S32MAX
+ * │ ├─ 001 ─ OPC_MXU_S32MIN
+ * │ ├─ 010 ─ OPC_MXU_D16MAX
+ * │ ├─ 011 ─ OPC_MXU_D16MIN
+ * │ ├─ 100 ─ OPC_MXU_Q8MAX
+ * │ ├─ 101 ─ OPC_MXU_Q8MIN
+ * │ ├─ 110 ─ OPC_MXU_Q8SLT
+ * │ └─ 111 ─ OPC_MXU_Q8SLTU
+ * ├─ 000100 ─ OPC_MXU_S32MSUB
+ * ├─ 000101 ─ OPC_MXU_S32MSUBU 20..18
+ * ├─ 000110 ─ OPC_MXU__POOL01 ─┬─ 000 ─ OPC_MXU_S32SLT
+ * │ ├─ 001 ─ OPC_MXU_D16SLT
+ * │ ├─ 010 ─ OPC_MXU_D16AVG
+ * │ ├─ 011 ─ OPC_MXU_D16AVGR
+ * │ ├─ 100 ─ OPC_MXU_Q8AVG
+ * │ ├─ 101 ─ OPC_MXU_Q8AVGR
+ * │ └─ 111 ─ OPC_MXU_Q8ADD
+ * │
+ * │ 20..18
+ * ├─ 000111 ─ OPC_MXU__POOL02 ─┬─ 000 ─ OPC_MXU_S32CPS
+ * │ ├─ 010 ─ OPC_MXU_D16CPS
+ * │ ├─ 100 ─ OPC_MXU_Q8ABD
+ * │ └─ 110 ─ OPC_MXU_Q16SAT
+ * ├─ 001000 ─ OPC_MXU_D16MUL
+ * │ 25..24
+ * ├─ 001001 ─ OPC_MXU__POOL03 ─┬─ 00 ─ OPC_MXU_D16MULF
+ * │ └─ 01 ─ OPC_MXU_D16MULE
+ * ├─ 001010 ─ OPC_MXU_D16MAC
+ * ├─ 001011 ─ OPC_MXU_D16MACF
+ * ├─ 001100 ─ OPC_MXU_D16MADL
+ * ├─ 001101 ─ OPC_MXU_S16MAD
+ * ├─ 001110 ─ OPC_MXU_Q16ADD
+ * ├─ 001111 ─ OPC_MXU_D16MACE 23
+ * │ ┌─ 0 ─ OPC_MXU_S32LDD
+ * ├─ 010000 ─ OPC_MXU__POOL04 ─┴─ 1 ─ OPC_MXU_S32LDDR
+ * │
+ * │ 23
+ * ├─ 010001 ─ OPC_MXU__POOL05 ─┬─ 0 ─ OPC_MXU_S32STD
+ * │ └─ 1 ─ OPC_MXU_S32STDR
+ * │
+ * │ 13..10
+ * ├─ 010010 ─ OPC_MXU__POOL06 ─┬─ 0000 ─ OPC_MXU_S32LDDV
+ * │ └─ 0001 ─ OPC_MXU_S32LDDVR
+ * │
+ * │ 13..10
+ * ├─ 010011 ─ OPC_MXU__POOL07 ─┬─ 0000 ─ OPC_MXU_S32STDV
+ * │ └─ 0001 ─ OPC_MXU_S32STDVR
+ * │
+ * │ 23
+ * ├─ 010100 ─ OPC_MXU__POOL08 ─┬─ 0 ─ OPC_MXU_S32LDI
+ * │ └─ 1 ─ OPC_MXU_S32LDIR
+ * │
+ * │ 23
+ * ├─ 010101 ─ OPC_MXU__POOL09 ─┬─ 0 ─ OPC_MXU_S32SDI
+ * │ └─ 1 ─ OPC_MXU_S32SDIR
+ * │
+ * │ 13..10
+ * ├─ 010110 ─ OPC_MXU__POOL10 ─┬─ 0000 ─ OPC_MXU_S32LDIV
+ * │ └─ 0001 ─ OPC_MXU_S32LDIVR
+ * │
+ * │ 13..10
+ * ├─ 010111 ─ OPC_MXU__POOL11 ─┬─ 0000 ─ OPC_MXU_S32SDIV
+ * │ └─ 0001 ─ OPC_MXU_S32SDIVR
+ * ├─ 011000 ─ OPC_MXU_D32ADD
+ * │ 23..22
+ * MXU ├─ 011001 ─ OPC_MXU__POOL12 ─┬─ 00 ─ OPC_MXU_D32ACC
+ * opcodes ─┤ ├─ 01 ─ OPC_MXU_D32ACCM
+ * │ └─ 10 ─ OPC_MXU_D32ASUM
+ * ├─ 011010 ─ <not assigned>
+ * │ 23..22
+ * ├─ 011011 ─ OPC_MXU__POOL13 ─┬─ 00 ─ OPC_MXU_Q16ACC
+ * │ ├─ 01 ─ OPC_MXU_Q16ACCM
+ * │ └─ 10 ─ OPC_MXU_Q16ASUM
+ * │
+ * │ 23..22
+ * ├─ 011100 ─ OPC_MXU__POOL14 ─┬─ 00 ─ OPC_MXU_Q8ADDE
+ * │ ├─ 01 ─ OPC_MXU_D8SUM
+ * ├─ 011101 ─ OPC_MXU_Q8ACCE └─ 10 ─ OPC_MXU_D8SUMC
+ * ├─ 011110 ─ <not assigned>
+ * ├─ 011111 ─ <not assigned>
+ * ├─ 100000 ─ <not assigned> (overlaps with CLZ)
+ * ├─ 100001 ─ <not assigned> (overlaps with CLO)
+ * ├─ 100010 ─ OPC_MXU_S8LDD
+ * ├─ 100011 ─ OPC_MXU_S8STD 15..14
+ * ├─ 100100 ─ OPC_MXU_S8LDI ┌─ 00 ─ OPC_MXU_S32MUL
+ * ├─ 100101 ─ OPC_MXU_S8SDI ├─ 00 ─ OPC_MXU_S32MULU
+ * │ ├─ 00 ─ OPC_MXU_S32EXTR
+ * ├─ 100110 ─ OPC_MXU__POOL15 ─┴─ 00 ─ OPC_MXU_S32EXTRV
+ * │
+ * │ 20..18
+ * ├─ 100111 ─ OPC_MXU__POOL16 ─┬─ 000 ─ OPC_MXU_D32SARW
+ * │ ├─ 001 ─ OPC_MXU_S32ALN
+ * │ ├─ 010 ─ OPC_MXU_S32ALNI
+ * │ ├─ 011 ─ OPC_MXU_S32LUI
+ * │ ├─ 100 ─ OPC_MXU_S32NOR
+ * │ ├─ 101 ─ OPC_MXU_S32AND
+ * │ ├─ 110 ─ OPC_MXU_S32OR
+ * │ └─ 111 ─ OPC_MXU_S32XOR
+ * │
+ * │ 7..5
+ * ├─ 101000 ─ OPC_MXU__POOL17 ─┬─ 000 ─ OPC_MXU_LXB
+ * │ ├─ 001 ─ OPC_MXU_LXH
+ * ├─ 101001 ─ <not assigned> ├─ 011 ─ OPC_MXU_LXW
+ * ├─ 101010 ─ OPC_MXU_S16LDD ├─ 100 ─ OPC_MXU_LXBU
+ * ├─ 101011 ─ OPC_MXU_S16STD └─ 101 ─ OPC_MXU_LXHU
+ * ├─ 101100 ─ OPC_MXU_S16LDI
+ * ├─ 101101 ─ OPC_MXU_S16SDI
+ * ├─ 101110 ─ OPC_MXU_S32M2I
+ * ├─ 101111 ─ OPC_MXU_S32I2M
+ * ├─ 110000 ─ OPC_MXU_D32SLL
+ * ├─ 110001 ─ OPC_MXU_D32SLR 20..18
+ * ├─ 110010 ─ OPC_MXU_D32SARL ┌─ 000 ─ OPC_MXU_D32SLLV
+ * ├─ 110011 ─ OPC_MXU_D32SAR ├─ 001 ─ OPC_MXU_D32SLRV
+ * ├─ 110100 ─ OPC_MXU_Q16SLL ├─ 010 ─ OPC_MXU_D32SARV
+ * ├─ 110101 ─ OPC_MXU_Q16SLR ├─ 011 ─ OPC_MXU_Q16SLLV
+ * │ ├─ 100 ─ OPC_MXU_Q16SLRV
+ * ├─ 110110 ─ OPC_MXU__POOL18 ─┴─ 101 ─ OPC_MXU_Q16SARV
+ * │
+ * ├─ 110111 ─ OPC_MXU_Q16SAR
+ * │ 23..22
+ * ├─ 111000 ─ OPC_MXU__POOL19 ─┬─ 00 ─ OPC_MXU_Q8MUL
+ * │ └─ 01 ─ OPC_MXU_Q8MULSU
+ * │
+ * │ 20..18
+ * ├─ 111001 ─ OPC_MXU__POOL20 ─┬─ 000 ─ OPC_MXU_Q8MOVZ
+ * │ ├─ 001 ─ OPC_MXU_Q8MOVN
+ * │ ├─ 010 ─ OPC_MXU_D16MOVZ
+ * │ ├─ 011 ─ OPC_MXU_D16MOVN
+ * │ ├─ 100 ─ OPC_MXU_S32MOVZ
+ * │ └─ 101 ─ OPC_MXU_S32MOVN
+ * │
+ * │ 23..22
+ * ├─ 111010 ─ OPC_MXU__POOL21 ─┬─ 00 ─ OPC_MXU_Q8MAC
+ * │ └─ 10 ─ OPC_MXU_Q8MACSU
+ * ├─ 111011 ─ OPC_MXU_Q16SCOP
+ * ├─ 111100 ─ OPC_MXU_Q8MADL
+ * ├─ 111101 ─ OPC_MXU_S32SFL
+ * ├─ 111110 ─ OPC_MXU_Q8SAD
+ * └─ 111111 ─ <not assigned> (overlaps with SDBBP)
+ *
+ *
+ * Compiled after:
+ *
+ * "XBurst® Instruction Set Architecture MIPS eXtension/enhanced Unit
+ * Programming Manual", Ingenic Semiconductor Co, Ltd., revision June 2, 2017
+ */
+
+enum {
+ OPC_MXU__POOL00 = 0x03,
+ OPC_MXU_D16MUL = 0x08,
+ OPC_MXU_D16MAC = 0x0A,
+ OPC_MXU__POOL04 = 0x10,
+ OPC_MXU_S8LDD = 0x22,
+ OPC_MXU__POOL16 = 0x27,
+ OPC_MXU_S32M2I = 0x2E,
+ OPC_MXU_S32I2M = 0x2F,
+ OPC_MXU__POOL19 = 0x38,
+};
+
+
+/*
+ * MXU pool 00
+ */
+enum {
+ OPC_MXU_S32MAX = 0x00,
+ OPC_MXU_S32MIN = 0x01,
+ OPC_MXU_D16MAX = 0x02,
+ OPC_MXU_D16MIN = 0x03,
+ OPC_MXU_Q8MAX = 0x04,
+ OPC_MXU_Q8MIN = 0x05,
+};
+
+/*
+ * MXU pool 04
+ */
+enum {
+ OPC_MXU_S32LDD = 0x00,
+ OPC_MXU_S32LDDR = 0x01,
+};
+
+/*
+ * MXU pool 16
+ */
+enum {
+ OPC_MXU_S32ALNI = 0x02,
+ OPC_MXU_S32NOR = 0x04,
+ OPC_MXU_S32AND = 0x05,
+ OPC_MXU_S32OR = 0x06,
+ OPC_MXU_S32XOR = 0x07,
+};
+
+/*
+ * MXU pool 19
+ */
+enum {
+ OPC_MXU_Q8MUL = 0x00,
+ OPC_MXU_Q8MULSU = 0x01,
+};
+
+/* MXU accumulate add/subtract 1-bit pattern 'aptn1' */
+#define MXU_APTN1_A 0
+#define MXU_APTN1_S 1
+
+/* MXU accumulate add/subtract 2-bit pattern 'aptn2' */
+#define MXU_APTN2_AA 0
+#define MXU_APTN2_AS 1
+#define MXU_APTN2_SA 2
+#define MXU_APTN2_SS 3
+
+/* MXU execute add/subtract 2-bit pattern 'eptn2' */
+#define MXU_EPTN2_AA 0
+#define MXU_EPTN2_AS 1
+#define MXU_EPTN2_SA 2
+#define MXU_EPTN2_SS 3
+
+/* MXU operand getting pattern 'optn2' */
+#define MXU_OPTN2_PTN0 0
+#define MXU_OPTN2_PTN1 1
+#define MXU_OPTN2_PTN2 2
+#define MXU_OPTN2_PTN3 3
+/* alternative naming scheme for 'optn2' */
+#define MXU_OPTN2_WW 0
+#define MXU_OPTN2_LW 1
+#define MXU_OPTN2_HW 2
+#define MXU_OPTN2_XW 3
+
+/* MXU operand getting pattern 'optn3' */
+#define MXU_OPTN3_PTN0 0
+#define MXU_OPTN3_PTN1 1
+#define MXU_OPTN3_PTN2 2
+#define MXU_OPTN3_PTN3 3
+#define MXU_OPTN3_PTN4 4
+#define MXU_OPTN3_PTN5 5
+#define MXU_OPTN3_PTN6 6
+#define MXU_OPTN3_PTN7 7
+
+/* MXU registers */
+static TCGv mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1];
+static TCGv mxu_CR;
+
+static const char * const mxuregnames[] = {
+ "XR1", "XR2", "XR3", "XR4", "XR5", "XR6", "XR7", "XR8",
+ "XR9", "XR10", "XR11", "XR12", "XR13", "XR14", "XR15", "MXU_CR",
+};
+
+void mxu_translate_init(void)
+{
+ for (unsigned i = 0; i < NUMBER_OF_MXU_REGISTERS - 1; i++) {
+ mxu_gpr[i] = tcg_global_mem_new(cpu_env,
+ offsetof(CPUMIPSState, active_tc.mxu_gpr[i]),
+ mxuregnames[i]);
+ }
+
+ mxu_CR = tcg_global_mem_new(cpu_env,
+ offsetof(CPUMIPSState, active_tc.mxu_cr),
+ mxuregnames[NUMBER_OF_MXU_REGISTERS - 1]);
+}
+
+/* MXU General purpose registers moves. */
+static inline void gen_load_mxu_gpr(TCGv t, unsigned int reg)
+{
+ if (reg == 0) {
+ tcg_gen_movi_tl(t, 0);
+ } else if (reg <= 15) {
+ tcg_gen_mov_tl(t, mxu_gpr[reg - 1]);
+ }
+}
+
+static inline void gen_store_mxu_gpr(TCGv t, unsigned int reg)
+{
+ if (reg > 0 && reg <= 15) {
+ tcg_gen_mov_tl(mxu_gpr[reg - 1], t);
+ }
+}
+
+/* MXU control register moves. */
+static inline void gen_load_mxu_cr(TCGv t)
+{
+ tcg_gen_mov_tl(t, mxu_CR);
+}
+
+static inline void gen_store_mxu_cr(TCGv t)
+{
+ /* TODO: Add handling of RW rules for MXU_CR. */
+ tcg_gen_mov_tl(mxu_CR, t);
+}
+
+/*
+ * S32I2M XRa, rb - Register move from GRF to XRF
+ */
+static void gen_mxu_s32i2m(DisasContext *ctx)
+{
+ TCGv t0;
+ uint32_t XRa, Rb;
+
+ t0 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 5);
+ Rb = extract32(ctx->opcode, 16, 5);
+
+ gen_load_gpr(t0, Rb);
+ if (XRa <= 15) {
+ gen_store_mxu_gpr(t0, XRa);
+ } else if (XRa == 16) {
+ gen_store_mxu_cr(t0);
+ }
+
+ tcg_temp_free(t0);
+}
+
+/*
+ * S32M2I XRa, rb - Register move from XRF to GRF
+ */
+static void gen_mxu_s32m2i(DisasContext *ctx)
+{
+ TCGv t0;
+ uint32_t XRa, Rb;
+
+ t0 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 5);
+ Rb = extract32(ctx->opcode, 16, 5);
+
+ if (XRa <= 15) {
+ gen_load_mxu_gpr(t0, XRa);
+ } else if (XRa == 16) {
+ gen_load_mxu_cr(t0);
+ }
+
+ gen_store_gpr(t0, Rb);
+
+ tcg_temp_free(t0);
+}
+
+/*
+ * S8LDD XRa, Rb, s8, optn3 - Load a byte from memory to XRF
+ */
+static void gen_mxu_s8ldd(DisasContext *ctx)
+{
+ TCGv t0, t1;
+ uint32_t XRa, Rb, s8, optn3;
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 4);
+ s8 = extract32(ctx->opcode, 10, 8);
+ optn3 = extract32(ctx->opcode, 18, 3);
+ Rb = extract32(ctx->opcode, 21, 5);
+
+ gen_load_gpr(t0, Rb);
+ tcg_gen_addi_tl(t0, t0, (int8_t)s8);
+
+ switch (optn3) {
+ /* XRa[7:0] = tmp8 */
+ case MXU_OPTN3_PTN0:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ gen_load_mxu_gpr(t0, XRa);
+ tcg_gen_deposit_tl(t0, t0, t1, 0, 8);
+ break;
+ /* XRa[15:8] = tmp8 */
+ case MXU_OPTN3_PTN1:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ gen_load_mxu_gpr(t0, XRa);
+ tcg_gen_deposit_tl(t0, t0, t1, 8, 8);
+ break;
+ /* XRa[23:16] = tmp8 */
+ case MXU_OPTN3_PTN2:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ gen_load_mxu_gpr(t0, XRa);
+ tcg_gen_deposit_tl(t0, t0, t1, 16, 8);
+ break;
+ /* XRa[31:24] = tmp8 */
+ case MXU_OPTN3_PTN3:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ gen_load_mxu_gpr(t0, XRa);
+ tcg_gen_deposit_tl(t0, t0, t1, 24, 8);
+ break;
+ /* XRa = {8'b0, tmp8, 8'b0, tmp8} */
+ case MXU_OPTN3_PTN4:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ tcg_gen_deposit_tl(t0, t1, t1, 16, 16);
+ break;
+ /* XRa = {tmp8, 8'b0, tmp8, 8'b0} */
+ case MXU_OPTN3_PTN5:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ tcg_gen_shli_tl(t1, t1, 8);
+ tcg_gen_deposit_tl(t0, t1, t1, 16, 16);
+ break;
+ /* XRa = {{8{sign of tmp8}}, tmp8, {8{sign of tmp8}}, tmp8} */
+ case MXU_OPTN3_PTN6:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_SB);
+ tcg_gen_mov_tl(t0, t1);
+ tcg_gen_andi_tl(t0, t0, 0xFF00FFFF);
+ tcg_gen_shli_tl(t1, t1, 16);
+ tcg_gen_or_tl(t0, t0, t1);
+ break;
+ /* XRa = {tmp8, tmp8, tmp8, tmp8} */
+ case MXU_OPTN3_PTN7:
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+ tcg_gen_deposit_tl(t1, t1, t1, 8, 8);
+ tcg_gen_deposit_tl(t0, t1, t1, 16, 16);
+ break;
+ }
+
+ gen_store_mxu_gpr(t0, XRa);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+/*
+ * D16MUL XRa, XRb, XRc, XRd, optn2 - Signed 16 bit pattern multiplication
+ */
+static void gen_mxu_d16mul(DisasContext *ctx)
+{
+ TCGv t0, t1, t2, t3;
+ uint32_t XRa, XRb, XRc, XRd, optn2;
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ t2 = tcg_temp_new();
+ t3 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRd = extract32(ctx->opcode, 18, 4);
+ optn2 = extract32(ctx->opcode, 22, 2);
+
+ gen_load_mxu_gpr(t1, XRb);
+ tcg_gen_sextract_tl(t0, t1, 0, 16);
+ tcg_gen_sextract_tl(t1, t1, 16, 16);
+ gen_load_mxu_gpr(t3, XRc);
+ tcg_gen_sextract_tl(t2, t3, 0, 16);
+ tcg_gen_sextract_tl(t3, t3, 16, 16);
+
+ switch (optn2) {
+ case MXU_OPTN2_WW: /* XRB.H*XRC.H == lop, XRB.L*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t1, t3);
+ tcg_gen_mul_tl(t2, t0, t2);
+ break;
+ case MXU_OPTN2_LW: /* XRB.L*XRC.H == lop, XRB.L*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t0, t3);
+ tcg_gen_mul_tl(t2, t0, t2);
+ break;
+ case MXU_OPTN2_HW: /* XRB.H*XRC.H == lop, XRB.H*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t1, t3);
+ tcg_gen_mul_tl(t2, t1, t2);
+ break;
+ case MXU_OPTN2_XW: /* XRB.L*XRC.H == lop, XRB.H*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t0, t3);
+ tcg_gen_mul_tl(t2, t1, t2);
+ break;
+ }
+ gen_store_mxu_gpr(t3, XRa);
+ gen_store_mxu_gpr(t2, XRd);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+}
+
+/*
+ * D16MAC XRa, XRb, XRc, XRd, aptn2, optn2 - Signed 16 bit pattern multiply
+ * and accumulate
+ */
+static void gen_mxu_d16mac(DisasContext *ctx)
+{
+ TCGv t0, t1, t2, t3;
+ uint32_t XRa, XRb, XRc, XRd, optn2, aptn2;
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ t2 = tcg_temp_new();
+ t3 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRd = extract32(ctx->opcode, 18, 4);
+ optn2 = extract32(ctx->opcode, 22, 2);
+ aptn2 = extract32(ctx->opcode, 24, 2);
+
+ gen_load_mxu_gpr(t1, XRb);
+ tcg_gen_sextract_tl(t0, t1, 0, 16);
+ tcg_gen_sextract_tl(t1, t1, 16, 16);
+
+ gen_load_mxu_gpr(t3, XRc);
+ tcg_gen_sextract_tl(t2, t3, 0, 16);
+ tcg_gen_sextract_tl(t3, t3, 16, 16);
+
+ switch (optn2) {
+ case MXU_OPTN2_WW: /* XRB.H*XRC.H == lop, XRB.L*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t1, t3);
+ tcg_gen_mul_tl(t2, t0, t2);
+ break;
+ case MXU_OPTN2_LW: /* XRB.L*XRC.H == lop, XRB.L*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t0, t3);
+ tcg_gen_mul_tl(t2, t0, t2);
+ break;
+ case MXU_OPTN2_HW: /* XRB.H*XRC.H == lop, XRB.H*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t1, t3);
+ tcg_gen_mul_tl(t2, t1, t2);
+ break;
+ case MXU_OPTN2_XW: /* XRB.L*XRC.H == lop, XRB.H*XRC.L == rop */
+ tcg_gen_mul_tl(t3, t0, t3);
+ tcg_gen_mul_tl(t2, t1, t2);
+ break;
+ }
+ gen_load_mxu_gpr(t0, XRa);
+ gen_load_mxu_gpr(t1, XRd);
+
+ switch (aptn2) {
+ case MXU_APTN2_AA:
+ tcg_gen_add_tl(t3, t0, t3);
+ tcg_gen_add_tl(t2, t1, t2);
+ break;
+ case MXU_APTN2_AS:
+ tcg_gen_add_tl(t3, t0, t3);
+ tcg_gen_sub_tl(t2, t1, t2);
+ break;
+ case MXU_APTN2_SA:
+ tcg_gen_sub_tl(t3, t0, t3);
+ tcg_gen_add_tl(t2, t1, t2);
+ break;
+ case MXU_APTN2_SS:
+ tcg_gen_sub_tl(t3, t0, t3);
+ tcg_gen_sub_tl(t2, t1, t2);
+ break;
+ }
+ gen_store_mxu_gpr(t3, XRa);
+ gen_store_mxu_gpr(t2, XRd);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+}
+
+/*
+ * Q8MUL XRa, XRb, XRc, XRd - Parallel unsigned 8 bit pattern multiply
+ * Q8MULSU XRa, XRb, XRc, XRd - Parallel signed 8 bit pattern multiply
+ */
+static void gen_mxu_q8mul_q8mulsu(DisasContext *ctx)
+{
+ TCGv t0, t1, t2, t3, t4, t5, t6, t7;
+ uint32_t XRa, XRb, XRc, XRd, sel;
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+ t2 = tcg_temp_new();
+ t3 = tcg_temp_new();
+ t4 = tcg_temp_new();
+ t5 = tcg_temp_new();
+ t6 = tcg_temp_new();
+ t7 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRd = extract32(ctx->opcode, 18, 4);
+ sel = extract32(ctx->opcode, 22, 2);
+
+ gen_load_mxu_gpr(t3, XRb);
+ gen_load_mxu_gpr(t7, XRc);
+
+ if (sel == 0x2) {
+ /* Q8MULSU */
+ tcg_gen_ext8s_tl(t0, t3);
+ tcg_gen_shri_tl(t3, t3, 8);
+ tcg_gen_ext8s_tl(t1, t3);
+ tcg_gen_shri_tl(t3, t3, 8);
+ tcg_gen_ext8s_tl(t2, t3);
+ tcg_gen_shri_tl(t3, t3, 8);
+ tcg_gen_ext8s_tl(t3, t3);
+ } else {
+ /* Q8MUL */
+ tcg_gen_ext8u_tl(t0, t3);
+ tcg_gen_shri_tl(t3, t3, 8);
+ tcg_gen_ext8u_tl(t1, t3);
+ tcg_gen_shri_tl(t3, t3, 8);
+ tcg_gen_ext8u_tl(t2, t3);
+ tcg_gen_shri_tl(t3, t3, 8);
+ tcg_gen_ext8u_tl(t3, t3);
+ }
+
+ tcg_gen_ext8u_tl(t4, t7);
+ tcg_gen_shri_tl(t7, t7, 8);
+ tcg_gen_ext8u_tl(t5, t7);
+ tcg_gen_shri_tl(t7, t7, 8);
+ tcg_gen_ext8u_tl(t6, t7);
+ tcg_gen_shri_tl(t7, t7, 8);
+ tcg_gen_ext8u_tl(t7, t7);
+
+ tcg_gen_mul_tl(t0, t0, t4);
+ tcg_gen_mul_tl(t1, t1, t5);
+ tcg_gen_mul_tl(t2, t2, t6);
+ tcg_gen_mul_tl(t3, t3, t7);
+
+ tcg_gen_andi_tl(t0, t0, 0xFFFF);
+ tcg_gen_andi_tl(t1, t1, 0xFFFF);
+ tcg_gen_andi_tl(t2, t2, 0xFFFF);
+ tcg_gen_andi_tl(t3, t3, 0xFFFF);
+
+ tcg_gen_shli_tl(t1, t1, 16);
+ tcg_gen_shli_tl(t3, t3, 16);
+
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_or_tl(t1, t2, t3);
+
+ gen_store_mxu_gpr(t0, XRd);
+ gen_store_mxu_gpr(t1, XRa);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+ tcg_temp_free(t4);
+ tcg_temp_free(t5);
+ tcg_temp_free(t6);
+ tcg_temp_free(t7);
+}
+
+/*
+ * S32LDD XRa, Rb, S12 - Load a word from memory to XRF
+ * S32LDDR XRa, Rb, S12 - Load a word from memory to XRF, reversed byte seq.
+ */
+static void gen_mxu_s32ldd_s32lddr(DisasContext *ctx)
+{
+ TCGv t0, t1;
+ uint32_t XRa, Rb, s12, sel;
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ XRa = extract32(ctx->opcode, 6, 4);
+ s12 = extract32(ctx->opcode, 10, 10);
+ sel = extract32(ctx->opcode, 20, 1);
+ Rb = extract32(ctx->opcode, 21, 5);
+
+ gen_load_gpr(t0, Rb);
+
+ tcg_gen_movi_tl(t1, s12);
+ tcg_gen_shli_tl(t1, t1, 2);
+ if (s12 & 0x200) {
+ tcg_gen_ori_tl(t1, t1, 0xFFFFF000);
+ }
+ tcg_gen_add_tl(t1, t0, t1);
+ tcg_gen_qemu_ld_tl(t1, t1, ctx->mem_idx, MO_SL);
+
+ if (sel == 1) {
+ /* S32LDDR */
+ tcg_gen_bswap32_tl(t1, t1);
+ }
+ gen_store_mxu_gpr(t1, XRa);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+
+/*
+ * MXU instruction category: logic
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * S32NOR S32AND S32OR S32XOR
+ */
+
+/*
+ * S32NOR XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'nor' operation
+ * applied to the content of XRb and XRc.
+ */
+static void gen_mxu_S32NOR(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 1s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0xFFFFFFFF);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just set destination to the negation of XRc */
+ tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ } else if (unlikely(XRc == 0)) {
+ /* XRa zero register -> just set destination to the negation of XRb */
+ tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to the negation of XRb */
+ tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ tcg_gen_nor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+/*
+ * S32AND XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'and' operation
+ * applied to the content of XRb and XRc.
+ */
+static void gen_mxu_S32AND(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) || (XRc == 0))) {
+ /* one of operands zero register -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ tcg_gen_and_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+/*
+ * S32OR XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'or' operation
+ * applied to the content of XRb and XRc.
+ */
+static void gen_mxu_S32OR(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just set destination to the content of XRc */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ } else if (unlikely(XRc == 0)) {
+ /* XRc zero register -> just set destination to the content of XRb */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+/*
+ * S32XOR XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'xor' operation
+ * applied to the content of XRb and XRc.
+ */
+static void gen_mxu_S32XOR(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just set destination to the content of XRc */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ } else if (unlikely(XRc == 0)) {
+ /* XRc zero register -> just set destination to the content of XRb */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else {
+ /* the most general case */
+ tcg_gen_xor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+
+/*
+ * MXU instruction category max/min
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * S32MAX D16MAX Q8MAX
+ * S32MIN D16MIN Q8MIN
+ */
+
+/*
+ * S32MAX XRa, XRb, XRc
+ * Update XRa with the maximum of signed 32-bit integers contained
+ * in XRb and XRc.
+ *
+ * S32MIN XRa, XRb, XRc
+ * Update XRa with the minimum of signed 32-bit integers contained
+ * in XRb and XRc.
+ */
+static void gen_mxu_S32MAX_S32MIN(DisasContext *ctx)
+{
+ uint32_t pad, opc, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ opc = extract32(ctx->opcode, 18, 3);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to zero */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely((XRb == 0) || (XRc == 0))) {
+ /* exactly one operand is zero register - find which one is not...*/
+ uint32_t XRx = XRb ? XRb : XRc;
+ /* ...and do max/min operation with one operand 0 */
+ if (opc == OPC_MXU_S32MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0);
+ }
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ if (opc == OPC_MXU_S32MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1],
+ mxu_gpr[XRc - 1]);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1],
+ mxu_gpr[XRc - 1]);
+ }
+ }
+}
+
+/*
+ * D16MAX
+ * Update XRa with the 16-bit-wise maximums of signed integers
+ * contained in XRb and XRc.
+ *
+ * D16MIN
+ * Update XRa with the 16-bit-wise minimums of signed integers
+ * contained in XRb and XRc.
+ */
+static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx)
+{
+ uint32_t pad, opc, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ opc = extract32(ctx->opcode, 18, 3);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRc == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRa == 0))) {
+ /* both operands zero registers -> just set destination to zero */
+ tcg_gen_movi_i32(mxu_gpr[XRc - 1], 0);
+ } else if (unlikely((XRb == 0) || (XRa == 0))) {
+ /* exactly one operand is zero register - find which one is not...*/
+ uint32_t XRx = XRb ? XRb : XRc;
+ /* ...and do half-word-wise max/min with one operand 0 */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_const_i32(0);
+
+ /* the left half-word first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFFFF0000);
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* the right half-word */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0x0000FFFF);
+ /* move half-words to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 16);
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting half-words to its original position */
+ tcg_gen_shri_i32(t0, t0, 16);
+ /* finally update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ /* the left half-word first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFFFF0000);
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000);
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* the right half-word */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF);
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0x0000FFFF);
+ /* move half-words to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 16);
+ tcg_gen_shli_i32(t1, t1, 16);
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting half-words to its original position */
+ tcg_gen_shri_i32(t0, t0, 16);
+ /* finally update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+}
+
+/*
+ * Q8MAX
+ * Update XRa with the 8-bit-wise maximums of signed integers
+ * contained in XRb and XRc.
+ *
+ * Q8MIN
+ * Update XRa with the 8-bit-wise minimums of signed integers
+ * contained in XRb and XRc.
+ */
+static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx)
+{
+ uint32_t pad, opc, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ opc = extract32(ctx->opcode, 18, 3);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to zero */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely((XRb == 0) || (XRc == 0))) {
+ /* exactly one operand is zero register - make it be the first...*/
+ uint32_t XRx = XRb ? XRb : XRc;
+ /* ...and do byte-wise max/min with one operand 0 */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_const_i32(0);
+ int32_t i;
+
+ /* the leftmost byte (byte 3) first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF000000);
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* bytes 2, 1, 0 */
+ for (i = 2; i >= 0; i--) {
+ /* extract the byte */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF << (8 * i));
+ /* move the byte to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 8 * (3 - i));
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting byte to its original position */
+ tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
+ /* finally update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+ }
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+ int32_t i;
+
+ /* the leftmost bytes (bytes 3) first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF000000);
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000);
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* bytes 2, 1, 0 */
+ for (i = 2; i >= 0; i--) {
+ /* extract corresponding bytes */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF << (8 * i));
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF << (8 * i));
+ /* move the bytes to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 8 * (3 - i));
+ tcg_gen_shli_i32(t1, t1, 8 * (3 - i));
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting byte to its original position */
+ tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
+ /* finally update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+ }
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+}
+
+
+/*
+ * MXU instruction category: align
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * S32ALN S32ALNI
+ */
+
+/*
+ * S32ALNI XRc, XRb, XRa, optn3
+ * Arrange bytes from XRb and XRc according to one of five sets of
+ * rules determined by optn3, and place the result in XRa.
+ */
+static void gen_mxu_S32ALNI(DisasContext *ctx)
+{
+ uint32_t optn3, pad, XRc, XRb, XRa;
+
+ optn3 = extract32(ctx->opcode, 23, 3);
+ pad = extract32(ctx->opcode, 21, 2);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just appropriatelly shift XRc into XRa */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ break;
+ case MXU_OPTN3_PTN1:
+ case MXU_OPTN3_PTN2:
+ case MXU_OPTN3_PTN3:
+ tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1],
+ 8 * (4 - optn3));
+ break;
+ case MXU_OPTN3_PTN4:
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ break;
+ }
+ } else if (unlikely(XRc == 0)) {
+ /* XRc zero register -> just appropriatelly shift XRb into XRa */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ break;
+ case MXU_OPTN3_PTN1:
+ case MXU_OPTN3_PTN2:
+ case MXU_OPTN3_PTN3:
+ tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3);
+ break;
+ case MXU_OPTN3_PTN4:
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ break;
+ }
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just rotation or moving from any of them */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ case MXU_OPTN3_PTN4:
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ break;
+ case MXU_OPTN3_PTN1:
+ case MXU_OPTN3_PTN2:
+ case MXU_OPTN3_PTN3:
+ tcg_gen_rotli_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3);
+ break;
+ }
+ } else {
+ /* the most general case */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ {
+ /* */
+ /* XRb XRc */
+ /* +---------------+ */
+ /* | A B C D | E F G H */
+ /* +-------+-------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ }
+ break;
+ case MXU_OPTN3_PTN1:
+ {
+ /* */
+ /* XRb XRc */
+ /* +-------------------+ */
+ /* A | B C D E | F G H */
+ /* +---------+---------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x00FFFFFF);
+ tcg_gen_shli_i32(t0, t0, 8);
+
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000);
+ tcg_gen_shri_i32(t1, t1, 24);
+
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+ break;
+ case MXU_OPTN3_PTN2:
+ {
+ /* */
+ /* XRb XRc */
+ /* +-------------------+ */
+ /* A B | C D E F | G H */
+ /* +---------+---------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF);
+ tcg_gen_shli_i32(t0, t0, 16);
+
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000);
+ tcg_gen_shri_i32(t1, t1, 16);
+
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+ break;
+ case MXU_OPTN3_PTN3:
+ {
+ /* */
+ /* XRb XRc */
+ /* +-------------------+ */
+ /* A B C | D E F G | H */
+ /* +---------+---------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x000000FF);
+ tcg_gen_shli_i32(t0, t0, 24);
+
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFFFF00);
+ tcg_gen_shri_i32(t1, t1, 8);
+
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+ break;
+ case MXU_OPTN3_PTN4:
+ {
+ /* */
+ /* XRb XRc */
+ /* +---------------+ */
+ /* A B C D | E F G H | */
+ /* +-------+-------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ }
+ break;
+ }
+ }
+}
+
+
+/*
+ * Decoding engine for MXU
+ * =======================
+ */
+
+static void decode_opc_mxu__pool00(DisasContext *ctx)
+{
+ uint32_t opcode = extract32(ctx->opcode, 18, 3);
+
+ switch (opcode) {
+ case OPC_MXU_S32MAX:
+ case OPC_MXU_S32MIN:
+ gen_mxu_S32MAX_S32MIN(ctx);
+ break;
+ case OPC_MXU_D16MAX:
+ case OPC_MXU_D16MIN:
+ gen_mxu_D16MAX_D16MIN(ctx);
+ break;
+ case OPC_MXU_Q8MAX:
+ case OPC_MXU_Q8MIN:
+ gen_mxu_Q8MAX_Q8MIN(ctx);
+ break;
+ default:
+ MIPS_INVAL("decode_opc_mxu");
+ gen_reserved_instruction(ctx);
+ break;
+ }
+}
+
+static void decode_opc_mxu__pool04(DisasContext *ctx)
+{
+ uint32_t opcode = extract32(ctx->opcode, 20, 1);
+
+ switch (opcode) {
+ case OPC_MXU_S32LDD:
+ case OPC_MXU_S32LDDR:
+ gen_mxu_s32ldd_s32lddr(ctx);
+ break;
+ default:
+ MIPS_INVAL("decode_opc_mxu");
+ gen_reserved_instruction(ctx);
+ break;
+ }
+}
+
+static void decode_opc_mxu__pool16(DisasContext *ctx)
+{
+ uint32_t opcode = extract32(ctx->opcode, 18, 3);
+
+ switch (opcode) {
+ case OPC_MXU_S32ALNI:
+ gen_mxu_S32ALNI(ctx);
+ break;
+ case OPC_MXU_S32NOR:
+ gen_mxu_S32NOR(ctx);
+ break;
+ case OPC_MXU_S32AND:
+ gen_mxu_S32AND(ctx);
+ break;
+ case OPC_MXU_S32OR:
+ gen_mxu_S32OR(ctx);
+ break;
+ case OPC_MXU_S32XOR:
+ gen_mxu_S32XOR(ctx);
+ break;
+ default:
+ MIPS_INVAL("decode_opc_mxu");
+ gen_reserved_instruction(ctx);
+ break;
+ }
+}
+
+static void decode_opc_mxu__pool19(DisasContext *ctx)
+{
+ uint32_t opcode = extract32(ctx->opcode, 22, 2);
+
+ switch (opcode) {
+ case OPC_MXU_Q8MUL:
+ case OPC_MXU_Q8MULSU:
+ gen_mxu_q8mul_q8mulsu(ctx);
+ break;
+ default:
+ MIPS_INVAL("decode_opc_mxu");
+ gen_reserved_instruction(ctx);
+ break;
+ }
+}
+
+bool decode_ase_mxu(DisasContext *ctx, uint32_t insn)
+{
+ uint32_t opcode = extract32(insn, 0, 6);
+
+ if (opcode == OPC_MXU_S32M2I) {
+ gen_mxu_s32m2i(ctx);
+ return true;
+ }
+
+ if (opcode == OPC_MXU_S32I2M) {
+ gen_mxu_s32i2m(ctx);
+ return true;
+ }
+
+ {
+ TCGv t_mxu_cr = tcg_temp_new();
+ TCGLabel *l_exit = gen_new_label();
+
+ gen_load_mxu_cr(t_mxu_cr);
+ tcg_gen_andi_tl(t_mxu_cr, t_mxu_cr, MXU_CR_MXU_EN);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t_mxu_cr, MXU_CR_MXU_EN, l_exit);
+
+ switch (opcode) {
+ case OPC_MXU__POOL00:
+ decode_opc_mxu__pool00(ctx);
+ break;
+ case OPC_MXU_D16MUL:
+ gen_mxu_d16mul(ctx);
+ break;
+ case OPC_MXU_D16MAC:
+ gen_mxu_d16mac(ctx);
+ break;
+ case OPC_MXU__POOL04:
+ decode_opc_mxu__pool04(ctx);
+ break;
+ case OPC_MXU_S8LDD:
+ gen_mxu_s8ldd(ctx);
+ break;
+ case OPC_MXU__POOL16:
+ decode_opc_mxu__pool16(ctx);
+ break;
+ case OPC_MXU__POOL19:
+ decode_opc_mxu__pool19(ctx);
+ break;
+ default:
+ MIPS_INVAL("decode_opc_mxu");
+ gen_reserved_instruction(ctx);
+ }
+
+ gen_set_label(l_exit);
+ tcg_temp_free(t_mxu_cr);
+ }
+
+ return true;
+}
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 0b6d82d228..c518bf3963 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -1130,779 +1130,6 @@ enum {
};
/*
- *
- * AN OVERVIEW OF MXU EXTENSION INSTRUCTION SET
- * ============================================
- *
- *
- * MXU (full name: MIPS eXtension/enhanced Unit) is a SIMD extension of MIPS32
- * instructions set. It is designed to fit the needs of signal, graphical and
- * video processing applications. MXU instruction set is used in Xburst family
- * of microprocessors by Ingenic.
- *
- * MXU unit contains 17 registers called X0-X16. X0 is always zero, and X16 is
- * the control register.
- *
- *
- * The notation used in MXU assembler mnemonics
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * Register operands:
- *
- * XRa, XRb, XRc, XRd - MXU registers
- * Rb, Rc, Rd, Rs, Rt - general purpose MIPS registers
- *
- * Non-register operands:
- *
- * aptn1 - 1-bit accumulate add/subtract pattern
- * aptn2 - 2-bit accumulate add/subtract pattern
- * eptn2 - 2-bit execute add/subtract pattern
- * optn2 - 2-bit operand pattern
- * optn3 - 3-bit operand pattern
- * sft4 - 4-bit shift amount
- * strd2 - 2-bit stride amount
- *
- * Prefixes:
- *
- * Level of parallelism: Operand size:
- * S - single operation at a time 32 - word
- * D - two operations in parallel 16 - half word
- * Q - four operations in parallel 8 - byte
- *
- * Operations:
- *
- * ADD - Add or subtract
- * ADDC - Add with carry-in
- * ACC - Accumulate
- * ASUM - Sum together then accumulate (add or subtract)
- * ASUMC - Sum together then accumulate (add or subtract) with carry-in
- * AVG - Average between 2 operands
- * ABD - Absolute difference
- * ALN - Align data
- * AND - Logical bitwise 'and' operation
- * CPS - Copy sign
- * EXTR - Extract bits
- * I2M - Move from GPR register to MXU register
- * LDD - Load data from memory to XRF
- * LDI - Load data from memory to XRF (and increase the address base)
- * LUI - Load unsigned immediate
- * MUL - Multiply
- * MULU - Unsigned multiply
- * MADD - 64-bit operand add 32x32 product
- * MSUB - 64-bit operand subtract 32x32 product
- * MAC - Multiply and accumulate (add or subtract)
- * MAD - Multiply and add or subtract
- * MAX - Maximum between 2 operands
- * MIN - Minimum between 2 operands
- * M2I - Move from MXU register to GPR register
- * MOVZ - Move if zero
- * MOVN - Move if non-zero
- * NOR - Logical bitwise 'nor' operation
- * OR - Logical bitwise 'or' operation
- * STD - Store data from XRF to memory
- * SDI - Store data from XRF to memory (and increase the address base)
- * SLT - Set of less than comparison
- * SAD - Sum of absolute differences
- * SLL - Logical shift left
- * SLR - Logical shift right
- * SAR - Arithmetic shift right
- * SAT - Saturation
- * SFL - Shuffle
- * SCOP - Calculate x’s scope (-1, means x<0; 0, means x==0; 1, means x>0)
- * XOR - Logical bitwise 'exclusive or' operation
- *
- * Suffixes:
- *
- * E - Expand results
- * F - Fixed point multiplication
- * L - Low part result
- * R - Doing rounding
- * V - Variable instead of immediate
- * W - Combine above L and V
- *
- *
- * The list of MXU instructions grouped by functionality
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * Load/Store instructions Multiplication instructions
- * ----------------------- ---------------------------
- *
- * S32LDD XRa, Rb, s12 S32MADD XRa, XRd, Rs, Rt
- * S32STD XRa, Rb, s12 S32MADDU XRa, XRd, Rs, Rt
- * S32LDDV XRa, Rb, rc, strd2 S32MSUB XRa, XRd, Rs, Rt
- * S32STDV XRa, Rb, rc, strd2 S32MSUBU XRa, XRd, Rs, Rt
- * S32LDI XRa, Rb, s12 S32MUL XRa, XRd, Rs, Rt
- * S32SDI XRa, Rb, s12 S32MULU XRa, XRd, Rs, Rt
- * S32LDIV XRa, Rb, rc, strd2 D16MUL XRa, XRb, XRc, XRd, optn2
- * S32SDIV XRa, Rb, rc, strd2 D16MULE XRa, XRb, XRc, optn2
- * S32LDDR XRa, Rb, s12 D16MULF XRa, XRb, XRc, optn2
- * S32STDR XRa, Rb, s12 D16MAC XRa, XRb, XRc, XRd, aptn2, optn2
- * S32LDDVR XRa, Rb, rc, strd2 D16MACE XRa, XRb, XRc, XRd, aptn2, optn2
- * S32STDVR XRa, Rb, rc, strd2 D16MACF XRa, XRb, XRc, XRd, aptn2, optn2
- * S32LDIR XRa, Rb, s12 D16MADL XRa, XRb, XRc, XRd, aptn2, optn2
- * S32SDIR XRa, Rb, s12 S16MAD XRa, XRb, XRc, XRd, aptn1, optn2
- * S32LDIVR XRa, Rb, rc, strd2 Q8MUL XRa, XRb, XRc, XRd
- * S32SDIVR XRa, Rb, rc, strd2 Q8MULSU XRa, XRb, XRc, XRd
- * S16LDD XRa, Rb, s10, eptn2 Q8MAC XRa, XRb, XRc, XRd, aptn2
- * S16STD XRa, Rb, s10, eptn2 Q8MACSU XRa, XRb, XRc, XRd, aptn2
- * S16LDI XRa, Rb, s10, eptn2 Q8MADL XRa, XRb, XRc, XRd, aptn2
- * S16SDI XRa, Rb, s10, eptn2
- * S8LDD XRa, Rb, s8, eptn3
- * S8STD XRa, Rb, s8, eptn3 Addition and subtraction instructions
- * S8LDI XRa, Rb, s8, eptn3 -------------------------------------
- * S8SDI XRa, Rb, s8, eptn3
- * LXW Rd, Rs, Rt, strd2 D32ADD XRa, XRb, XRc, XRd, eptn2
- * LXH Rd, Rs, Rt, strd2 D32ADDC XRa, XRb, XRc, XRd
- * LXHU Rd, Rs, Rt, strd2 D32ACC XRa, XRb, XRc, XRd, eptn2
- * LXB Rd, Rs, Rt, strd2 D32ACCM XRa, XRb, XRc, XRd, eptn2
- * LXBU Rd, Rs, Rt, strd2 D32ASUM XRa, XRb, XRc, XRd, eptn2
- * S32CPS XRa, XRb, XRc
- * Q16ADD XRa, XRb, XRc, XRd, eptn2, optn2
- * Comparison instructions Q16ACC XRa, XRb, XRc, XRd, eptn2
- * ----------------------- Q16ACCM XRa, XRb, XRc, XRd, eptn2
- * D16ASUM XRa, XRb, XRc, XRd, eptn2
- * S32MAX XRa, XRb, XRc D16CPS XRa, XRb,
- * S32MIN XRa, XRb, XRc D16AVG XRa, XRb, XRc
- * S32SLT XRa, XRb, XRc D16AVGR XRa, XRb, XRc
- * S32MOVZ XRa, XRb, XRc Q8ADD XRa, XRb, XRc, eptn2
- * S32MOVN XRa, XRb, XRc Q8ADDE XRa, XRb, XRc, XRd, eptn2
- * D16MAX XRa, XRb, XRc Q8ACCE XRa, XRb, XRc, XRd, eptn2
- * D16MIN XRa, XRb, XRc Q8ABD XRa, XRb, XRc
- * D16SLT XRa, XRb, XRc Q8SAD XRa, XRb, XRc, XRd
- * D16MOVZ XRa, XRb, XRc Q8AVG XRa, XRb, XRc
- * D16MOVN XRa, XRb, XRc Q8AVGR XRa, XRb, XRc
- * Q8MAX XRa, XRb, XRc D8SUM XRa, XRb, XRc, XRd
- * Q8MIN XRa, XRb, XRc D8SUMC XRa, XRb, XRc, XRd
- * Q8SLT XRa, XRb, XRc
- * Q8SLTU XRa, XRb, XRc
- * Q8MOVZ XRa, XRb, XRc Shift instructions
- * Q8MOVN XRa, XRb, XRc ------------------
- *
- * D32SLL XRa, XRb, XRc, XRd, sft4
- * Bitwise instructions D32SLR XRa, XRb, XRc, XRd, sft4
- * -------------------- D32SAR XRa, XRb, XRc, XRd, sft4
- * D32SARL XRa, XRb, XRc, sft4
- * S32NOR XRa, XRb, XRc D32SLLV XRa, XRb, Rb
- * S32AND XRa, XRb, XRc D32SLRV XRa, XRb, Rb
- * S32XOR XRa, XRb, XRc D32SARV XRa, XRb, Rb
- * S32OR XRa, XRb, XRc D32SARW XRa, XRb, XRc, Rb
- * Q16SLL XRa, XRb, XRc, XRd, sft4
- * Q16SLR XRa, XRb, XRc, XRd, sft4
- * Miscellaneous instructions Q16SAR XRa, XRb, XRc, XRd, sft4
- * ------------------------- Q16SLLV XRa, XRb, Rb
- * Q16SLRV XRa, XRb, Rb
- * S32SFL XRa, XRb, XRc, XRd, optn2 Q16SARV XRa, XRb, Rb
- * S32ALN XRa, XRb, XRc, Rb
- * S32ALNI XRa, XRb, XRc, s3
- * S32LUI XRa, s8, optn3 Move instructions
- * S32EXTR XRa, XRb, Rb, bits5 -----------------
- * S32EXTRV XRa, XRb, Rs, Rt
- * Q16SCOP XRa, XRb, XRc, XRd S32M2I XRa, Rb
- * Q16SAT XRa, XRb, XRc S32I2M XRa, Rb
- *
- *
- * The opcode organization of MXU instructions
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * The bits 31..26 of all MXU instructions are equal to 0x1C (also referred
- * as opcode SPECIAL2 in the base MIPS ISA). The organization and meaning of
- * other bits up to the instruction level is as follows:
- *
- * bits
- * 05..00
- *
- * ┌─ 000000 ─ OPC_MXU_S32MADD
- * ├─ 000001 ─ OPC_MXU_S32MADDU
- * ├─ 000010 ─ <not assigned> (non-MXU OPC_MUL)
- * │
- * │ 20..18
- * ├─ 000011 ─ OPC_MXU__POOL00 ─┬─ 000 ─ OPC_MXU_S32MAX
- * │ ├─ 001 ─ OPC_MXU_S32MIN
- * │ ├─ 010 ─ OPC_MXU_D16MAX
- * │ ├─ 011 ─ OPC_MXU_D16MIN
- * │ ├─ 100 ─ OPC_MXU_Q8MAX
- * │ ├─ 101 ─ OPC_MXU_Q8MIN
- * │ ├─ 110 ─ OPC_MXU_Q8SLT
- * │ └─ 111 ─ OPC_MXU_Q8SLTU
- * ├─ 000100 ─ OPC_MXU_S32MSUB
- * ├─ 000101 ─ OPC_MXU_S32MSUBU 20..18
- * ├─ 000110 ─ OPC_MXU__POOL01 ─┬─ 000 ─ OPC_MXU_S32SLT
- * │ ├─ 001 ─ OPC_MXU_D16SLT
- * │ ├─ 010 ─ OPC_MXU_D16AVG
- * │ ├─ 011 ─ OPC_MXU_D16AVGR
- * │ ├─ 100 ─ OPC_MXU_Q8AVG
- * │ ├─ 101 ─ OPC_MXU_Q8AVGR
- * │ └─ 111 ─ OPC_MXU_Q8ADD
- * │
- * │ 20..18
- * ├─ 000111 ─ OPC_MXU__POOL02 ─┬─ 000 ─ OPC_MXU_S32CPS
- * │ ├─ 010 ─ OPC_MXU_D16CPS
- * │ ├─ 100 ─ OPC_MXU_Q8ABD
- * │ └─ 110 ─ OPC_MXU_Q16SAT
- * ├─ 001000 ─ OPC_MXU_D16MUL
- * │ 25..24
- * ├─ 001001 ─ OPC_MXU__POOL03 ─┬─ 00 ─ OPC_MXU_D16MULF
- * │ └─ 01 ─ OPC_MXU_D16MULE
- * ├─ 001010 ─ OPC_MXU_D16MAC
- * ├─ 001011 ─ OPC_MXU_D16MACF
- * ├─ 001100 ─ OPC_MXU_D16MADL
- * ├─ 001101 ─ OPC_MXU_S16MAD
- * ├─ 001110 ─ OPC_MXU_Q16ADD
- * ├─ 001111 ─ OPC_MXU_D16MACE 23
- * │ ┌─ 0 ─ OPC_MXU_S32LDD
- * ├─ 010000 ─ OPC_MXU__POOL04 ─┴─ 1 ─ OPC_MXU_S32LDDR
- * │
- * │ 23
- * ├─ 010001 ─ OPC_MXU__POOL05 ─┬─ 0 ─ OPC_MXU_S32STD
- * │ └─ 1 ─ OPC_MXU_S32STDR
- * │
- * │ 13..10
- * ├─ 010010 ─ OPC_MXU__POOL06 ─┬─ 0000 ─ OPC_MXU_S32LDDV
- * │ └─ 0001 ─ OPC_MXU_S32LDDVR
- * │
- * │ 13..10
- * ├─ 010011 ─ OPC_MXU__POOL07 ─┬─ 0000 ─ OPC_MXU_S32STDV
- * │ └─ 0001 ─ OPC_MXU_S32STDVR
- * │
- * │ 23
- * ├─ 010100 ─ OPC_MXU__POOL08 ─┬─ 0 ─ OPC_MXU_S32LDI
- * │ └─ 1 ─ OPC_MXU_S32LDIR
- * │
- * │ 23
- * ├─ 010101 ─ OPC_MXU__POOL09 ─┬─ 0 ─ OPC_MXU_S32SDI
- * │ └─ 1 ─ OPC_MXU_S32SDIR
- * │
- * │ 13..10
- * ├─ 010110 ─ OPC_MXU__POOL10 ─┬─ 0000 ─ OPC_MXU_S32LDIV
- * │ └─ 0001 ─ OPC_MXU_S32LDIVR
- * │
- * │ 13..10
- * ├─ 010111 ─ OPC_MXU__POOL11 ─┬─ 0000 ─ OPC_MXU_S32SDIV
- * │ └─ 0001 ─ OPC_MXU_S32SDIVR
- * ├─ 011000 ─ OPC_MXU_D32ADD
- * │ 23..22
- * MXU ├─ 011001 ─ OPC_MXU__POOL12 ─┬─ 00 ─ OPC_MXU_D32ACC
- * opcodes ─┤ ├─ 01 ─ OPC_MXU_D32ACCM
- * │ └─ 10 ─ OPC_MXU_D32ASUM
- * ├─ 011010 ─ <not assigned>
- * │ 23..22
- * ├─ 011011 ─ OPC_MXU__POOL13 ─┬─ 00 ─ OPC_MXU_Q16ACC
- * │ ├─ 01 ─ OPC_MXU_Q16ACCM
- * │ └─ 10 ─ OPC_MXU_Q16ASUM
- * │
- * │ 23..22
- * ├─ 011100 ─ OPC_MXU__POOL14 ─┬─ 00 ─ OPC_MXU_Q8ADDE
- * │ ├─ 01 ─ OPC_MXU_D8SUM
- * ├─ 011101 ─ OPC_MXU_Q8ACCE └─ 10 ─ OPC_MXU_D8SUMC
- * ├─ 011110 ─ <not assigned>
- * ├─ 011111 ─ <not assigned>
- * ├─ 100000 ─ <not assigned> (overlaps with CLZ)
- * ├─ 100001 ─ <not assigned> (overlaps with CLO)
- * ├─ 100010 ─ OPC_MXU_S8LDD
- * ├─ 100011 ─ OPC_MXU_S8STD 15..14
- * ├─ 100100 ─ OPC_MXU_S8LDI ┌─ 00 ─ OPC_MXU_S32MUL
- * ├─ 100101 ─ OPC_MXU_S8SDI ├─ 00 ─ OPC_MXU_S32MULU
- * │ ├─ 00 ─ OPC_MXU_S32EXTR
- * ├─ 100110 ─ OPC_MXU__POOL15 ─┴─ 00 ─ OPC_MXU_S32EXTRV
- * │
- * │ 20..18
- * ├─ 100111 ─ OPC_MXU__POOL16 ─┬─ 000 ─ OPC_MXU_D32SARW
- * │ ├─ 001 ─ OPC_MXU_S32ALN
- * │ ├─ 010 ─ OPC_MXU_S32ALNI
- * │ ├─ 011 ─ OPC_MXU_S32LUI
- * │ ├─ 100 ─ OPC_MXU_S32NOR
- * │ ├─ 101 ─ OPC_MXU_S32AND
- * │ ├─ 110 ─ OPC_MXU_S32OR
- * │ └─ 111 ─ OPC_MXU_S32XOR
- * │
- * │ 7..5
- * ├─ 101000 ─ OPC_MXU__POOL17 ─┬─ 000 ─ OPC_MXU_LXB
- * │ ├─ 001 ─ OPC_MXU_LXH
- * ├─ 101001 ─ <not assigned> ├─ 011 ─ OPC_MXU_LXW
- * ├─ 101010 ─ OPC_MXU_S16LDD ├─ 100 ─ OPC_MXU_LXBU
- * ├─ 101011 ─ OPC_MXU_S16STD └─ 101 ─ OPC_MXU_LXHU
- * ├─ 101100 ─ OPC_MXU_S16LDI
- * ├─ 101101 ─ OPC_MXU_S16SDI
- * ├─ 101110 ─ OPC_MXU_S32M2I
- * ├─ 101111 ─ OPC_MXU_S32I2M
- * ├─ 110000 ─ OPC_MXU_D32SLL
- * ├─ 110001 ─ OPC_MXU_D32SLR 20..18
- * ├─ 110010 ─ OPC_MXU_D32SARL ┌─ 000 ─ OPC_MXU_D32SLLV
- * ├─ 110011 ─ OPC_MXU_D32SAR ├─ 001 ─ OPC_MXU_D32SLRV
- * ├─ 110100 ─ OPC_MXU_Q16SLL ├─ 010 ─ OPC_MXU_D32SARV
- * ├─ 110101 ─ OPC_MXU_Q16SLR ├─ 011 ─ OPC_MXU_Q16SLLV
- * │ ├─ 100 ─ OPC_MXU_Q16SLRV
- * ├─ 110110 ─ OPC_MXU__POOL18 ─┴─ 101 ─ OPC_MXU_Q16SARV
- * │
- * ├─ 110111 ─ OPC_MXU_Q16SAR
- * │ 23..22
- * ├─ 111000 ─ OPC_MXU__POOL19 ─┬─ 00 ─ OPC_MXU_Q8MUL
- * │ └─ 01 ─ OPC_MXU_Q8MULSU
- * │
- * │ 20..18
- * ├─ 111001 ─ OPC_MXU__POOL20 ─┬─ 000 ─ OPC_MXU_Q8MOVZ
- * │ ├─ 001 ─ OPC_MXU_Q8MOVN
- * │ ├─ 010 ─ OPC_MXU_D16MOVZ
- * │ ├─ 011 ─ OPC_MXU_D16MOVN
- * │ ├─ 100 ─ OPC_MXU_S32MOVZ
- * │ └─ 101 ─ OPC_MXU_S32MOVN
- * │
- * │ 23..22
- * ├─ 111010 ─ OPC_MXU__POOL21 ─┬─ 00 ─ OPC_MXU_Q8MAC
- * │ └─ 10 ─ OPC_MXU_Q8MACSU
- * ├─ 111011 ─ OPC_MXU_Q16SCOP
- * ├─ 111100 ─ OPC_MXU_Q8MADL
- * ├─ 111101 ─ OPC_MXU_S32SFL
- * ├─ 111110 ─ OPC_MXU_Q8SAD
- * └─ 111111 ─ <not assigned> (overlaps with SDBBP)
- *
- *
- * Compiled after:
- *
- * "XBurst® Instruction Set Architecture MIPS eXtension/enhanced Unit
- * Programming Manual", Ingenic Semiconductor Co, Ltd., revision June 2, 2017
- */
-
-enum {
- OPC_MXU_S32MADD = 0x00,
- OPC_MXU_S32MADDU = 0x01,
- OPC__MXU_MUL = 0x02,
- OPC_MXU__POOL00 = 0x03,
- OPC_MXU_S32MSUB = 0x04,
- OPC_MXU_S32MSUBU = 0x05,
- OPC_MXU__POOL01 = 0x06,
- OPC_MXU__POOL02 = 0x07,
- OPC_MXU_D16MUL = 0x08,
- OPC_MXU__POOL03 = 0x09,
- OPC_MXU_D16MAC = 0x0A,
- OPC_MXU_D16MACF = 0x0B,
- OPC_MXU_D16MADL = 0x0C,
- OPC_MXU_S16MAD = 0x0D,
- OPC_MXU_Q16ADD = 0x0E,
- OPC_MXU_D16MACE = 0x0F,
- OPC_MXU__POOL04 = 0x10,
- OPC_MXU__POOL05 = 0x11,
- OPC_MXU__POOL06 = 0x12,
- OPC_MXU__POOL07 = 0x13,
- OPC_MXU__POOL08 = 0x14,
- OPC_MXU__POOL09 = 0x15,
- OPC_MXU__POOL10 = 0x16,
- OPC_MXU__POOL11 = 0x17,
- OPC_MXU_D32ADD = 0x18,
- OPC_MXU__POOL12 = 0x19,
- /* not assigned 0x1A */
- OPC_MXU__POOL13 = 0x1B,
- OPC_MXU__POOL14 = 0x1C,
- OPC_MXU_Q8ACCE = 0x1D,
- /* not assigned 0x1E */
- /* not assigned 0x1F */
- /* not assigned 0x20 */
- /* not assigned 0x21 */
- OPC_MXU_S8LDD = 0x22,
- OPC_MXU_S8STD = 0x23,
- OPC_MXU_S8LDI = 0x24,
- OPC_MXU_S8SDI = 0x25,
- OPC_MXU__POOL15 = 0x26,
- OPC_MXU__POOL16 = 0x27,
- OPC_MXU__POOL17 = 0x28,
- /* not assigned 0x29 */
- OPC_MXU_S16LDD = 0x2A,
- OPC_MXU_S16STD = 0x2B,
- OPC_MXU_S16LDI = 0x2C,
- OPC_MXU_S16SDI = 0x2D,
- OPC_MXU_S32M2I = 0x2E,
- OPC_MXU_S32I2M = 0x2F,
- OPC_MXU_D32SLL = 0x30,
- OPC_MXU_D32SLR = 0x31,
- OPC_MXU_D32SARL = 0x32,
- OPC_MXU_D32SAR = 0x33,
- OPC_MXU_Q16SLL = 0x34,
- OPC_MXU_Q16SLR = 0x35,
- OPC_MXU__POOL18 = 0x36,
- OPC_MXU_Q16SAR = 0x37,
- OPC_MXU__POOL19 = 0x38,
- OPC_MXU__POOL20 = 0x39,
- OPC_MXU__POOL21 = 0x3A,
- OPC_MXU_Q16SCOP = 0x3B,
- OPC_MXU_Q8MADL = 0x3C,
- OPC_MXU_S32SFL = 0x3D,
- OPC_MXU_Q8SAD = 0x3E,
- /* not assigned 0x3F */
-};
-
-
-/*
- * MXU pool 00
- */
-enum {
- OPC_MXU_S32MAX = 0x00,
- OPC_MXU_S32MIN = 0x01,
- OPC_MXU_D16MAX = 0x02,
- OPC_MXU_D16MIN = 0x03,
- OPC_MXU_Q8MAX = 0x04,
- OPC_MXU_Q8MIN = 0x05,
- OPC_MXU_Q8SLT = 0x06,
- OPC_MXU_Q8SLTU = 0x07,
-};
-
-/*
- * MXU pool 01
- */
-enum {
- OPC_MXU_S32SLT = 0x00,
- OPC_MXU_D16SLT = 0x01,
- OPC_MXU_D16AVG = 0x02,
- OPC_MXU_D16AVGR = 0x03,
- OPC_MXU_Q8AVG = 0x04,
- OPC_MXU_Q8AVGR = 0x05,
- OPC_MXU_Q8ADD = 0x07,
-};
-
-/*
- * MXU pool 02
- */
-enum {
- OPC_MXU_S32CPS = 0x00,
- OPC_MXU_D16CPS = 0x02,
- OPC_MXU_Q8ABD = 0x04,
- OPC_MXU_Q16SAT = 0x06,
-};
-
-/*
- * MXU pool 03
- */
-enum {
- OPC_MXU_D16MULF = 0x00,
- OPC_MXU_D16MULE = 0x01,
-};
-
-/*
- * MXU pool 04
- */
-enum {
- OPC_MXU_S32LDD = 0x00,
- OPC_MXU_S32LDDR = 0x01,
-};
-
-/*
- * MXU pool 05
- */
-enum {
- OPC_MXU_S32STD = 0x00,
- OPC_MXU_S32STDR = 0x01,
-};
-
-/*
- * MXU pool 06
- */
-enum {
- OPC_MXU_S32LDDV = 0x00,
- OPC_MXU_S32LDDVR = 0x01,
-};
-
-/*
- * MXU pool 07
- */
-enum {
- OPC_MXU_S32STDV = 0x00,
- OPC_MXU_S32STDVR = 0x01,
-};
-
-/*
- * MXU pool 08
- */
-enum {
- OPC_MXU_S32LDI = 0x00,
- OPC_MXU_S32LDIR = 0x01,
-};
-
-/*
- * MXU pool 09
- */
-enum {
- OPC_MXU_S32SDI = 0x00,
- OPC_MXU_S32SDIR = 0x01,
-};
-
-/*
- * MXU pool 10
- */
-enum {
- OPC_MXU_S32LDIV = 0x00,
- OPC_MXU_S32LDIVR = 0x01,
-};
-
-/*
- * MXU pool 11
- */
-enum {
- OPC_MXU_S32SDIV = 0x00,
- OPC_MXU_S32SDIVR = 0x01,
-};
-
-/*
- * MXU pool 12
- */
-enum {
- OPC_MXU_D32ACC = 0x00,
- OPC_MXU_D32ACCM = 0x01,
- OPC_MXU_D32ASUM = 0x02,
-};
-
-/*
- * MXU pool 13
- */
-enum {
- OPC_MXU_Q16ACC = 0x00,
- OPC_MXU_Q16ACCM = 0x01,
- OPC_MXU_Q16ASUM = 0x02,
-};
-
-/*
- * MXU pool 14
- */
-enum {
- OPC_MXU_Q8ADDE = 0x00,
- OPC_MXU_D8SUM = 0x01,
- OPC_MXU_D8SUMC = 0x02,
-};
-
-/*
- * MXU pool 15
- */
-enum {
- OPC_MXU_S32MUL = 0x00,
- OPC_MXU_S32MULU = 0x01,
- OPC_MXU_S32EXTR = 0x02,
- OPC_MXU_S32EXTRV = 0x03,
-};
-
-/*
- * MXU pool 16
- */
-enum {
- OPC_MXU_D32SARW = 0x00,
- OPC_MXU_S32ALN = 0x01,
- OPC_MXU_S32ALNI = 0x02,
- OPC_MXU_S32LUI = 0x03,
- OPC_MXU_S32NOR = 0x04,
- OPC_MXU_S32AND = 0x05,
- OPC_MXU_S32OR = 0x06,
- OPC_MXU_S32XOR = 0x07,
-};
-
-/*
- * MXU pool 17
- */
-enum {
- OPC_MXU_LXB = 0x00,
- OPC_MXU_LXH = 0x01,
- OPC_MXU_LXW = 0x03,
- OPC_MXU_LXBU = 0x04,
- OPC_MXU_LXHU = 0x05,
-};
-
-/*
- * MXU pool 18
- */
-enum {
- OPC_MXU_D32SLLV = 0x00,
- OPC_MXU_D32SLRV = 0x01,
- OPC_MXU_D32SARV = 0x03,
- OPC_MXU_Q16SLLV = 0x04,
- OPC_MXU_Q16SLRV = 0x05,
- OPC_MXU_Q16SARV = 0x07,
-};
-
-/*
- * MXU pool 19
- */
-enum {
- OPC_MXU_Q8MUL = 0x00,
- OPC_MXU_Q8MULSU = 0x01,
-};
-
-/*
- * MXU pool 20
- */
-enum {
- OPC_MXU_Q8MOVZ = 0x00,
- OPC_MXU_Q8MOVN = 0x01,
- OPC_MXU_D16MOVZ = 0x02,
- OPC_MXU_D16MOVN = 0x03,
- OPC_MXU_S32MOVZ = 0x04,
- OPC_MXU_S32MOVN = 0x05,
-};
-
-/*
- * MXU pool 21
- */
-enum {
- OPC_MXU_Q8MAC = 0x00,
- OPC_MXU_Q8MACSU = 0x01,
-};
-
-/*
- * Overview of the TX79-specific instruction set
- * =============================================
- *
- * The R5900 and the C790 have 128-bit wide GPRs, where the upper 64 bits
- * are only used by the specific quadword (128-bit) LQ/SQ load/store
- * instructions and certain multimedia instructions (MMIs). These MMIs
- * configure the 128-bit data path as two 64-bit, four 32-bit, eight 16-bit
- * or sixteen 8-bit paths.
- *
- * Reference:
- *
- * The Toshiba TX System RISC TX79 Core Architecture manual,
- * https://wiki.qemu.org/File:C790.pdf
- *
- * Three-Operand Multiply and Multiply-Add (4 instructions)
- * --------------------------------------------------------
- * MADD [rd,] rs, rt Multiply/Add
- * MADDU [rd,] rs, rt Multiply/Add Unsigned
- * MULT [rd,] rs, rt Multiply (3-operand)
- * MULTU [rd,] rs, rt Multiply Unsigned (3-operand)
- *
- * Multiply Instructions for Pipeline 1 (10 instructions)
- * ------------------------------------------------------
- * MULT1 [rd,] rs, rt Multiply Pipeline 1
- * MULTU1 [rd,] rs, rt Multiply Unsigned Pipeline 1
- * DIV1 rs, rt Divide Pipeline 1
- * DIVU1 rs, rt Divide Unsigned Pipeline 1
- * MADD1 [rd,] rs, rt Multiply-Add Pipeline 1
- * MADDU1 [rd,] rs, rt Multiply-Add Unsigned Pipeline 1
- * MFHI1 rd Move From HI1 Register
- * MFLO1 rd Move From LO1 Register
- * MTHI1 rs Move To HI1 Register
- * MTLO1 rs Move To LO1 Register
- *
- * Arithmetic (19 instructions)
- * ----------------------------
- * PADDB rd, rs, rt Parallel Add Byte
- * PSUBB rd, rs, rt Parallel Subtract Byte
- * PADDH rd, rs, rt Parallel Add Halfword
- * PSUBH rd, rs, rt Parallel Subtract Halfword
- * PADDW rd, rs, rt Parallel Add Word
- * PSUBW rd, rs, rt Parallel Subtract Word
- * PADSBH rd, rs, rt Parallel Add/Subtract Halfword
- * PADDSB rd, rs, rt Parallel Add with Signed Saturation Byte
- * PSUBSB rd, rs, rt Parallel Subtract with Signed Saturation Byte
- * PADDSH rd, rs, rt Parallel Add with Signed Saturation Halfword
- * PSUBSH rd, rs, rt Parallel Subtract with Signed Saturation Halfword
- * PADDSW rd, rs, rt Parallel Add with Signed Saturation Word
- * PSUBSW rd, rs, rt Parallel Subtract with Signed Saturation Word
- * PADDUB rd, rs, rt Parallel Add with Unsigned saturation Byte
- * PSUBUB rd, rs, rt Parallel Subtract with Unsigned saturation Byte
- * PADDUH rd, rs, rt Parallel Add with Unsigned saturation Halfword
- * PSUBUH rd, rs, rt Parallel Subtract with Unsigned saturation Halfword
- * PADDUW rd, rs, rt Parallel Add with Unsigned saturation Word
- * PSUBUW rd, rs, rt Parallel Subtract with Unsigned saturation Word
- *
- * Min/Max (4 instructions)
- * ------------------------
- * PMAXH rd, rs, rt Parallel Maximum Halfword
- * PMINH rd, rs, rt Parallel Minimum Halfword
- * PMAXW rd, rs, rt Parallel Maximum Word
- * PMINW rd, rs, rt Parallel Minimum Word
- *
- * Absolute (2 instructions)
- * -------------------------
- * PABSH rd, rt Parallel Absolute Halfword
- * PABSW rd, rt Parallel Absolute Word
- *
- * Logical (4 instructions)
- * ------------------------
- * PAND rd, rs, rt Parallel AND
- * POR rd, rs, rt Parallel OR
- * PXOR rd, rs, rt Parallel XOR
- * PNOR rd, rs, rt Parallel NOR
- *
- * Shift (9 instructions)
- * ----------------------
- * PSLLH rd, rt, sa Parallel Shift Left Logical Halfword
- * PSRLH rd, rt, sa Parallel Shift Right Logical Halfword
- * PSRAH rd, rt, sa Parallel Shift Right Arithmetic Halfword
- * PSLLW rd, rt, sa Parallel Shift Left Logical Word
- * PSRLW rd, rt, sa Parallel Shift Right Logical Word
- * PSRAW rd, rt, sa Parallel Shift Right Arithmetic Word
- * PSLLVW rd, rt, rs Parallel Shift Left Logical Variable Word
- * PSRLVW rd, rt, rs Parallel Shift Right Logical Variable Word
- * PSRAVW rd, rt, rs Parallel Shift Right Arithmetic Variable Word
- *
- * Compare (6 instructions)
- * ------------------------
- * PCGTB rd, rs, rt Parallel Compare for Greater Than Byte
- * PCEQB rd, rs, rt Parallel Compare for Equal Byte
- * PCGTH rd, rs, rt Parallel Compare for Greater Than Halfword
- * PCEQH rd, rs, rt Parallel Compare for Equal Halfword
- * PCGTW rd, rs, rt Parallel Compare for Greater Than Word
- * PCEQW rd, rs, rt Parallel Compare for Equal Word
- *
- * LZC (1 instruction)
- * -------------------
- * PLZCW rd, rs Parallel Leading Zero or One Count Word
- *
- * Quadword Load and Store (2 instructions)
- * ----------------------------------------
- * LQ rt, offset(base) Load Quadword
- * SQ rt, offset(base) Store Quadword
- *
- * Multiply and Divide (19 instructions)
- * -------------------------------------
- * PMULTW rd, rs, rt Parallel Multiply Word
- * PMULTUW rd, rs, rt Parallel Multiply Unsigned Word
- * PDIVW rs, rt Parallel Divide Word
- * PDIVUW rs, rt Parallel Divide Unsigned Word
- * PMADDW rd, rs, rt Parallel Multiply-Add Word
- * PMADDUW rd, rs, rt Parallel Multiply-Add Unsigned Word
- * PMSUBW rd, rs, rt Parallel Multiply-Subtract Word
- * PMULTH rd, rs, rt Parallel Multiply Halfword
- * PMADDH rd, rs, rt Parallel Multiply-Add Halfword
- * PMSUBH rd, rs, rt Parallel Multiply-Subtract Halfword
- * PHMADH rd, rs, rt Parallel Horizontal Multiply-Add Halfword
- * PHMSBH rd, rs, rt Parallel Horizontal Multiply-Subtract Halfword
- * PDIVBW rs, rt Parallel Divide Broadcast Word
- * PMFHI rd Parallel Move From HI Register
- * PMFLO rd Parallel Move From LO Register
- * PMTHI rs Parallel Move To HI Register
- * PMTLO rs Parallel Move To LO Register
- * PMFHL rd Parallel Move From HI/LO Register
- * PMTHL rs Parallel Move To HI/LO Register
- *
- * Pack/Extend (11 instructions)
- * -----------------------------
- * PPAC5 rd, rt Parallel Pack to 5 bits
- * PPACB rd, rs, rt Parallel Pack to Byte
- * PPACH rd, rs, rt Parallel Pack to Halfword
- * PPACW rd, rs, rt Parallel Pack to Word
- * PEXT5 rd, rt Parallel Extend Upper from 5 bits
- * PEXTUB rd, rs, rt Parallel Extend Upper from Byte
- * PEXTLB rd, rs, rt Parallel Extend Lower from Byte
- * PEXTUH rd, rs, rt Parallel Extend Upper from Halfword
- * PEXTLH rd, rs, rt Parallel Extend Lower from Halfword
- * PEXTUW rd, rs, rt Parallel Extend Upper from Word
- * PEXTLW rd, rs, rt Parallel Extend Lower from Word
- *
- * Others (16 instructions)
- * ------------------------
- * PCPYH rd, rt Parallel Copy Halfword
- * PCPYLD rd, rs, rt Parallel Copy Lower Doubleword
- * PCPYUD rd, rs, rt Parallel Copy Upper Doubleword
- * PREVH rd, rt Parallel Reverse Halfword
- * PINTH rd, rs, rt Parallel Interleave Halfword
- * PINTEH rd, rs, rt Parallel Interleave Even Halfword
- * PEXEH rd, rt Parallel Exchange Even Halfword
- * PEXCH rd, rt Parallel Exchange Center Halfword
- * PEXEW rd, rt Parallel Exchange Even Word
- * PEXCW rd, rt Parallel Exchange Center Word
- * QFSRV rd, rs, rt Quadword Funnel Shift Right Variable
- * MFSA rd Move from Shift Amount Register
- * MTSA rs Move to Shift Amount Register
- * MTSAB rs, immediate Move Byte Count to Shift Amount Register
- * MTSAH rs, immediate Move Halfword Count to Shift Amount Register
- * PROT3W rd, rt Parallel Rotate 3 Words
- *
* MMI (MultiMedia Instruction) encodings
* ======================================
*
@@ -1970,211 +1197,12 @@ enum {
enum {
MMI_OPC_MADD = 0x00 | MMI_OPC_CLASS_MMI, /* Same as OPC_MADD */
MMI_OPC_MADDU = 0x01 | MMI_OPC_CLASS_MMI, /* Same as OPC_MADDU */
- MMI_OPC_PLZCW = 0x04 | MMI_OPC_CLASS_MMI,
- MMI_OPC_CLASS_MMI0 = 0x08 | MMI_OPC_CLASS_MMI,
- MMI_OPC_CLASS_MMI2 = 0x09 | MMI_OPC_CLASS_MMI,
- MMI_OPC_MFHI1 = 0x10 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MFHI */
- MMI_OPC_MTHI1 = 0x11 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MTHI */
- MMI_OPC_MFLO1 = 0x12 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MFLO */
- MMI_OPC_MTLO1 = 0x13 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MTLO */
MMI_OPC_MULT1 = 0x18 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MULT */
MMI_OPC_MULTU1 = 0x19 | MMI_OPC_CLASS_MMI, /* Same min. as OPC_MULTU */
MMI_OPC_DIV1 = 0x1A | MMI_OPC_CLASS_MMI, /* Same minor as OPC_DIV */
MMI_OPC_DIVU1 = 0x1B | MMI_OPC_CLASS_MMI, /* Same minor as OPC_DIVU */
MMI_OPC_MADD1 = 0x20 | MMI_OPC_CLASS_MMI,
MMI_OPC_MADDU1 = 0x21 | MMI_OPC_CLASS_MMI,
- MMI_OPC_CLASS_MMI1 = 0x28 | MMI_OPC_CLASS_MMI,
- MMI_OPC_CLASS_MMI3 = 0x29 | MMI_OPC_CLASS_MMI,
- MMI_OPC_PMFHL = 0x30 | MMI_OPC_CLASS_MMI,
- MMI_OPC_PMTHL = 0x31 | MMI_OPC_CLASS_MMI,
- MMI_OPC_PSLLH = 0x34 | MMI_OPC_CLASS_MMI,
- MMI_OPC_PSRLH = 0x36 | MMI_OPC_CLASS_MMI,
- MMI_OPC_PSRAH = 0x37 | MMI_OPC_CLASS_MMI,
- MMI_OPC_PSLLW = 0x3C | MMI_OPC_CLASS_MMI,
- MMI_OPC_PSRLW = 0x3E | MMI_OPC_CLASS_MMI,
- MMI_OPC_PSRAW = 0x3F | MMI_OPC_CLASS_MMI,
-};
-
-/*
- * MMI instructions with opcode field = MMI and bits 5..0 = MMI0:
- *
- * 31 26 10 6 5 0
- * +--------+----------------------+--------+--------+
- * | MMI | |function| MMI0 |
- * +--------+----------------------+--------+--------+
- *
- * function bits 7..6
- * bits | 0 | 1 | 2 | 3
- * 10..8 | 00 | 01 | 10 | 11
- * -------+-------+-------+-------+-------
- * 0 000 | PADDW | PSUBW | PCGTW | PMAXW
- * 1 001 | PADDH | PSUBH | PCGTH | PMAXH
- * 2 010 | PADDB | PSUBB | PCGTB | *
- * 3 011 | * | * | * | *
- * 4 100 | PADDSW| PSUBSW| PEXTLW| PPACW
- * 5 101 | PADDSH| PSUBSH| PEXTLH| PPACH
- * 6 110 | PADDSB| PSUBSB| PEXTLB| PPACB
- * 7 111 | * | * | PEXT5 | PPAC5
- */
-
-#define MASK_MMI0(op) (MASK_OP_MAJOR(op) | ((op) & 0x7FF))
-enum {
- MMI_OPC_0_PADDW = (0x00 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PSUBW = (0x01 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PCGTW = (0x02 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PMAXW = (0x03 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PADDH = (0x04 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PSUBH = (0x05 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PCGTH = (0x06 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PMAXH = (0x07 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PADDB = (0x08 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PSUBB = (0x09 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PCGTB = (0x0A << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PADDSW = (0x10 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PSUBSW = (0x11 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PEXTLW = (0x12 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PPACW = (0x13 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PADDSH = (0x14 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PSUBSH = (0x15 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PEXTLH = (0x16 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PPACH = (0x17 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PADDSB = (0x18 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PSUBSB = (0x19 << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PEXTLB = (0x1A << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PPACB = (0x1B << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PEXT5 = (0x1E << 6) | MMI_OPC_CLASS_MMI0,
- MMI_OPC_0_PPAC5 = (0x1F << 6) | MMI_OPC_CLASS_MMI0,
-};
-
-/*
- * MMI instructions with opcode field = MMI and bits 5..0 = MMI1:
- *
- * 31 26 10 6 5 0
- * +--------+----------------------+--------+--------+
- * | MMI | |function| MMI1 |
- * +--------+----------------------+--------+--------+
- *
- * function bits 7..6
- * bits | 0 | 1 | 2 | 3
- * 10..8 | 00 | 01 | 10 | 11
- * -------+-------+-------+-------+-------
- * 0 000 | * | PABSW | PCEQW | PMINW
- * 1 001 | PADSBH| PABSH | PCEQH | PMINH
- * 2 010 | * | * | PCEQB | *
- * 3 011 | * | * | * | *
- * 4 100 | PADDUW| PSUBUW| PEXTUW| *
- * 5 101 | PADDUH| PSUBUH| PEXTUH| *
- * 6 110 | PADDUB| PSUBUB| PEXTUB| QFSRV
- * 7 111 | * | * | * | *
- */
-
-#define MASK_MMI1(op) (MASK_OP_MAJOR(op) | ((op) & 0x7FF))
-enum {
- MMI_OPC_1_PABSW = (0x01 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PCEQW = (0x02 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PMINW = (0x03 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PADSBH = (0x04 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PABSH = (0x05 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PCEQH = (0x06 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PMINH = (0x07 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PCEQB = (0x0A << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PADDUW = (0x10 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PSUBUW = (0x11 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PEXTUW = (0x12 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PADDUH = (0x14 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PSUBUH = (0x15 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PEXTUH = (0x16 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PADDUB = (0x18 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PSUBUB = (0x19 << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_PEXTUB = (0x1A << 6) | MMI_OPC_CLASS_MMI1,
- MMI_OPC_1_QFSRV = (0x1B << 6) | MMI_OPC_CLASS_MMI1,
-};
-
-/*
- * MMI instructions with opcode field = MMI and bits 5..0 = MMI2:
- *
- * 31 26 10 6 5 0
- * +--------+----------------------+--------+--------+
- * | MMI | |function| MMI2 |
- * +--------+----------------------+--------+--------+
- *
- * function bits 7..6
- * bits | 0 | 1 | 2 | 3
- * 10..8 | 00 | 01 | 10 | 11
- * -------+-------+-------+-------+-------
- * 0 000 | PMADDW| * | PSLLVW| PSRLVW
- * 1 001 | PMSUBW| * | * | *
- * 2 010 | PMFHI | PMFLO | PINTH | *
- * 3 011 | PMULTW| PDIVW | PCPYLD| *
- * 4 100 | PMADDH| PHMADH| PAND | PXOR
- * 5 101 | PMSUBH| PHMSBH| * | *
- * 6 110 | * | * | PEXEH | PREVH
- * 7 111 | PMULTH| PDIVBW| PEXEW | PROT3W
- */
-
-#define MASK_MMI2(op) (MASK_OP_MAJOR(op) | ((op) & 0x7FF))
-enum {
- MMI_OPC_2_PMADDW = (0x00 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PSLLVW = (0x02 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PSRLVW = (0x03 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMSUBW = (0x04 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMFHI = (0x08 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMFLO = (0x09 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PINTH = (0x0A << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMULTW = (0x0C << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PDIVW = (0x0D << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PCPYLD = (0x0E << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMADDH = (0x10 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PHMADH = (0x11 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PAND = (0x12 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PXOR = (0x13 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMSUBH = (0x14 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PHMSBH = (0x15 << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PEXEH = (0x1A << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PREVH = (0x1B << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PMULTH = (0x1C << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PDIVBW = (0x1D << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PEXEW = (0x1E << 6) | MMI_OPC_CLASS_MMI2,
- MMI_OPC_2_PROT3W = (0x1F << 6) | MMI_OPC_CLASS_MMI2,
-};
-
-/*
- * MMI instructions with opcode field = MMI and bits 5..0 = MMI3:
- *
- * 31 26 10 6 5 0
- * +--------+----------------------+--------+--------+
- * | MMI | |function| MMI3 |
- * +--------+----------------------+--------+--------+
- *
- * function bits 7..6
- * bits | 0 | 1 | 2 | 3
- * 10..8 | 00 | 01 | 10 | 11
- * -------+-------+-------+-------+-------
- * 0 000 |PMADDUW| * | * | PSRAVW
- * 1 001 | * | * | * | *
- * 2 010 | PMTHI | PMTLO | PINTEH| *
- * 3 011 |PMULTUW| PDIVUW| PCPYUD| *
- * 4 100 | * | * | POR | PNOR
- * 5 101 | * | * | * | *
- * 6 110 | * | * | PEXCH | PCPYH
- * 7 111 | * | * | PEXCW | *
- */
-
-#define MASK_MMI3(op) (MASK_OP_MAJOR(op) | ((op) & 0x7FF))
-enum {
- MMI_OPC_3_PMADDUW = (0x00 << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PSRAVW = (0x03 << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PMTHI = (0x08 << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PMTLO = (0x09 << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PINTEH = (0x0A << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PMULTUW = (0x0C << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PDIVUW = (0x0D << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PCPYUD = (0x0E << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_POR = (0x12 << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PNOR = (0x13 << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PEXCH = (0x1A << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PCPYH = (0x1B << 6) | MMI_OPC_CLASS_MMI3,
- MMI_OPC_3_PEXCW = (0x1E << 6) | MMI_OPC_CLASS_MMI3,
};
/* global register indices */
@@ -2192,12 +1220,6 @@ static TCGv_i32 hflags;
TCGv_i32 fpu_fcr0, fpu_fcr31;
TCGv_i64 fpu_f64[32];
-#if !defined(TARGET_MIPS64)
-/* MXU registers */
-static TCGv mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1];
-static TCGv mxu_CR;
-#endif
-
#include "exec/gen-icount.h"
#define gen_helper_0e0i(name, arg) do { \
@@ -2267,13 +1289,6 @@ static const char * const fregnames[] = {
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
};
-#if !defined(TARGET_MIPS64)
-static const char * const mxuregnames[] = {
- "XR1", "XR2", "XR3", "XR4", "XR5", "XR6", "XR7", "XR8",
- "XR9", "XR10", "XR11", "XR12", "XR13", "XR14", "XR15", "MXU_CR",
-};
-#endif
-
/* General purpose registers moves. */
void gen_load_gpr(TCGv t, int reg)
{
@@ -2357,38 +1372,6 @@ static inline void gen_store_srsgpr(int from, int to)
}
}
-#if !defined(TARGET_MIPS64)
-/* MXU General purpose registers moves. */
-static inline void gen_load_mxu_gpr(TCGv t, unsigned int reg)
-{
- if (reg == 0) {
- tcg_gen_movi_tl(t, 0);
- } else if (reg <= 15) {
- tcg_gen_mov_tl(t, mxu_gpr[reg - 1]);
- }
-}
-
-static inline void gen_store_mxu_gpr(TCGv t, unsigned int reg)
-{
- if (reg > 0 && reg <= 15) {
- tcg_gen_mov_tl(mxu_gpr[reg - 1], t);
- }
-}
-
-/* MXU control register moves. */
-static inline void gen_load_mxu_cr(TCGv t)
-{
- tcg_gen_mov_tl(t, mxu_CR);
-}
-
-static inline void gen_store_mxu_cr(TCGv t)
-{
- /* TODO: Add handling of RW rules for MXU_CR. */
- tcg_gen_mov_tl(mxu_CR, t);
-}
-#endif
-
-
/* Tests */
static inline void gen_save_pc(target_ulong pc)
{
@@ -4122,31 +3105,6 @@ static void gen_shift(DisasContext *ctx, uint32_t opc,
tcg_temp_free(t1);
}
-#if defined(TARGET_MIPS64)
-/* Copy GPR to and from TX79 HI1/LO1 register. */
-static void gen_HILO1_tx79(DisasContext *ctx, uint32_t opc, int reg)
-{
- switch (opc) {
- case MMI_OPC_MFHI1:
- gen_store_gpr(cpu_HI[1], reg);
- break;
- case MMI_OPC_MFLO1:
- gen_store_gpr(cpu_LO[1], reg);
- break;
- case MMI_OPC_MTHI1:
- gen_load_gpr(cpu_HI[1], reg);
- break;
- case MMI_OPC_MTLO1:
- gen_load_gpr(cpu_LO[1], reg);
- break;
- default:
- MIPS_INVAL("mfthilo1 TX79");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-#endif
-
/* Arithmetic on HI/LO registers */
static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg)
{
@@ -11118,11 +10076,7 @@ static void gen_movci(DisasContext *ctx, int rd, int rs, int cc, int tf)
tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
tcg_gen_brcondi_i32(cond, t0, 0, l1);
tcg_temp_free_i32(t0);
- if (rs == 0) {
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- } else {
- tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
- }
+ gen_load_gpr(cpu_gpr[rd], rs);
gen_set_label(l1);
}
@@ -13040,7 +11994,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc,
}
}
-static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel)
+void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel)
{
TCGv t0;
@@ -15452,24 +14406,15 @@ static void gen_pool16c_insn(DisasContext *ctx)
static inline void gen_movep(DisasContext *ctx, int enc_dest, int enc_rt,
int enc_rs)
{
- int rd, rs, re, rt;
+ int rd, re;
static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 };
static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 };
static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 };
+
rd = rd_enc[enc_dest];
re = re_enc[enc_dest];
- rs = rs_rt_enc[enc_rs];
- rt = rs_rt_enc[enc_rt];
- if (rs) {
- tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
- } else {
- tcg_gen_movi_tl(cpu_gpr[rd], 0);
- }
- if (rt) {
- tcg_gen_mov_tl(cpu_gpr[re], cpu_gpr[rt]);
- } else {
- tcg_gen_movi_tl(cpu_gpr[re], 0);
- }
+ gen_load_gpr(cpu_gpr[rd], rs_rt_enc[enc_rs]);
+ gen_load_gpr(cpu_gpr[re], rs_rt_enc[enc_rt]);
}
static void gen_pool16c_r6_insn(DisasContext *ctx)
@@ -24742,2400 +23687,6 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
}
-#if defined(TARGET_MIPS64)
-
-/*
- *
- * MMI (MultiMedia Interface) ASE instructions
- * ===========================================
- */
-
-/*
- * MMI instructions category: data communication
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * PCPYH PEXCH PEXTLB PINTH PPACB PEXT5 PREVH
- * PCPYLD PEXCW PEXTLH PINTEH PPACH PPAC5 PROT3W
- * PCPYUD PEXEH PEXTLW PPACW
- * PEXEW PEXTUB
- * PEXTUH
- * PEXTUW
- */
-
-/*
- * PCPYH rd, rt
- *
- * Parallel Copy Halfword
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---------+---------+-----------+
- * | MMI |0 0 0 0 0| rt | rd | PCPYH | MMI3 |
- * +-----------+---------+---------+---------+---------+-----------+
- */
-static void gen_mmi_pcpyh(DisasContext *ctx)
-{
- uint32_t pd, rt, rd;
- uint32_t opcode;
-
- opcode = ctx->opcode;
-
- pd = extract32(opcode, 21, 5);
- rt = extract32(opcode, 16, 5);
- rd = extract32(opcode, 11, 5);
-
- if (unlikely(pd != 0)) {
- gen_reserved_instruction(ctx);
- } else if (rd == 0) {
- /* nop */
- } else if (rt == 0) {
- tcg_gen_movi_i64(cpu_gpr[rd], 0);
- tcg_gen_movi_i64(cpu_gpr_hi[rd], 0);
- } else {
- TCGv_i64 t0 = tcg_temp_new();
- TCGv_i64 t1 = tcg_temp_new();
- uint64_t mask = (1ULL << 16) - 1;
-
- tcg_gen_andi_i64(t0, cpu_gpr[rt], mask);
- tcg_gen_movi_i64(t1, 0);
- tcg_gen_or_i64(t1, t0, t1);
- tcg_gen_shli_i64(t0, t0, 16);
- tcg_gen_or_i64(t1, t0, t1);
- tcg_gen_shli_i64(t0, t0, 16);
- tcg_gen_or_i64(t1, t0, t1);
- tcg_gen_shli_i64(t0, t0, 16);
- tcg_gen_or_i64(t1, t0, t1);
-
- tcg_gen_mov_i64(cpu_gpr[rd], t1);
-
- tcg_gen_andi_i64(t0, cpu_gpr_hi[rt], mask);
- tcg_gen_movi_i64(t1, 0);
- tcg_gen_or_i64(t1, t0, t1);
- tcg_gen_shli_i64(t0, t0, 16);
- tcg_gen_or_i64(t1, t0, t1);
- tcg_gen_shli_i64(t0, t0, 16);
- tcg_gen_or_i64(t1, t0, t1);
- tcg_gen_shli_i64(t0, t0, 16);
- tcg_gen_or_i64(t1, t0, t1);
-
- tcg_gen_mov_i64(cpu_gpr_hi[rd], t1);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- }
-}
-
-/*
- * PCPYLD rd, rs, rt
- *
- * Parallel Copy Lower Doubleword
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---------+---------+-----------+
- * | MMI | rs | rt | rd | PCPYLD | MMI2 |
- * +-----------+---------+---------+---------+---------+-----------+
- */
-static void gen_mmi_pcpyld(DisasContext *ctx)
-{
- uint32_t rs, rt, rd;
- uint32_t opcode;
-
- opcode = ctx->opcode;
-
- rs = extract32(opcode, 21, 5);
- rt = extract32(opcode, 16, 5);
- rd = extract32(opcode, 11, 5);
-
- if (rd == 0) {
- /* nop */
- } else {
- if (rs == 0) {
- tcg_gen_movi_i64(cpu_gpr_hi[rd], 0);
- } else {
- tcg_gen_mov_i64(cpu_gpr_hi[rd], cpu_gpr[rs]);
- }
- if (rt == 0) {
- tcg_gen_movi_i64(cpu_gpr[rd], 0);
- } else {
- if (rd != rt) {
- tcg_gen_mov_i64(cpu_gpr[rd], cpu_gpr[rt]);
- }
- }
- }
-}
-
-/*
- * PCPYUD rd, rs, rt
- *
- * Parallel Copy Upper Doubleword
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---------+---------+-----------+
- * | MMI | rs | rt | rd | PCPYUD | MMI3 |
- * +-----------+---------+---------+---------+---------+-----------+
- */
-static void gen_mmi_pcpyud(DisasContext *ctx)
-{
- uint32_t rs, rt, rd;
- uint32_t opcode;
-
- opcode = ctx->opcode;
-
- rs = extract32(opcode, 21, 5);
- rt = extract32(opcode, 16, 5);
- rd = extract32(opcode, 11, 5);
-
- if (rd == 0) {
- /* nop */
- } else {
- if (rs == 0) {
- tcg_gen_movi_i64(cpu_gpr[rd], 0);
- } else {
- tcg_gen_mov_i64(cpu_gpr[rd], cpu_gpr_hi[rs]);
- }
- if (rt == 0) {
- tcg_gen_movi_i64(cpu_gpr_hi[rd], 0);
- } else {
- if (rd != rt) {
- tcg_gen_mov_i64(cpu_gpr_hi[rd], cpu_gpr_hi[rt]);
- }
- }
- }
-}
-
-#endif
-
-
-#if !defined(TARGET_MIPS64)
-
-/* MXU accumulate add/subtract 1-bit pattern 'aptn1' */
-#define MXU_APTN1_A 0
-#define MXU_APTN1_S 1
-
-/* MXU accumulate add/subtract 2-bit pattern 'aptn2' */
-#define MXU_APTN2_AA 0
-#define MXU_APTN2_AS 1
-#define MXU_APTN2_SA 2
-#define MXU_APTN2_SS 3
-
-/* MXU execute add/subtract 2-bit pattern 'eptn2' */
-#define MXU_EPTN2_AA 0
-#define MXU_EPTN2_AS 1
-#define MXU_EPTN2_SA 2
-#define MXU_EPTN2_SS 3
-
-/* MXU operand getting pattern 'optn2' */
-#define MXU_OPTN2_PTN0 0
-#define MXU_OPTN2_PTN1 1
-#define MXU_OPTN2_PTN2 2
-#define MXU_OPTN2_PTN3 3
-/* alternative naming scheme for 'optn2' */
-#define MXU_OPTN2_WW 0
-#define MXU_OPTN2_LW 1
-#define MXU_OPTN2_HW 2
-#define MXU_OPTN2_XW 3
-
-/* MXU operand getting pattern 'optn3' */
-#define MXU_OPTN3_PTN0 0
-#define MXU_OPTN3_PTN1 1
-#define MXU_OPTN3_PTN2 2
-#define MXU_OPTN3_PTN3 3
-#define MXU_OPTN3_PTN4 4
-#define MXU_OPTN3_PTN5 5
-#define MXU_OPTN3_PTN6 6
-#define MXU_OPTN3_PTN7 7
-
-
-/*
- * S32I2M XRa, rb - Register move from GRF to XRF
- */
-static void gen_mxu_s32i2m(DisasContext *ctx)
-{
- TCGv t0;
- uint32_t XRa, Rb;
-
- t0 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 5);
- Rb = extract32(ctx->opcode, 16, 5);
-
- gen_load_gpr(t0, Rb);
- if (XRa <= 15) {
- gen_store_mxu_gpr(t0, XRa);
- } else if (XRa == 16) {
- gen_store_mxu_cr(t0);
- }
-
- tcg_temp_free(t0);
-}
-
-/*
- * S32M2I XRa, rb - Register move from XRF to GRF
- */
-static void gen_mxu_s32m2i(DisasContext *ctx)
-{
- TCGv t0;
- uint32_t XRa, Rb;
-
- t0 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 5);
- Rb = extract32(ctx->opcode, 16, 5);
-
- if (XRa <= 15) {
- gen_load_mxu_gpr(t0, XRa);
- } else if (XRa == 16) {
- gen_load_mxu_cr(t0);
- }
-
- gen_store_gpr(t0, Rb);
-
- tcg_temp_free(t0);
-}
-
-/*
- * S8LDD XRa, Rb, s8, optn3 - Load a byte from memory to XRF
- */
-static void gen_mxu_s8ldd(DisasContext *ctx)
-{
- TCGv t0, t1;
- uint32_t XRa, Rb, s8, optn3;
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 4);
- s8 = extract32(ctx->opcode, 10, 8);
- optn3 = extract32(ctx->opcode, 18, 3);
- Rb = extract32(ctx->opcode, 21, 5);
-
- gen_load_gpr(t0, Rb);
- tcg_gen_addi_tl(t0, t0, (int8_t)s8);
-
- switch (optn3) {
- /* XRa[7:0] = tmp8 */
- case MXU_OPTN3_PTN0:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- gen_load_mxu_gpr(t0, XRa);
- tcg_gen_deposit_tl(t0, t0, t1, 0, 8);
- break;
- /* XRa[15:8] = tmp8 */
- case MXU_OPTN3_PTN1:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- gen_load_mxu_gpr(t0, XRa);
- tcg_gen_deposit_tl(t0, t0, t1, 8, 8);
- break;
- /* XRa[23:16] = tmp8 */
- case MXU_OPTN3_PTN2:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- gen_load_mxu_gpr(t0, XRa);
- tcg_gen_deposit_tl(t0, t0, t1, 16, 8);
- break;
- /* XRa[31:24] = tmp8 */
- case MXU_OPTN3_PTN3:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- gen_load_mxu_gpr(t0, XRa);
- tcg_gen_deposit_tl(t0, t0, t1, 24, 8);
- break;
- /* XRa = {8'b0, tmp8, 8'b0, tmp8} */
- case MXU_OPTN3_PTN4:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- tcg_gen_deposit_tl(t0, t1, t1, 16, 16);
- break;
- /* XRa = {tmp8, 8'b0, tmp8, 8'b0} */
- case MXU_OPTN3_PTN5:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- tcg_gen_shli_tl(t1, t1, 8);
- tcg_gen_deposit_tl(t0, t1, t1, 16, 16);
- break;
- /* XRa = {{8{sign of tmp8}}, tmp8, {8{sign of tmp8}}, tmp8} */
- case MXU_OPTN3_PTN6:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_SB);
- tcg_gen_mov_tl(t0, t1);
- tcg_gen_andi_tl(t0, t0, 0xFF00FFFF);
- tcg_gen_shli_tl(t1, t1, 16);
- tcg_gen_or_tl(t0, t0, t1);
- break;
- /* XRa = {tmp8, tmp8, tmp8, tmp8} */
- case MXU_OPTN3_PTN7:
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
- tcg_gen_deposit_tl(t1, t1, t1, 8, 8);
- tcg_gen_deposit_tl(t0, t1, t1, 16, 16);
- break;
- }
-
- gen_store_mxu_gpr(t0, XRa);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
-}
-
-/*
- * D16MUL XRa, XRb, XRc, XRd, optn2 - Signed 16 bit pattern multiplication
- */
-static void gen_mxu_d16mul(DisasContext *ctx)
-{
- TCGv t0, t1, t2, t3;
- uint32_t XRa, XRb, XRc, XRd, optn2;
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- t2 = tcg_temp_new();
- t3 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRc = extract32(ctx->opcode, 14, 4);
- XRd = extract32(ctx->opcode, 18, 4);
- optn2 = extract32(ctx->opcode, 22, 2);
-
- gen_load_mxu_gpr(t1, XRb);
- tcg_gen_sextract_tl(t0, t1, 0, 16);
- tcg_gen_sextract_tl(t1, t1, 16, 16);
- gen_load_mxu_gpr(t3, XRc);
- tcg_gen_sextract_tl(t2, t3, 0, 16);
- tcg_gen_sextract_tl(t3, t3, 16, 16);
-
- switch (optn2) {
- case MXU_OPTN2_WW: /* XRB.H*XRC.H == lop, XRB.L*XRC.L == rop */
- tcg_gen_mul_tl(t3, t1, t3);
- tcg_gen_mul_tl(t2, t0, t2);
- break;
- case MXU_OPTN2_LW: /* XRB.L*XRC.H == lop, XRB.L*XRC.L == rop */
- tcg_gen_mul_tl(t3, t0, t3);
- tcg_gen_mul_tl(t2, t0, t2);
- break;
- case MXU_OPTN2_HW: /* XRB.H*XRC.H == lop, XRB.H*XRC.L == rop */
- tcg_gen_mul_tl(t3, t1, t3);
- tcg_gen_mul_tl(t2, t1, t2);
- break;
- case MXU_OPTN2_XW: /* XRB.L*XRC.H == lop, XRB.H*XRC.L == rop */
- tcg_gen_mul_tl(t3, t0, t3);
- tcg_gen_mul_tl(t2, t1, t2);
- break;
- }
- gen_store_mxu_gpr(t3, XRa);
- gen_store_mxu_gpr(t2, XRd);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- tcg_temp_free(t3);
-}
-
-/*
- * D16MAC XRa, XRb, XRc, XRd, aptn2, optn2 - Signed 16 bit pattern multiply
- * and accumulate
- */
-static void gen_mxu_d16mac(DisasContext *ctx)
-{
- TCGv t0, t1, t2, t3;
- uint32_t XRa, XRb, XRc, XRd, optn2, aptn2;
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- t2 = tcg_temp_new();
- t3 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRc = extract32(ctx->opcode, 14, 4);
- XRd = extract32(ctx->opcode, 18, 4);
- optn2 = extract32(ctx->opcode, 22, 2);
- aptn2 = extract32(ctx->opcode, 24, 2);
-
- gen_load_mxu_gpr(t1, XRb);
- tcg_gen_sextract_tl(t0, t1, 0, 16);
- tcg_gen_sextract_tl(t1, t1, 16, 16);
-
- gen_load_mxu_gpr(t3, XRc);
- tcg_gen_sextract_tl(t2, t3, 0, 16);
- tcg_gen_sextract_tl(t3, t3, 16, 16);
-
- switch (optn2) {
- case MXU_OPTN2_WW: /* XRB.H*XRC.H == lop, XRB.L*XRC.L == rop */
- tcg_gen_mul_tl(t3, t1, t3);
- tcg_gen_mul_tl(t2, t0, t2);
- break;
- case MXU_OPTN2_LW: /* XRB.L*XRC.H == lop, XRB.L*XRC.L == rop */
- tcg_gen_mul_tl(t3, t0, t3);
- tcg_gen_mul_tl(t2, t0, t2);
- break;
- case MXU_OPTN2_HW: /* XRB.H*XRC.H == lop, XRB.H*XRC.L == rop */
- tcg_gen_mul_tl(t3, t1, t3);
- tcg_gen_mul_tl(t2, t1, t2);
- break;
- case MXU_OPTN2_XW: /* XRB.L*XRC.H == lop, XRB.H*XRC.L == rop */
- tcg_gen_mul_tl(t3, t0, t3);
- tcg_gen_mul_tl(t2, t1, t2);
- break;
- }
- gen_load_mxu_gpr(t0, XRa);
- gen_load_mxu_gpr(t1, XRd);
-
- switch (aptn2) {
- case MXU_APTN2_AA:
- tcg_gen_add_tl(t3, t0, t3);
- tcg_gen_add_tl(t2, t1, t2);
- break;
- case MXU_APTN2_AS:
- tcg_gen_add_tl(t3, t0, t3);
- tcg_gen_sub_tl(t2, t1, t2);
- break;
- case MXU_APTN2_SA:
- tcg_gen_sub_tl(t3, t0, t3);
- tcg_gen_add_tl(t2, t1, t2);
- break;
- case MXU_APTN2_SS:
- tcg_gen_sub_tl(t3, t0, t3);
- tcg_gen_sub_tl(t2, t1, t2);
- break;
- }
- gen_store_mxu_gpr(t3, XRa);
- gen_store_mxu_gpr(t2, XRd);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- tcg_temp_free(t3);
-}
-
-/*
- * Q8MUL XRa, XRb, XRc, XRd - Parallel unsigned 8 bit pattern multiply
- * Q8MULSU XRa, XRb, XRc, XRd - Parallel signed 8 bit pattern multiply
- */
-static void gen_mxu_q8mul_q8mulsu(DisasContext *ctx)
-{
- TCGv t0, t1, t2, t3, t4, t5, t6, t7;
- uint32_t XRa, XRb, XRc, XRd, sel;
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- t2 = tcg_temp_new();
- t3 = tcg_temp_new();
- t4 = tcg_temp_new();
- t5 = tcg_temp_new();
- t6 = tcg_temp_new();
- t7 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRc = extract32(ctx->opcode, 14, 4);
- XRd = extract32(ctx->opcode, 18, 4);
- sel = extract32(ctx->opcode, 22, 2);
-
- gen_load_mxu_gpr(t3, XRb);
- gen_load_mxu_gpr(t7, XRc);
-
- if (sel == 0x2) {
- /* Q8MULSU */
- tcg_gen_ext8s_tl(t0, t3);
- tcg_gen_shri_tl(t3, t3, 8);
- tcg_gen_ext8s_tl(t1, t3);
- tcg_gen_shri_tl(t3, t3, 8);
- tcg_gen_ext8s_tl(t2, t3);
- tcg_gen_shri_tl(t3, t3, 8);
- tcg_gen_ext8s_tl(t3, t3);
- } else {
- /* Q8MUL */
- tcg_gen_ext8u_tl(t0, t3);
- tcg_gen_shri_tl(t3, t3, 8);
- tcg_gen_ext8u_tl(t1, t3);
- tcg_gen_shri_tl(t3, t3, 8);
- tcg_gen_ext8u_tl(t2, t3);
- tcg_gen_shri_tl(t3, t3, 8);
- tcg_gen_ext8u_tl(t3, t3);
- }
-
- tcg_gen_ext8u_tl(t4, t7);
- tcg_gen_shri_tl(t7, t7, 8);
- tcg_gen_ext8u_tl(t5, t7);
- tcg_gen_shri_tl(t7, t7, 8);
- tcg_gen_ext8u_tl(t6, t7);
- tcg_gen_shri_tl(t7, t7, 8);
- tcg_gen_ext8u_tl(t7, t7);
-
- tcg_gen_mul_tl(t0, t0, t4);
- tcg_gen_mul_tl(t1, t1, t5);
- tcg_gen_mul_tl(t2, t2, t6);
- tcg_gen_mul_tl(t3, t3, t7);
-
- tcg_gen_andi_tl(t0, t0, 0xFFFF);
- tcg_gen_andi_tl(t1, t1, 0xFFFF);
- tcg_gen_andi_tl(t2, t2, 0xFFFF);
- tcg_gen_andi_tl(t3, t3, 0xFFFF);
-
- tcg_gen_shli_tl(t1, t1, 16);
- tcg_gen_shli_tl(t3, t3, 16);
-
- tcg_gen_or_tl(t0, t0, t1);
- tcg_gen_or_tl(t1, t2, t3);
-
- gen_store_mxu_gpr(t0, XRd);
- gen_store_mxu_gpr(t1, XRa);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- tcg_temp_free(t3);
- tcg_temp_free(t4);
- tcg_temp_free(t5);
- tcg_temp_free(t6);
- tcg_temp_free(t7);
-}
-
-/*
- * S32LDD XRa, Rb, S12 - Load a word from memory to XRF
- * S32LDDR XRa, Rb, S12 - Load a word from memory to XRF, reversed byte seq.
- */
-static void gen_mxu_s32ldd_s32lddr(DisasContext *ctx)
-{
- TCGv t0, t1;
- uint32_t XRa, Rb, s12, sel;
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
-
- XRa = extract32(ctx->opcode, 6, 4);
- s12 = extract32(ctx->opcode, 10, 10);
- sel = extract32(ctx->opcode, 20, 1);
- Rb = extract32(ctx->opcode, 21, 5);
-
- gen_load_gpr(t0, Rb);
-
- tcg_gen_movi_tl(t1, s12);
- tcg_gen_shli_tl(t1, t1, 2);
- if (s12 & 0x200) {
- tcg_gen_ori_tl(t1, t1, 0xFFFFF000);
- }
- tcg_gen_add_tl(t1, t0, t1);
- tcg_gen_qemu_ld_tl(t1, t1, ctx->mem_idx, MO_SL);
-
- if (sel == 1) {
- /* S32LDDR */
- tcg_gen_bswap32_tl(t1, t1);
- }
- gen_store_mxu_gpr(t1, XRa);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
-}
-
-
-/*
- * MXU instruction category: logic
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * S32NOR S32AND S32OR S32XOR
- */
-
-/*
- * S32NOR XRa, XRb, XRc
- * Update XRa with the result of logical bitwise 'nor' operation
- * applied to the content of XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_S32NOR(DisasContext *ctx)
-{
- uint32_t pad, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRc == 0))) {
- /* both operands zero registers -> just set destination to all 1s */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0xFFFFFFFF);
- } else if (unlikely(XRb == 0)) {
- /* XRb zero register -> just set destination to the negation of XRc */
- tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
- } else if (unlikely(XRc == 0)) {
- /* XRa zero register -> just set destination to the negation of XRb */
- tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to the negation of XRb */
- tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else {
- /* the most general case */
- tcg_gen_nor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
- }
-}
-
-/*
- * S32AND XRa, XRb, XRc
- * Update XRa with the result of logical bitwise 'and' operation
- * applied to the content of XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_S32AND(DisasContext *ctx)
-{
- uint32_t pad, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) || (XRc == 0))) {
- /* one of operands zero register -> just set destination to all 0s */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to one of them */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else {
- /* the most general case */
- tcg_gen_and_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
- }
-}
-
-/*
- * S32OR XRa, XRb, XRc
- * Update XRa with the result of logical bitwise 'or' operation
- * applied to the content of XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_S32OR(DisasContext *ctx)
-{
- uint32_t pad, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRc == 0))) {
- /* both operands zero registers -> just set destination to all 0s */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else if (unlikely(XRb == 0)) {
- /* XRb zero register -> just set destination to the content of XRc */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
- } else if (unlikely(XRc == 0)) {
- /* XRc zero register -> just set destination to the content of XRb */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to one of them */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else {
- /* the most general case */
- tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
- }
-}
-
-/*
- * S32XOR XRa, XRb, XRc
- * Update XRa with the result of logical bitwise 'xor' operation
- * applied to the content of XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_S32XOR(DisasContext *ctx)
-{
- uint32_t pad, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRc == 0))) {
- /* both operands zero registers -> just set destination to all 0s */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else if (unlikely(XRb == 0)) {
- /* XRb zero register -> just set destination to the content of XRc */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
- } else if (unlikely(XRc == 0)) {
- /* XRc zero register -> just set destination to the content of XRb */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to all 0s */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else {
- /* the most general case */
- tcg_gen_xor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
- }
-}
-
-
-/*
- * MXU instruction category max/min
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * S32MAX D16MAX Q8MAX
- * S32MIN D16MIN Q8MIN
- */
-
-/*
- * S32MAX XRa, XRb, XRc
- * Update XRa with the maximum of signed 32-bit integers contained
- * in XRb and XRc.
- *
- * S32MIN XRa, XRb, XRc
- * Update XRa with the minimum of signed 32-bit integers contained
- * in XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_S32MAX_S32MIN(DisasContext *ctx)
-{
- uint32_t pad, opc, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- opc = extract32(ctx->opcode, 18, 3);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRc == 0))) {
- /* both operands zero registers -> just set destination to zero */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else if (unlikely((XRb == 0) || (XRc == 0))) {
- /* exactly one operand is zero register - find which one is not...*/
- uint32_t XRx = XRb ? XRb : XRc;
- /* ...and do max/min operation with one operand 0 */
- if (opc == OPC_MXU_S32MAX) {
- tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0);
- } else {
- tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0);
- }
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to one of them */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else {
- /* the most general case */
- if (opc == OPC_MXU_S32MAX) {
- tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1],
- mxu_gpr[XRc - 1]);
- } else {
- tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1],
- mxu_gpr[XRc - 1]);
- }
- }
-}
-
-/*
- * D16MAX
- * Update XRa with the 16-bit-wise maximums of signed integers
- * contained in XRb and XRc.
- *
- * D16MIN
- * Update XRa with the 16-bit-wise minimums of signed integers
- * contained in XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx)
-{
- uint32_t pad, opc, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- opc = extract32(ctx->opcode, 18, 3);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRc == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRa == 0))) {
- /* both operands zero registers -> just set destination to zero */
- tcg_gen_movi_i32(mxu_gpr[XRc - 1], 0);
- } else if (unlikely((XRb == 0) || (XRa == 0))) {
- /* exactly one operand is zero register - find which one is not...*/
- uint32_t XRx = XRb ? XRb : XRc;
- /* ...and do half-word-wise max/min with one operand 0 */
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_const_i32(0);
-
- /* the left half-word first */
- tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFFFF0000);
- if (opc == OPC_MXU_D16MAX) {
- tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
- } else {
- tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
- }
-
- /* the right half-word */
- tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0x0000FFFF);
- /* move half-words to the leftmost position */
- tcg_gen_shli_i32(t0, t0, 16);
- /* t0 will be max/min of t0 and t1 */
- if (opc == OPC_MXU_D16MAX) {
- tcg_gen_smax_i32(t0, t0, t1);
- } else {
- tcg_gen_smin_i32(t0, t0, t1);
- }
- /* return resulting half-words to its original position */
- tcg_gen_shri_i32(t0, t0, 16);
- /* finally update the destination */
- tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to one of them */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else {
- /* the most general case */
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_temp_new();
-
- /* the left half-word first */
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFFFF0000);
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000);
- if (opc == OPC_MXU_D16MAX) {
- tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
- } else {
- tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
- }
-
- /* the right half-word */
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF);
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0x0000FFFF);
- /* move half-words to the leftmost position */
- tcg_gen_shli_i32(t0, t0, 16);
- tcg_gen_shli_i32(t1, t1, 16);
- /* t0 will be max/min of t0 and t1 */
- if (opc == OPC_MXU_D16MAX) {
- tcg_gen_smax_i32(t0, t0, t1);
- } else {
- tcg_gen_smin_i32(t0, t0, t1);
- }
- /* return resulting half-words to its original position */
- tcg_gen_shri_i32(t0, t0, 16);
- /* finally update the destination */
- tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- }
-}
-
-/*
- * Q8MAX
- * Update XRa with the 8-bit-wise maximums of signed integers
- * contained in XRb and XRc.
- *
- * Q8MIN
- * Update XRa with the 8-bit-wise minimums of signed integers
- * contained in XRb and XRc.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- */
-static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx)
-{
- uint32_t pad, opc, XRc, XRb, XRa;
-
- pad = extract32(ctx->opcode, 21, 5);
- opc = extract32(ctx->opcode, 18, 3);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRc == 0))) {
- /* both operands zero registers -> just set destination to zero */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else if (unlikely((XRb == 0) || (XRc == 0))) {
- /* exactly one operand is zero register - make it be the first...*/
- uint32_t XRx = XRb ? XRb : XRc;
- /* ...and do byte-wise max/min with one operand 0 */
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_const_i32(0);
- int32_t i;
-
- /* the leftmost byte (byte 3) first */
- tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF000000);
- if (opc == OPC_MXU_Q8MAX) {
- tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
- } else {
- tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
- }
-
- /* bytes 2, 1, 0 */
- for (i = 2; i >= 0; i--) {
- /* extract the byte */
- tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF << (8 * i));
- /* move the byte to the leftmost position */
- tcg_gen_shli_i32(t0, t0, 8 * (3 - i));
- /* t0 will be max/min of t0 and t1 */
- if (opc == OPC_MXU_Q8MAX) {
- tcg_gen_smax_i32(t0, t0, t1);
- } else {
- tcg_gen_smin_i32(t0, t0, t1);
- }
- /* return resulting byte to its original position */
- tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
- /* finally update the destination */
- tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
- }
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just set destination to one of them */
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- } else {
- /* the most general case */
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_temp_new();
- int32_t i;
-
- /* the leftmost bytes (bytes 3) first */
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF000000);
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000);
- if (opc == OPC_MXU_Q8MAX) {
- tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
- } else {
- tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
- }
-
- /* bytes 2, 1, 0 */
- for (i = 2; i >= 0; i--) {
- /* extract corresponding bytes */
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF << (8 * i));
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF << (8 * i));
- /* move the bytes to the leftmost position */
- tcg_gen_shli_i32(t0, t0, 8 * (3 - i));
- tcg_gen_shli_i32(t1, t1, 8 * (3 - i));
- /* t0 will be max/min of t0 and t1 */
- if (opc == OPC_MXU_Q8MAX) {
- tcg_gen_smax_i32(t0, t0, t1);
- } else {
- tcg_gen_smin_i32(t0, t0, t1);
- }
- /* return resulting byte to its original position */
- tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
- /* finally update the destination */
- tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
- }
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- }
-}
-
-
-/*
- * MXU instruction category: align
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * S32ALN S32ALNI
- */
-
-/*
- * S32ALNI XRc, XRb, XRa, optn3
- * Arrange bytes from XRb and XRc according to one of five sets of
- * rules determined by optn3, and place the result in XRa.
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+-----+---+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |optn3|0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
- * +-----------+-----+---+-----+-------+-------+-------+-----------+
- *
- */
-static void gen_mxu_S32ALNI(DisasContext *ctx)
-{
- uint32_t optn3, pad, XRc, XRb, XRa;
-
- optn3 = extract32(ctx->opcode, 23, 3);
- pad = extract32(ctx->opcode, 21, 2);
- XRc = extract32(ctx->opcode, 14, 4);
- XRb = extract32(ctx->opcode, 10, 4);
- XRa = extract32(ctx->opcode, 6, 4);
-
- if (unlikely(pad != 0)) {
- /* opcode padding incorrect -> do nothing */
- } else if (unlikely(XRa == 0)) {
- /* destination is zero register -> do nothing */
- } else if (unlikely((XRb == 0) && (XRc == 0))) {
- /* both operands zero registers -> just set destination to all 0s */
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- } else if (unlikely(XRb == 0)) {
- /* XRb zero register -> just appropriatelly shift XRc into XRa */
- switch (optn3) {
- case MXU_OPTN3_PTN0:
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- break;
- case MXU_OPTN3_PTN1:
- case MXU_OPTN3_PTN2:
- case MXU_OPTN3_PTN3:
- tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1],
- 8 * (4 - optn3));
- break;
- case MXU_OPTN3_PTN4:
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
- break;
- }
- } else if (unlikely(XRc == 0)) {
- /* XRc zero register -> just appropriatelly shift XRb into XRa */
- switch (optn3) {
- case MXU_OPTN3_PTN0:
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- break;
- case MXU_OPTN3_PTN1:
- case MXU_OPTN3_PTN2:
- case MXU_OPTN3_PTN3:
- tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3);
- break;
- case MXU_OPTN3_PTN4:
- tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
- break;
- }
- } else if (unlikely(XRb == XRc)) {
- /* both operands same -> just rotation or moving from any of them */
- switch (optn3) {
- case MXU_OPTN3_PTN0:
- case MXU_OPTN3_PTN4:
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- break;
- case MXU_OPTN3_PTN1:
- case MXU_OPTN3_PTN2:
- case MXU_OPTN3_PTN3:
- tcg_gen_rotli_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3);
- break;
- }
- } else {
- /* the most general case */
- switch (optn3) {
- case MXU_OPTN3_PTN0:
- {
- /* */
- /* XRb XRc */
- /* +---------------+ */
- /* | A B C D | E F G H */
- /* +-------+-------+ */
- /* | */
- /* XRa */
- /* */
-
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
- }
- break;
- case MXU_OPTN3_PTN1:
- {
- /* */
- /* XRb XRc */
- /* +-------------------+ */
- /* A | B C D E | F G H */
- /* +---------+---------+ */
- /* | */
- /* XRa */
- /* */
-
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_temp_new();
-
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x00FFFFFF);
- tcg_gen_shli_i32(t0, t0, 8);
-
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000);
- tcg_gen_shri_i32(t1, t1, 24);
-
- tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- }
- break;
- case MXU_OPTN3_PTN2:
- {
- /* */
- /* XRb XRc */
- /* +-------------------+ */
- /* A B | C D E F | G H */
- /* +---------+---------+ */
- /* | */
- /* XRa */
- /* */
-
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_temp_new();
-
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF);
- tcg_gen_shli_i32(t0, t0, 16);
-
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000);
- tcg_gen_shri_i32(t1, t1, 16);
-
- tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- }
- break;
- case MXU_OPTN3_PTN3:
- {
- /* */
- /* XRb XRc */
- /* +-------------------+ */
- /* A B C | D E F G | H */
- /* +---------+---------+ */
- /* | */
- /* XRa */
- /* */
-
- TCGv_i32 t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_temp_new();
-
- tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x000000FF);
- tcg_gen_shli_i32(t0, t0, 24);
-
- tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFFFF00);
- tcg_gen_shri_i32(t1, t1, 8);
-
- tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
-
- tcg_temp_free(t1);
- tcg_temp_free(t0);
- }
- break;
- case MXU_OPTN3_PTN4:
- {
- /* */
- /* XRb XRc */
- /* +---------------+ */
- /* A B C D | E F G H | */
- /* +-------+-------+ */
- /* | */
- /* XRa */
- /* */
-
- tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
- }
- break;
- }
- }
-}
-
-
-/*
- * Decoding engine for MXU
- * =======================
- */
-
-/*
- *
- * Decode MXU pool00
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL00|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool00(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 18, 3);
-
- switch (opcode) {
- case OPC_MXU_S32MAX:
- case OPC_MXU_S32MIN:
- gen_mxu_S32MAX_S32MIN(ctx);
- break;
- case OPC_MXU_D16MAX:
- case OPC_MXU_D16MIN:
- gen_mxu_D16MAX_D16MIN(ctx);
- break;
- case OPC_MXU_Q8MAX:
- case OPC_MXU_Q8MIN:
- gen_mxu_Q8MAX_Q8MIN(ctx);
- break;
- case OPC_MXU_Q8SLT:
- /* TODO: Implement emulation of Q8SLT instruction. */
- MIPS_INVAL("OPC_MXU_Q8SLT");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8SLTU:
- /* TODO: Implement emulation of Q8SLTU instruction. */
- MIPS_INVAL("OPC_MXU_Q8SLTU");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool01
- *
- * S32SLT, D16SLT, D16AVG, D16AVGR, Q8AVG, Q8AVGR:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL01|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- * Q8ADD:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+-----+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |en2|0 0 0|x x x| XRc | XRb | XRa |MXU__POOL01|
- * +-----------+---+-----+-----+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool01(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 18, 3);
-
- switch (opcode) {
- case OPC_MXU_S32SLT:
- /* TODO: Implement emulation of S32SLT instruction. */
- MIPS_INVAL("OPC_MXU_S32SLT");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16SLT:
- /* TODO: Implement emulation of D16SLT instruction. */
- MIPS_INVAL("OPC_MXU_D16SLT");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16AVG:
- /* TODO: Implement emulation of D16AVG instruction. */
- MIPS_INVAL("OPC_MXU_D16AVG");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16AVGR:
- /* TODO: Implement emulation of D16AVGR instruction. */
- MIPS_INVAL("OPC_MXU_D16AVGR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8AVG:
- /* TODO: Implement emulation of Q8AVG instruction. */
- MIPS_INVAL("OPC_MXU_Q8AVG");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8AVGR:
- /* TODO: Implement emulation of Q8AVGR instruction. */
- MIPS_INVAL("OPC_MXU_Q8AVGR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8ADD:
- /* TODO: Implement emulation of Q8ADD instruction. */
- MIPS_INVAL("OPC_MXU_Q8ADD");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool02
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL02|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool02(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 18, 3);
-
- switch (opcode) {
- case OPC_MXU_S32CPS:
- /* TODO: Implement emulation of S32CPS instruction. */
- MIPS_INVAL("OPC_MXU_S32CPS");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16CPS:
- /* TODO: Implement emulation of D16CPS instruction. */
- MIPS_INVAL("OPC_MXU_D16CPS");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8ABD:
- /* TODO: Implement emulation of Q8ABD instruction. */
- MIPS_INVAL("OPC_MXU_Q8ABD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16SAT:
- /* TODO: Implement emulation of Q16SAT instruction. */
- MIPS_INVAL("OPC_MXU_Q16SAT");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool03
- *
- * D16MULF:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |x x|on2|0 0 0 0| XRc | XRb | XRa |MXU__POOL03|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- * D16MULE:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |x x|on2| Xd | XRc | XRb | XRa |MXU__POOL03|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool03(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 24, 2);
-
- switch (opcode) {
- case OPC_MXU_D16MULF:
- /* TODO: Implement emulation of D16MULF instruction. */
- MIPS_INVAL("OPC_MXU_D16MULF");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16MULE:
- /* TODO: Implement emulation of D16MULE instruction. */
- MIPS_INVAL("OPC_MXU_D16MULE");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool04
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-+-------------------+-------+-----------+
- * | SPECIAL2 | rb |x| s12 | XRa |MXU__POOL04|
- * +-----------+---------+-+-------------------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool04(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 20, 1);
-
- switch (opcode) {
- case OPC_MXU_S32LDD:
- case OPC_MXU_S32LDDR:
- gen_mxu_s32ldd_s32lddr(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool05
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-+-------------------+-------+-----------+
- * | SPECIAL2 | rb |x| s12 | XRa |MXU__POOL05|
- * +-----------+---------+-+-------------------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool05(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 20, 1);
-
- switch (opcode) {
- case OPC_MXU_S32STD:
- /* TODO: Implement emulation of S32STD instruction. */
- MIPS_INVAL("OPC_MXU_S32STD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32STDR:
- /* TODO: Implement emulation of S32STDR instruction. */
- MIPS_INVAL("OPC_MXU_S32STDR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool06
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+-------+-------+-----------+
- * | SPECIAL2 | rb | rc |st2|x x x x| XRa |MXU__POOL06|
- * +-----------+---------+---------+---+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool06(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 10, 4);
-
- switch (opcode) {
- case OPC_MXU_S32LDDV:
- /* TODO: Implement emulation of S32LDDV instruction. */
- MIPS_INVAL("OPC_MXU_S32LDDV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32LDDVR:
- /* TODO: Implement emulation of S32LDDVR instruction. */
- MIPS_INVAL("OPC_MXU_S32LDDVR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool07
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+-------+-------+-----------+
- * | SPECIAL2 | rb | rc |st2|x x x x| XRa |MXU__POOL07|
- * +-----------+---------+---------+---+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool07(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 10, 4);
-
- switch (opcode) {
- case OPC_MXU_S32STDV:
- /* TODO: Implement emulation of S32TDV instruction. */
- MIPS_INVAL("OPC_MXU_S32TDV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32STDVR:
- /* TODO: Implement emulation of S32TDVR instruction. */
- MIPS_INVAL("OPC_MXU_S32TDVR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool08
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-+-------------------+-------+-----------+
- * | SPECIAL2 | rb |x| s12 | XRa |MXU__POOL08|
- * +-----------+---------+-+-------------------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool08(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 20, 1);
-
- switch (opcode) {
- case OPC_MXU_S32LDI:
- /* TODO: Implement emulation of S32LDI instruction. */
- MIPS_INVAL("OPC_MXU_S32LDI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32LDIR:
- /* TODO: Implement emulation of S32LDIR instruction. */
- MIPS_INVAL("OPC_MXU_S32LDIR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool09
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-+-------------------+-------+-----------+
- * | SPECIAL2 | rb |x| s12 | XRa |MXU__POOL09|
- * +-----------+---------+-+-------------------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool09(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 5, 0);
-
- switch (opcode) {
- case OPC_MXU_S32SDI:
- /* TODO: Implement emulation of S32SDI instruction. */
- MIPS_INVAL("OPC_MXU_S32SDI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32SDIR:
- /* TODO: Implement emulation of S32SDIR instruction. */
- MIPS_INVAL("OPC_MXU_S32SDIR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool10
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+-------+-------+-----------+
- * | SPECIAL2 | rb | rc |st2|x x x x| XRa |MXU__POOL10|
- * +-----------+---------+---------+---+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool10(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 5, 0);
-
- switch (opcode) {
- case OPC_MXU_S32LDIV:
- /* TODO: Implement emulation of S32LDIV instruction. */
- MIPS_INVAL("OPC_MXU_S32LDIV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32LDIVR:
- /* TODO: Implement emulation of S32LDIVR instruction. */
- MIPS_INVAL("OPC_MXU_S32LDIVR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool11
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+-------+-------+-----------+
- * | SPECIAL2 | rb | rc |st2|x x x x| XRa |MXU__POOL11|
- * +-----------+---------+---------+---+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool11(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 10, 4);
-
- switch (opcode) {
- case OPC_MXU_S32SDIV:
- /* TODO: Implement emulation of S32SDIV instruction. */
- MIPS_INVAL("OPC_MXU_S32SDIV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32SDIVR:
- /* TODO: Implement emulation of S32SDIVR instruction. */
- MIPS_INVAL("OPC_MXU_S32SDIVR");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool12
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |an2|x x| Xd | XRc | XRb | XRa |MXU__POOL12|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool12(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 22, 2);
-
- switch (opcode) {
- case OPC_MXU_D32ACC:
- /* TODO: Implement emulation of D32ACC instruction. */
- MIPS_INVAL("OPC_MXU_D32ACC");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32ACCM:
- /* TODO: Implement emulation of D32ACCM instruction. */
- MIPS_INVAL("OPC_MXU_D32ACCM");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32ASUM:
- /* TODO: Implement emulation of D32ASUM instruction. */
- MIPS_INVAL("OPC_MXU_D32ASUM");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool13
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |en2|x x|0 0 0 0| XRc | XRb | XRa |MXU__POOL13|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool13(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 22, 2);
-
- switch (opcode) {
- case OPC_MXU_Q16ACC:
- /* TODO: Implement emulation of Q16ACC instruction. */
- MIPS_INVAL("OPC_MXU_Q16ACC");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16ACCM:
- /* TODO: Implement emulation of Q16ACCM instruction. */
- MIPS_INVAL("OPC_MXU_Q16ACCM");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16ASUM:
- /* TODO: Implement emulation of Q16ASUM instruction. */
- MIPS_INVAL("OPC_MXU_Q16ASUM");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool14
- *
- * Q8ADDE, Q8ACCE:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0|x x| XRd | XRc | XRb | XRa |MXU__POOL14|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- * D8SUM, D8SUMC:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |en2|x x|0 0 0 0| XRc | XRb | XRa |MXU__POOL14|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool14(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 22, 2);
-
- switch (opcode) {
- case OPC_MXU_Q8ADDE:
- /* TODO: Implement emulation of Q8ADDE instruction. */
- MIPS_INVAL("OPC_MXU_Q8ADDE");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D8SUM:
- /* TODO: Implement emulation of D8SUM instruction. */
- MIPS_INVAL("OPC_MXU_D8SUM");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D8SUMC:
- /* TODO: Implement emulation of D8SUMC instruction. */
- MIPS_INVAL("OPC_MXU_D8SUMC");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool15
- *
- * S32MUL, S32MULU, S32EXTRV:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+-------+-------+-----------+
- * | SPECIAL2 | rs | rt |x x| XRd | XRa |MXU__POOL15|
- * +-----------+---------+---------+---+-------+-------+-----------+
- *
- * S32EXTR:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+-------+-------+-----------+
- * | SPECIAL2 | rb | sft5 |x x| XRd | XRa |MXU__POOL15|
- * +-----------+---------+---------+---+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool15(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 14, 2);
-
- switch (opcode) {
- case OPC_MXU_S32MUL:
- /* TODO: Implement emulation of S32MUL instruction. */
- MIPS_INVAL("OPC_MXU_S32MUL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32MULU:
- /* TODO: Implement emulation of S32MULU instruction. */
- MIPS_INVAL("OPC_MXU_S32MULU");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32EXTR:
- /* TODO: Implement emulation of S32EXTR instruction. */
- MIPS_INVAL("OPC_MXU_S32EXTR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32EXTRV:
- /* TODO: Implement emulation of S32EXTRV instruction. */
- MIPS_INVAL("OPC_MXU_S32EXTRV");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool16
- *
- * D32SARW:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 | rb |x x x| XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- * S32ALN:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 | rs |x x x| XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- * S32ALNI:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+-----+---+-----+-------+-------+-------+-----------+
- * | SPECIAL2 | s3 |0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
- * +-----------+-----+---+-----+-------+-------+-------+-----------+
- *
- * S32LUI:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+-----+---+-----+-------+---------------+-----------+
- * | SPECIAL2 |optn3|0 0|x x x| XRc | s8 |MXU__POOL16|
- * +-----------+-----+---+-----+-------+---------------+-----------+
- *
- * S32NOR, S32AND, S32OR, S32XOR:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 18, 3);
-
- switch (opcode) {
- case OPC_MXU_D32SARW:
- /* TODO: Implement emulation of D32SARW instruction. */
- MIPS_INVAL("OPC_MXU_D32SARW");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32ALN:
- /* TODO: Implement emulation of S32ALN instruction. */
- MIPS_INVAL("OPC_MXU_S32ALN");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32ALNI:
- gen_mxu_S32ALNI(ctx);
- break;
- case OPC_MXU_S32LUI:
- /* TODO: Implement emulation of S32LUI instruction. */
- MIPS_INVAL("OPC_MXU_S32LUI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32NOR:
- gen_mxu_S32NOR(ctx);
- break;
- case OPC_MXU_S32AND:
- gen_mxu_S32AND(ctx);
- break;
- case OPC_MXU_S32OR:
- gen_mxu_S32OR(ctx);
- break;
- case OPC_MXU_S32XOR:
- gen_mxu_S32XOR(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool17
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+---------+---+---------+-----+-----------+
- * | SPECIAL2 | rs | rt |0 0| rd |x x x|MXU__POOL15|
- * +-----------+---------+---------+---+---------+-----+-----------+
- *
- */
-static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 6, 2);
-
- switch (opcode) {
- case OPC_MXU_LXW:
- /* TODO: Implement emulation of LXW instruction. */
- MIPS_INVAL("OPC_MXU_LXW");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_LXH:
- /* TODO: Implement emulation of LXH instruction. */
- MIPS_INVAL("OPC_MXU_LXH");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_LXHU:
- /* TODO: Implement emulation of LXHU instruction. */
- MIPS_INVAL("OPC_MXU_LXHU");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_LXB:
- /* TODO: Implement emulation of LXB instruction. */
- MIPS_INVAL("OPC_MXU_LXB");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_LXBU:
- /* TODO: Implement emulation of LXBU instruction. */
- MIPS_INVAL("OPC_MXU_LXBU");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-/*
- *
- * Decode MXU pool18
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 | rb |x x x| XRd | XRa |0 0 0 0|MXU__POOL18|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 18, 3);
-
- switch (opcode) {
- case OPC_MXU_D32SLLV:
- /* TODO: Implement emulation of D32SLLV instruction. */
- MIPS_INVAL("OPC_MXU_D32SLLV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32SLRV:
- /* TODO: Implement emulation of D32SLRV instruction. */
- MIPS_INVAL("OPC_MXU_D32SLRV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32SARV:
- /* TODO: Implement emulation of D32SARV instruction. */
- MIPS_INVAL("OPC_MXU_D32SARV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16SLLV:
- /* TODO: Implement emulation of Q16SLLV instruction. */
- MIPS_INVAL("OPC_MXU_Q16SLLV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16SLRV:
- /* TODO: Implement emulation of Q16SLRV instruction. */
- MIPS_INVAL("OPC_MXU_Q16SLRV");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16SARV:
- /* TODO: Implement emulation of Q16SARV instruction. */
- MIPS_INVAL("OPC_MXU_Q16SARV");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool19
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0|x x| XRd | XRc | XRb | XRa |MXU__POOL19|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 22, 2);
-
- switch (opcode) {
- case OPC_MXU_Q8MUL:
- case OPC_MXU_Q8MULSU:
- gen_mxu_q8mul_q8mulsu(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool20
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL20|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool20(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 18, 3);
-
- switch (opcode) {
- case OPC_MXU_Q8MOVZ:
- /* TODO: Implement emulation of Q8MOVZ instruction. */
- MIPS_INVAL("OPC_MXU_Q8MOVZ");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8MOVN:
- /* TODO: Implement emulation of Q8MOVN instruction. */
- MIPS_INVAL("OPC_MXU_Q8MOVN");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16MOVZ:
- /* TODO: Implement emulation of D16MOVZ instruction. */
- MIPS_INVAL("OPC_MXU_D16MOVZ");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16MOVN:
- /* TODO: Implement emulation of D16MOVN instruction. */
- MIPS_INVAL("OPC_MXU_D16MOVN");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32MOVZ:
- /* TODO: Implement emulation of S32MOVZ instruction. */
- MIPS_INVAL("OPC_MXU_S32MOVZ");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32MOVN:
- /* TODO: Implement emulation of S32MOVN instruction. */
- MIPS_INVAL("OPC_MXU_S32MOVN");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-/*
- *
- * Decode MXU pool21
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |an2|x x| XRd | XRc | XRb | XRa |MXU__POOL21|
- * +-----------+---+---+-------+-------+-------+-------+-----------+
- *
- */
-static void decode_opc_mxu__pool21(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opcode = extract32(ctx->opcode, 22, 2);
-
- switch (opcode) {
- case OPC_MXU_Q8MAC:
- /* TODO: Implement emulation of Q8MAC instruction. */
- MIPS_INVAL("OPC_MXU_Q8MAC");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8MACSU:
- /* TODO: Implement emulation of Q8MACSU instruction. */
- MIPS_INVAL("OPC_MXU_Q8MACSU");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-
-/*
- * Main MXU decoding function
- *
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------------------------------------+-----------+
- * | SPECIAL2 | |x x x x x x|
- * +-----------+---------------------------------------+-----------+
- *
- */
-static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx)
-{
- /*
- * TODO: Investigate necessity of including handling of
- * CLZ, CLO, SDBB in this function, as they belong to
- * SPECIAL2 opcode space for regular pre-R6 MIPS ISAs.
- */
- uint32_t opcode = extract32(ctx->opcode, 0, 6);
-
- if (opcode == OPC__MXU_MUL) {
- uint32_t rs, rt, rd, op1;
-
- rs = extract32(ctx->opcode, 21, 5);
- rt = extract32(ctx->opcode, 16, 5);
- rd = extract32(ctx->opcode, 11, 5);
- op1 = MASK_SPECIAL2(ctx->opcode);
-
- gen_arith(ctx, op1, rd, rs, rt);
-
- return;
- }
-
- if (opcode == OPC_MXU_S32M2I) {
- gen_mxu_s32m2i(ctx);
- return;
- }
-
- if (opcode == OPC_MXU_S32I2M) {
- gen_mxu_s32i2m(ctx);
- return;
- }
-
- {
- TCGv t_mxu_cr = tcg_temp_new();
- TCGLabel *l_exit = gen_new_label();
-
- gen_load_mxu_cr(t_mxu_cr);
- tcg_gen_andi_tl(t_mxu_cr, t_mxu_cr, MXU_CR_MXU_EN);
- tcg_gen_brcondi_tl(TCG_COND_NE, t_mxu_cr, MXU_CR_MXU_EN, l_exit);
-
- switch (opcode) {
- case OPC_MXU_S32MADD:
- /* TODO: Implement emulation of S32MADD instruction. */
- MIPS_INVAL("OPC_MXU_S32MADD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32MADDU:
- /* TODO: Implement emulation of S32MADDU instruction. */
- MIPS_INVAL("OPC_MXU_S32MADDU");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL00:
- decode_opc_mxu__pool00(env, ctx);
- break;
- case OPC_MXU_S32MSUB:
- /* TODO: Implement emulation of S32MSUB instruction. */
- MIPS_INVAL("OPC_MXU_S32MSUB");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32MSUBU:
- /* TODO: Implement emulation of S32MSUBU instruction. */
- MIPS_INVAL("OPC_MXU_S32MSUBU");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL01:
- decode_opc_mxu__pool01(env, ctx);
- break;
- case OPC_MXU__POOL02:
- decode_opc_mxu__pool02(env, ctx);
- break;
- case OPC_MXU_D16MUL:
- gen_mxu_d16mul(ctx);
- break;
- case OPC_MXU__POOL03:
- decode_opc_mxu__pool03(env, ctx);
- break;
- case OPC_MXU_D16MAC:
- gen_mxu_d16mac(ctx);
- break;
- case OPC_MXU_D16MACF:
- /* TODO: Implement emulation of D16MACF instruction. */
- MIPS_INVAL("OPC_MXU_D16MACF");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16MADL:
- /* TODO: Implement emulation of D16MADL instruction. */
- MIPS_INVAL("OPC_MXU_D16MADL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S16MAD:
- /* TODO: Implement emulation of S16MAD instruction. */
- MIPS_INVAL("OPC_MXU_S16MAD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16ADD:
- /* TODO: Implement emulation of Q16ADD instruction. */
- MIPS_INVAL("OPC_MXU_Q16ADD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D16MACE:
- /* TODO: Implement emulation of D16MACE instruction. */
- MIPS_INVAL("OPC_MXU_D16MACE");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL04:
- decode_opc_mxu__pool04(env, ctx);
- break;
- case OPC_MXU__POOL05:
- decode_opc_mxu__pool05(env, ctx);
- break;
- case OPC_MXU__POOL06:
- decode_opc_mxu__pool06(env, ctx);
- break;
- case OPC_MXU__POOL07:
- decode_opc_mxu__pool07(env, ctx);
- break;
- case OPC_MXU__POOL08:
- decode_opc_mxu__pool08(env, ctx);
- break;
- case OPC_MXU__POOL09:
- decode_opc_mxu__pool09(env, ctx);
- break;
- case OPC_MXU__POOL10:
- decode_opc_mxu__pool10(env, ctx);
- break;
- case OPC_MXU__POOL11:
- decode_opc_mxu__pool11(env, ctx);
- break;
- case OPC_MXU_D32ADD:
- /* TODO: Implement emulation of D32ADD instruction. */
- MIPS_INVAL("OPC_MXU_D32ADD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL12:
- decode_opc_mxu__pool12(env, ctx);
- break;
- case OPC_MXU__POOL13:
- decode_opc_mxu__pool13(env, ctx);
- break;
- case OPC_MXU__POOL14:
- decode_opc_mxu__pool14(env, ctx);
- break;
- case OPC_MXU_Q8ACCE:
- /* TODO: Implement emulation of Q8ACCE instruction. */
- MIPS_INVAL("OPC_MXU_Q8ACCE");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S8LDD:
- gen_mxu_s8ldd(ctx);
- break;
- case OPC_MXU_S8STD:
- /* TODO: Implement emulation of S8STD instruction. */
- MIPS_INVAL("OPC_MXU_S8STD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S8LDI:
- /* TODO: Implement emulation of S8LDI instruction. */
- MIPS_INVAL("OPC_MXU_S8LDI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S8SDI:
- /* TODO: Implement emulation of S8SDI instruction. */
- MIPS_INVAL("OPC_MXU_S8SDI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL15:
- decode_opc_mxu__pool15(env, ctx);
- break;
- case OPC_MXU__POOL16:
- decode_opc_mxu__pool16(env, ctx);
- break;
- case OPC_MXU__POOL17:
- decode_opc_mxu__pool17(env, ctx);
- break;
- case OPC_MXU_S16LDD:
- /* TODO: Implement emulation of S16LDD instruction. */
- MIPS_INVAL("OPC_MXU_S16LDD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S16STD:
- /* TODO: Implement emulation of S16STD instruction. */
- MIPS_INVAL("OPC_MXU_S16STD");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S16LDI:
- /* TODO: Implement emulation of S16LDI instruction. */
- MIPS_INVAL("OPC_MXU_S16LDI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S16SDI:
- /* TODO: Implement emulation of S16SDI instruction. */
- MIPS_INVAL("OPC_MXU_S16SDI");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32SLL:
- /* TODO: Implement emulation of D32SLL instruction. */
- MIPS_INVAL("OPC_MXU_D32SLL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32SLR:
- /* TODO: Implement emulation of D32SLR instruction. */
- MIPS_INVAL("OPC_MXU_D32SLR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32SARL:
- /* TODO: Implement emulation of D32SARL instruction. */
- MIPS_INVAL("OPC_MXU_D32SARL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_D32SAR:
- /* TODO: Implement emulation of D32SAR instruction. */
- MIPS_INVAL("OPC_MXU_D32SAR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16SLL:
- /* TODO: Implement emulation of Q16SLL instruction. */
- MIPS_INVAL("OPC_MXU_Q16SLL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q16SLR:
- /* TODO: Implement emulation of Q16SLR instruction. */
- MIPS_INVAL("OPC_MXU_Q16SLR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL18:
- decode_opc_mxu__pool18(env, ctx);
- break;
- case OPC_MXU_Q16SAR:
- /* TODO: Implement emulation of Q16SAR instruction. */
- MIPS_INVAL("OPC_MXU_Q16SAR");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU__POOL19:
- decode_opc_mxu__pool19(env, ctx);
- break;
- case OPC_MXU__POOL20:
- decode_opc_mxu__pool20(env, ctx);
- break;
- case OPC_MXU__POOL21:
- decode_opc_mxu__pool21(env, ctx);
- break;
- case OPC_MXU_Q16SCOP:
- /* TODO: Implement emulation of Q16SCOP instruction. */
- MIPS_INVAL("OPC_MXU_Q16SCOP");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8MADL:
- /* TODO: Implement emulation of Q8MADL instruction. */
- MIPS_INVAL("OPC_MXU_Q8MADL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_S32SFL:
- /* TODO: Implement emulation of S32SFL instruction. */
- MIPS_INVAL("OPC_MXU_S32SFL");
- gen_reserved_instruction(ctx);
- break;
- case OPC_MXU_Q8SAD:
- /* TODO: Implement emulation of Q8SAD instruction. */
- MIPS_INVAL("OPC_MXU_Q8SAD");
- gen_reserved_instruction(ctx);
- break;
- default:
- MIPS_INVAL("decode_opc_mxu");
- gen_reserved_instruction(ctx);
- }
-
- gen_set_label(l_exit);
- tcg_temp_free(t_mxu_cr);
- }
-}
-
-#endif /* !defined(TARGET_MIPS64) */
-
-
static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
{
int rs, rt, rd;
@@ -27851,146 +24402,6 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
#if defined(TARGET_MIPS64)
-static void decode_mmi0(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opc = MASK_MMI0(ctx->opcode);
-
- switch (opc) {
- case MMI_OPC_0_PADDW: /* TODO: MMI_OPC_0_PADDW */
- case MMI_OPC_0_PSUBW: /* TODO: MMI_OPC_0_PSUBW */
- case MMI_OPC_0_PCGTW: /* TODO: MMI_OPC_0_PCGTW */
- case MMI_OPC_0_PMAXW: /* TODO: MMI_OPC_0_PMAXW */
- case MMI_OPC_0_PADDH: /* TODO: MMI_OPC_0_PADDH */
- case MMI_OPC_0_PSUBH: /* TODO: MMI_OPC_0_PSUBH */
- case MMI_OPC_0_PCGTH: /* TODO: MMI_OPC_0_PCGTH */
- case MMI_OPC_0_PMAXH: /* TODO: MMI_OPC_0_PMAXH */
- case MMI_OPC_0_PADDB: /* TODO: MMI_OPC_0_PADDB */
- case MMI_OPC_0_PSUBB: /* TODO: MMI_OPC_0_PSUBB */
- case MMI_OPC_0_PCGTB: /* TODO: MMI_OPC_0_PCGTB */
- case MMI_OPC_0_PADDSW: /* TODO: MMI_OPC_0_PADDSW */
- case MMI_OPC_0_PSUBSW: /* TODO: MMI_OPC_0_PSUBSW */
- case MMI_OPC_0_PEXTLW: /* TODO: MMI_OPC_0_PEXTLW */
- case MMI_OPC_0_PPACW: /* TODO: MMI_OPC_0_PPACW */
- case MMI_OPC_0_PADDSH: /* TODO: MMI_OPC_0_PADDSH */
- case MMI_OPC_0_PSUBSH: /* TODO: MMI_OPC_0_PSUBSH */
- case MMI_OPC_0_PEXTLH: /* TODO: MMI_OPC_0_PEXTLH */
- case MMI_OPC_0_PPACH: /* TODO: MMI_OPC_0_PPACH */
- case MMI_OPC_0_PADDSB: /* TODO: MMI_OPC_0_PADDSB */
- case MMI_OPC_0_PSUBSB: /* TODO: MMI_OPC_0_PSUBSB */
- case MMI_OPC_0_PEXTLB: /* TODO: MMI_OPC_0_PEXTLB */
- case MMI_OPC_0_PPACB: /* TODO: MMI_OPC_0_PPACB */
- case MMI_OPC_0_PEXT5: /* TODO: MMI_OPC_0_PEXT5 */
- case MMI_OPC_0_PPAC5: /* TODO: MMI_OPC_0_PPAC5 */
- gen_reserved_instruction(ctx); /* TODO: MMI_OPC_CLASS_MMI0 */
- break;
- default:
- MIPS_INVAL("TX79 MMI class MMI0");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-static void decode_mmi1(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opc = MASK_MMI1(ctx->opcode);
-
- switch (opc) {
- case MMI_OPC_1_PABSW: /* TODO: MMI_OPC_1_PABSW */
- case MMI_OPC_1_PCEQW: /* TODO: MMI_OPC_1_PCEQW */
- case MMI_OPC_1_PMINW: /* TODO: MMI_OPC_1_PMINW */
- case MMI_OPC_1_PADSBH: /* TODO: MMI_OPC_1_PADSBH */
- case MMI_OPC_1_PABSH: /* TODO: MMI_OPC_1_PABSH */
- case MMI_OPC_1_PCEQH: /* TODO: MMI_OPC_1_PCEQH */
- case MMI_OPC_1_PMINH: /* TODO: MMI_OPC_1_PMINH */
- case MMI_OPC_1_PCEQB: /* TODO: MMI_OPC_1_PCEQB */
- case MMI_OPC_1_PADDUW: /* TODO: MMI_OPC_1_PADDUW */
- case MMI_OPC_1_PSUBUW: /* TODO: MMI_OPC_1_PSUBUW */
- case MMI_OPC_1_PEXTUW: /* TODO: MMI_OPC_1_PEXTUW */
- case MMI_OPC_1_PADDUH: /* TODO: MMI_OPC_1_PADDUH */
- case MMI_OPC_1_PSUBUH: /* TODO: MMI_OPC_1_PSUBUH */
- case MMI_OPC_1_PEXTUH: /* TODO: MMI_OPC_1_PEXTUH */
- case MMI_OPC_1_PADDUB: /* TODO: MMI_OPC_1_PADDUB */
- case MMI_OPC_1_PSUBUB: /* TODO: MMI_OPC_1_PSUBUB */
- case MMI_OPC_1_PEXTUB: /* TODO: MMI_OPC_1_PEXTUB */
- case MMI_OPC_1_QFSRV: /* TODO: MMI_OPC_1_QFSRV */
- gen_reserved_instruction(ctx); /* TODO: MMI_OPC_CLASS_MMI1 */
- break;
- default:
- MIPS_INVAL("TX79 MMI class MMI1");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-static void decode_mmi2(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opc = MASK_MMI2(ctx->opcode);
-
- switch (opc) {
- case MMI_OPC_2_PMADDW: /* TODO: MMI_OPC_2_PMADDW */
- case MMI_OPC_2_PSLLVW: /* TODO: MMI_OPC_2_PSLLVW */
- case MMI_OPC_2_PSRLVW: /* TODO: MMI_OPC_2_PSRLVW */
- case MMI_OPC_2_PMSUBW: /* TODO: MMI_OPC_2_PMSUBW */
- case MMI_OPC_2_PMFHI: /* TODO: MMI_OPC_2_PMFHI */
- case MMI_OPC_2_PMFLO: /* TODO: MMI_OPC_2_PMFLO */
- case MMI_OPC_2_PINTH: /* TODO: MMI_OPC_2_PINTH */
- case MMI_OPC_2_PMULTW: /* TODO: MMI_OPC_2_PMULTW */
- case MMI_OPC_2_PDIVW: /* TODO: MMI_OPC_2_PDIVW */
- case MMI_OPC_2_PMADDH: /* TODO: MMI_OPC_2_PMADDH */
- case MMI_OPC_2_PHMADH: /* TODO: MMI_OPC_2_PHMADH */
- case MMI_OPC_2_PAND: /* TODO: MMI_OPC_2_PAND */
- case MMI_OPC_2_PXOR: /* TODO: MMI_OPC_2_PXOR */
- case MMI_OPC_2_PMSUBH: /* TODO: MMI_OPC_2_PMSUBH */
- case MMI_OPC_2_PHMSBH: /* TODO: MMI_OPC_2_PHMSBH */
- case MMI_OPC_2_PEXEH: /* TODO: MMI_OPC_2_PEXEH */
- case MMI_OPC_2_PREVH: /* TODO: MMI_OPC_2_PREVH */
- case MMI_OPC_2_PMULTH: /* TODO: MMI_OPC_2_PMULTH */
- case MMI_OPC_2_PDIVBW: /* TODO: MMI_OPC_2_PDIVBW */
- case MMI_OPC_2_PEXEW: /* TODO: MMI_OPC_2_PEXEW */
- case MMI_OPC_2_PROT3W: /* TODO: MMI_OPC_2_PROT3W */
- gen_reserved_instruction(ctx); /* TODO: MMI_OPC_CLASS_MMI2 */
- break;
- case MMI_OPC_2_PCPYLD:
- gen_mmi_pcpyld(ctx);
- break;
- default:
- MIPS_INVAL("TX79 MMI class MMI2");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
-static void decode_mmi3(CPUMIPSState *env, DisasContext *ctx)
-{
- uint32_t opc = MASK_MMI3(ctx->opcode);
-
- switch (opc) {
- case MMI_OPC_3_PMADDUW: /* TODO: MMI_OPC_3_PMADDUW */
- case MMI_OPC_3_PSRAVW: /* TODO: MMI_OPC_3_PSRAVW */
- case MMI_OPC_3_PMTHI: /* TODO: MMI_OPC_3_PMTHI */
- case MMI_OPC_3_PMTLO: /* TODO: MMI_OPC_3_PMTLO */
- case MMI_OPC_3_PINTEH: /* TODO: MMI_OPC_3_PINTEH */
- case MMI_OPC_3_PMULTUW: /* TODO: MMI_OPC_3_PMULTUW */
- case MMI_OPC_3_PDIVUW: /* TODO: MMI_OPC_3_PDIVUW */
- case MMI_OPC_3_POR: /* TODO: MMI_OPC_3_POR */
- case MMI_OPC_3_PNOR: /* TODO: MMI_OPC_3_PNOR */
- case MMI_OPC_3_PEXCH: /* TODO: MMI_OPC_3_PEXCH */
- case MMI_OPC_3_PEXCW: /* TODO: MMI_OPC_3_PEXCW */
- gen_reserved_instruction(ctx); /* TODO: MMI_OPC_CLASS_MMI3 */
- break;
- case MMI_OPC_3_PCPYH:
- gen_mmi_pcpyh(ctx);
- break;
- case MMI_OPC_3_PCPYUD:
- gen_mmi_pcpyud(ctx);
- break;
- default:
- MIPS_INVAL("TX79 MMI class MMI3");
- gen_reserved_instruction(ctx);
- break;
- }
-}
-
static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opc = MASK_MMI(ctx->opcode);
@@ -27999,18 +24410,6 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
int rd = extract32(ctx->opcode, 11, 5);
switch (opc) {
- case MMI_OPC_CLASS_MMI0:
- decode_mmi0(env, ctx);
- break;
- case MMI_OPC_CLASS_MMI1:
- decode_mmi1(env, ctx);
- break;
- case MMI_OPC_CLASS_MMI2:
- decode_mmi2(env, ctx);
- break;
- case MMI_OPC_CLASS_MMI3:
- decode_mmi3(env, ctx);
- break;
case MMI_OPC_MULT1:
case MMI_OPC_MULTU1:
case MMI_OPC_MADD:
@@ -28023,25 +24422,6 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
case MMI_OPC_DIVU1:
gen_div1_tx79(ctx, opc, rs, rt);
break;
- case MMI_OPC_MTLO1:
- case MMI_OPC_MTHI1:
- gen_HILO1_tx79(ctx, opc, rs);
- break;
- case MMI_OPC_MFLO1:
- case MMI_OPC_MFHI1:
- gen_HILO1_tx79(ctx, opc, rd);
- break;
- case MMI_OPC_PLZCW: /* TODO: MMI_OPC_PLZCW */
- case MMI_OPC_PMFHL: /* TODO: MMI_OPC_PMFHL */
- case MMI_OPC_PMTHL: /* TODO: MMI_OPC_PMTHL */
- case MMI_OPC_PSLLH: /* TODO: MMI_OPC_PSLLH */
- case MMI_OPC_PSRLH: /* TODO: MMI_OPC_PSRLH */
- case MMI_OPC_PSRAH: /* TODO: MMI_OPC_PSRAH */
- case MMI_OPC_PSLLW: /* TODO: MMI_OPC_PSLLW */
- case MMI_OPC_PSRLW: /* TODO: MMI_OPC_PSRLW */
- case MMI_OPC_PSRAW: /* TODO: MMI_OPC_PSRAW */
- gen_reserved_instruction(ctx); /* TODO: MMI_OPC_CLASS_MMI */
- break;
default:
MIPS_INVAL("TX79 MMI class");
gen_reserved_instruction(ctx);
@@ -28276,13 +24656,18 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
#if defined(TARGET_MIPS64)
if ((ctx->insn_flags & INSN_R5900) && (ctx->insn_flags & ASE_MMI)) {
decode_mmi(env, ctx);
-#else
- if (ctx->insn_flags & ASE_MXU) {
- decode_opc_mxu(env, ctx);
+ break;
+ }
#endif
- } else {
- decode_opc_special2_legacy(env, ctx);
+ if (TARGET_LONG_BITS == 32 && (ctx->insn_flags & ASE_MXU)) {
+ if (MASK_SPECIAL2(ctx->opcode) == OPC_MUL) {
+ gen_arith(ctx, OPC_MUL, rd, rs, rt);
+ } else {
+ decode_ase_mxu(ctx, ctx->opcode);
+ }
+ break;
}
+ decode_opc_special2_legacy(env, ctx);
break;
case OPC_SPECIAL3:
#if defined(TARGET_MIPS64)
@@ -28997,6 +25382,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
if (cpu_supports_isa(env, ISA_MIPS_R6) && decode_isa_rel6(ctx, ctx->opcode)) {
return;
}
+ if (cpu_supports_isa(env, INSN_R5900) && decode_ext_txx9(ctx, ctx->opcode)) {
+ return;
+ }
if (decode_opc_legacy(env, ctx)) {
return;
@@ -29340,18 +25728,9 @@ void mips_tcg_init(void)
cpu_llval = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, llval),
"llval");
-#if !defined(TARGET_MIPS64)
- for (i = 0; i < NUMBER_OF_MXU_REGISTERS - 1; i++) {
- mxu_gpr[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPUMIPSState,
- active_tc.mxu_gpr[i]),
- mxuregnames[i]);
+ if (TARGET_LONG_BITS == 32) {
+ mxu_translate_init();
}
-
- mxu_CR = tcg_global_mem_new(cpu_env,
- offsetof(CPUMIPSState, active_tc.mxu_cr),
- mxuregnames[NUMBER_OF_MXU_REGISTERS - 1]);
-#endif /* !TARGET_MIPS64 */
}
void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb,
diff --git a/target/mips/translate.h b/target/mips/translate.h
index 468e29d757..2b3c7a69ec 100644
--- a/target/mips/translate.h
+++ b/target/mips/translate.h
@@ -148,6 +148,8 @@ void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1);
bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
+void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel);
+
extern TCGv cpu_gpr[32], cpu_PC;
#if defined(TARGET_MIPS64)
extern TCGv_i64 cpu_gpr_hi[32];
@@ -178,8 +180,16 @@ extern TCGv bcond;
/* MSA */
void msa_translate_init(void);
+/* MXU */
+void mxu_translate_init(void);
+bool decode_ase_mxu(DisasContext *ctx, uint32_t insn);
+
/* decodetree generated */
bool decode_isa_rel6(DisasContext *ctx, uint32_t insn);
bool decode_ase_msa(DisasContext *ctx, uint32_t insn);
+bool decode_ext_txx9(DisasContext *ctx, uint32_t insn);
+#if defined(TARGET_MIPS64)
+bool decode_ext_tx79(DisasContext *ctx, uint32_t insn);
+#endif
#endif
diff --git a/target/mips/tx79.decode b/target/mips/tx79.decode
new file mode 100644
index 0000000000..0f748b53a6
--- /dev/null
+++ b/target/mips/tx79.decode
@@ -0,0 +1,39 @@
+# Toshiba C790's instruction set
+#
+# Copyright (C) 2021 Philippe Mathieu-Daudé
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Toshiba Appendix B C790-Specific Instruction Set Details
+
+###########################################################################
+# Named attribute sets. These are used to make nice(er) names
+# when creating helpers common to those for the individual
+# instruction patterns.
+
+&rtype rs rt rd sa
+
+###########################################################################
+# Named instruction formats. These are generally used to
+# reduce the amount of duplication between instruction patterns.
+
+@rs_rt_rd ...... rs:5 rt:5 rd:5 ..... ...... &rtype sa=0
+@rt_rd ...... ..... rt:5 rd:5 ..... ...... &rtype rs=0 sa=0
+@rs ...... rs:5 ..... .......... ...... &rtype rt=0 rd=0 sa=0
+@rd ...... .......... rd:5 ..... ...... &rtype rs=0 rt=0 sa=0
+
+###########################################################################
+
+MFHI1 011100 0000000000 ..... 00000 010000 @rd
+MTHI1 011100 ..... 0000000000 00000 010001 @rs
+MFLO1 011100 0000000000 ..... 00000 010010 @rd
+MTLO1 011100 ..... 0000000000 00000 010011 @rs
+
+# MMI2
+
+PCPYLD 011100 ..... ..... ..... 01110 001001 @rs_rt_rd
+
+# MMI3
+
+PCPYUD 011100 ..... ..... ..... 01110 101001 @rs_rt_rd
+PCPYH 011100 00000 ..... ..... 11011 101001 @rt_rd
diff --git a/target/mips/tx79_translate.c b/target/mips/tx79_translate.c
new file mode 100644
index 0000000000..ad83774b97
--- /dev/null
+++ b/target/mips/tx79_translate.c
@@ -0,0 +1,303 @@
+/*
+ * Toshiba TX79-specific instructions translation routines
+ *
+ * Copyright (c) 2018 Fredrik Noring
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "exec/helper-gen.h"
+#include "translate.h"
+
+/* Include the auto-generated decoder. */
+#include "decode-tx79.c.inc"
+
+/*
+ * Overview of the TX79-specific instruction set
+ * =============================================
+ *
+ * The R5900 and the C790 have 128-bit wide GPRs, where the upper 64 bits
+ * are only used by the specific quadword (128-bit) LQ/SQ load/store
+ * instructions and certain multimedia instructions (MMIs). These MMIs
+ * configure the 128-bit data path as two 64-bit, four 32-bit, eight 16-bit
+ * or sixteen 8-bit paths.
+ *
+ * Reference:
+ *
+ * The Toshiba TX System RISC TX79 Core Architecture manual,
+ * https://wiki.qemu.org/File:C790.pdf
+ */
+
+bool decode_ext_tx79(DisasContext *ctx, uint32_t insn)
+{
+ if (TARGET_LONG_BITS == 64 && decode_tx79(ctx, insn)) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Three-Operand Multiply and Multiply-Add (4 instructions)
+ * --------------------------------------------------------
+ * MADD [rd,] rs, rt Multiply/Add
+ * MADDU [rd,] rs, rt Multiply/Add Unsigned
+ * MULT [rd,] rs, rt Multiply (3-operand)
+ * MULTU [rd,] rs, rt Multiply Unsigned (3-operand)
+ */
+
+/*
+ * Multiply Instructions for Pipeline 1 (10 instructions)
+ * ------------------------------------------------------
+ * MULT1 [rd,] rs, rt Multiply Pipeline 1
+ * MULTU1 [rd,] rs, rt Multiply Unsigned Pipeline 1
+ * DIV1 rs, rt Divide Pipeline 1
+ * DIVU1 rs, rt Divide Unsigned Pipeline 1
+ * MADD1 [rd,] rs, rt Multiply-Add Pipeline 1
+ * MADDU1 [rd,] rs, rt Multiply-Add Unsigned Pipeline 1
+ * MFHI1 rd Move From HI1 Register
+ * MFLO1 rd Move From LO1 Register
+ * MTHI1 rs Move To HI1 Register
+ * MTLO1 rs Move To LO1 Register
+ */
+
+static bool trans_MFHI1(DisasContext *ctx, arg_rtype *a)
+{
+ gen_store_gpr(cpu_HI[1], a->rd);
+
+ return true;
+}
+
+static bool trans_MFLO1(DisasContext *ctx, arg_rtype *a)
+{
+ gen_store_gpr(cpu_LO[1], a->rd);
+
+ return true;
+}
+
+static bool trans_MTHI1(DisasContext *ctx, arg_rtype *a)
+{
+ gen_load_gpr(cpu_HI[1], a->rs);
+
+ return true;
+}
+
+static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a)
+{
+ gen_load_gpr(cpu_LO[1], a->rs);
+
+ return true;
+}
+
+/*
+ * Arithmetic (19 instructions)
+ * ----------------------------
+ * PADDB rd, rs, rt Parallel Add Byte
+ * PSUBB rd, rs, rt Parallel Subtract Byte
+ * PADDH rd, rs, rt Parallel Add Halfword
+ * PSUBH rd, rs, rt Parallel Subtract Halfword
+ * PADDW rd, rs, rt Parallel Add Word
+ * PSUBW rd, rs, rt Parallel Subtract Word
+ * PADSBH rd, rs, rt Parallel Add/Subtract Halfword
+ * PADDSB rd, rs, rt Parallel Add with Signed Saturation Byte
+ * PSUBSB rd, rs, rt Parallel Subtract with Signed Saturation Byte
+ * PADDSH rd, rs, rt Parallel Add with Signed Saturation Halfword
+ * PSUBSH rd, rs, rt Parallel Subtract with Signed Saturation Halfword
+ * PADDSW rd, rs, rt Parallel Add with Signed Saturation Word
+ * PSUBSW rd, rs, rt Parallel Subtract with Signed Saturation Word
+ * PADDUB rd, rs, rt Parallel Add with Unsigned saturation Byte
+ * PSUBUB rd, rs, rt Parallel Subtract with Unsigned saturation Byte
+ * PADDUH rd, rs, rt Parallel Add with Unsigned saturation Halfword
+ * PSUBUH rd, rs, rt Parallel Subtract with Unsigned saturation Halfword
+ * PADDUW rd, rs, rt Parallel Add with Unsigned saturation Word
+ * PSUBUW rd, rs, rt Parallel Subtract with Unsigned saturation Word
+ */
+
+/*
+ * Min/Max (4 instructions)
+ * ------------------------
+ * PMAXH rd, rs, rt Parallel Maximum Halfword
+ * PMINH rd, rs, rt Parallel Minimum Halfword
+ * PMAXW rd, rs, rt Parallel Maximum Word
+ * PMINW rd, rs, rt Parallel Minimum Word
+ */
+
+/*
+ * Absolute (2 instructions)
+ * -------------------------
+ * PABSH rd, rt Parallel Absolute Halfword
+ * PABSW rd, rt Parallel Absolute Word
+ */
+
+/*
+ * Logical (4 instructions)
+ * ------------------------
+ * PAND rd, rs, rt Parallel AND
+ * POR rd, rs, rt Parallel OR
+ * PXOR rd, rs, rt Parallel XOR
+ * PNOR rd, rs, rt Parallel NOR
+ */
+
+/*
+ * Shift (9 instructions)
+ * ----------------------
+ * PSLLH rd, rt, sa Parallel Shift Left Logical Halfword
+ * PSRLH rd, rt, sa Parallel Shift Right Logical Halfword
+ * PSRAH rd, rt, sa Parallel Shift Right Arithmetic Halfword
+ * PSLLW rd, rt, sa Parallel Shift Left Logical Word
+ * PSRLW rd, rt, sa Parallel Shift Right Logical Word
+ * PSRAW rd, rt, sa Parallel Shift Right Arithmetic Word
+ * PSLLVW rd, rt, rs Parallel Shift Left Logical Variable Word
+ * PSRLVW rd, rt, rs Parallel Shift Right Logical Variable Word
+ * PSRAVW rd, rt, rs Parallel Shift Right Arithmetic Variable Word
+ */
+
+/*
+ * Compare (6 instructions)
+ * ------------------------
+ * PCGTB rd, rs, rt Parallel Compare for Greater Than Byte
+ * PCEQB rd, rs, rt Parallel Compare for Equal Byte
+ * PCGTH rd, rs, rt Parallel Compare for Greater Than Halfword
+ * PCEQH rd, rs, rt Parallel Compare for Equal Halfword
+ * PCGTW rd, rs, rt Parallel Compare for Greater Than Word
+ * PCEQW rd, rs, rt Parallel Compare for Equal Word
+ */
+
+/*
+ * LZC (1 instruction)
+ * -------------------
+ * PLZCW rd, rs Parallel Leading Zero or One Count Word
+ */
+
+/*
+ * Quadword Load and Store (2 instructions)
+ * ----------------------------------------
+ * LQ rt, offset(base) Load Quadword
+ * SQ rt, offset(base) Store Quadword
+ */
+
+/*
+ * Multiply and Divide (19 instructions)
+ * -------------------------------------
+ * PMULTW rd, rs, rt Parallel Multiply Word
+ * PMULTUW rd, rs, rt Parallel Multiply Unsigned Word
+ * PDIVW rs, rt Parallel Divide Word
+ * PDIVUW rs, rt Parallel Divide Unsigned Word
+ * PMADDW rd, rs, rt Parallel Multiply-Add Word
+ * PMADDUW rd, rs, rt Parallel Multiply-Add Unsigned Word
+ * PMSUBW rd, rs, rt Parallel Multiply-Subtract Word
+ * PMULTH rd, rs, rt Parallel Multiply Halfword
+ * PMADDH rd, rs, rt Parallel Multiply-Add Halfword
+ * PMSUBH rd, rs, rt Parallel Multiply-Subtract Halfword
+ * PHMADH rd, rs, rt Parallel Horizontal Multiply-Add Halfword
+ * PHMSBH rd, rs, rt Parallel Horizontal Multiply-Subtract Halfword
+ * PDIVBW rs, rt Parallel Divide Broadcast Word
+ * PMFHI rd Parallel Move From HI Register
+ * PMFLO rd Parallel Move From LO Register
+ * PMTHI rs Parallel Move To HI Register
+ * PMTLO rs Parallel Move To LO Register
+ * PMFHL rd Parallel Move From HI/LO Register
+ * PMTHL rs Parallel Move To HI/LO Register
+ */
+
+/*
+ * Pack/Extend (11 instructions)
+ * -----------------------------
+ * PPAC5 rd, rt Parallel Pack to 5 bits
+ * PPACB rd, rs, rt Parallel Pack to Byte
+ * PPACH rd, rs, rt Parallel Pack to Halfword
+ * PPACW rd, rs, rt Parallel Pack to Word
+ * PEXT5 rd, rt Parallel Extend Upper from 5 bits
+ * PEXTUB rd, rs, rt Parallel Extend Upper from Byte
+ * PEXTLB rd, rs, rt Parallel Extend Lower from Byte
+ * PEXTUH rd, rs, rt Parallel Extend Upper from Halfword
+ * PEXTLH rd, rs, rt Parallel Extend Lower from Halfword
+ * PEXTUW rd, rs, rt Parallel Extend Upper from Word
+ * PEXTLW rd, rs, rt Parallel Extend Lower from Word
+ */
+
+/*
+ * Others (16 instructions)
+ * ------------------------
+ * PCPYH rd, rt Parallel Copy Halfword
+ * PCPYLD rd, rs, rt Parallel Copy Lower Doubleword
+ * PCPYUD rd, rs, rt Parallel Copy Upper Doubleword
+ * PREVH rd, rt Parallel Reverse Halfword
+ * PINTH rd, rs, rt Parallel Interleave Halfword
+ * PINTEH rd, rs, rt Parallel Interleave Even Halfword
+ * PEXEH rd, rt Parallel Exchange Even Halfword
+ * PEXCH rd, rt Parallel Exchange Center Halfword
+ * PEXEW rd, rt Parallel Exchange Even Word
+ * PEXCW rd, rt Parallel Exchange Center Word
+ * QFSRV rd, rs, rt Quadword Funnel Shift Right Variable
+ * MFSA rd Move from Shift Amount Register
+ * MTSA rs Move to Shift Amount Register
+ * MTSAB rs, immediate Move Byte Count to Shift Amount Register
+ * MTSAH rs, immediate Move Halfword Count to Shift Amount Register
+ * PROT3W rd, rt Parallel Rotate 3 Words
+ */
+
+/* Parallel Copy Halfword */
+static bool trans_PCPYH(DisasContext *s, arg_rtype *a)
+{
+ if (a->rd == 0) {
+ /* nop */
+ return true;
+ }
+
+ if (a->rt == 0) {
+ tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
+ tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
+ return true;
+ }
+
+ tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], cpu_gpr[a->rt], 16, 16);
+ tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], cpu_gpr[a->rd], 32, 32);
+ tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt], cpu_gpr_hi[a->rt], 16, 16);
+ tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], 32, 32);
+
+ return true;
+}
+
+/* Parallel Copy Lower Doubleword */
+static bool trans_PCPYLD(DisasContext *s, arg_rtype *a)
+{
+ if (a->rd == 0) {
+ /* nop */
+ return true;
+ }
+
+ if (a->rs == 0) {
+ tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
+ } else {
+ tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr[a->rs]);
+ }
+
+ if (a->rt == 0) {
+ tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
+ } else if (a->rd != a->rt) {
+ tcg_gen_mov_i64(cpu_gpr[a->rd], cpu_gpr[a->rt]);
+ }
+
+ return true;
+}
+
+/* Parallel Copy Upper Doubleword */
+static bool trans_PCPYUD(DisasContext *s, arg_rtype *a)
+{
+ if (a->rd == 0) {
+ /* nop */
+ return true;
+ }
+
+ gen_load_gpr_hi(cpu_gpr[a->rd], a->rs);
+
+ if (a->rt == 0) {
+ tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
+ } else if (a->rd != a->rt) {
+ tcg_gen_mov_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rt]);
+ }
+
+ return true;
+}
diff --git a/target/mips/txx9_translate.c b/target/mips/txx9_translate.c
new file mode 100644
index 0000000000..8a2c0b766b
--- /dev/null
+++ b/target/mips/txx9_translate.c
@@ -0,0 +1,20 @@
+/*
+ * Toshiba TXx9 instructions translation routines
+ *
+ * Copyright (c) 2021 Philippe Mathieu-Daudé
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "translate.h"
+
+bool decode_ext_txx9(DisasContext *ctx, uint32_t insn)
+{
+#if defined(TARGET_MIPS64)
+ if (decode_ext_tx79(ctx, insn)) {
+ return true;
+ }
+#endif
+ return false;
+}
diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
index b82349d1b1..4b61a2c03f 100644
--- a/target/tricore/cpu.h
+++ b/target/tricore/cpu.h
@@ -375,18 +375,6 @@ typedef TriCoreCPU ArchCPU;
#include "exec/cpu-all.h"
-enum {
- /* 1 bit to define user level / supervisor access */
- ACCESS_USER = 0x00,
- ACCESS_SUPER = 0x01,
- /* 1 bit to indicate direction */
- ACCESS_STORE = 0x02,
- /* Type of instruction that generated the access */
- ACCESS_CODE = 0x10, /* Code fetch access */
- ACCESS_INT = 0x20, /* Integer load/store access */
- ACCESS_FLOAT = 0x30, /* floating point load/store access */
-};
-
void cpu_state_reset(CPUTriCoreState *s);
void tricore_tcg_init(void);
int cpu_tricore_signal_handler(int host_signum, void *pinfo, void *puc);
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
index 7715293263..c5e997f321 100644
--- a/target/tricore/helper.c
+++ b/target/tricore/helper.c
@@ -33,7 +33,7 @@ enum {
#if defined(CONFIG_SOFTMMU)
static int get_physical_address(CPUTriCoreState *env, hwaddr *physical,
int *prot, target_ulong address,
- int rw, int access_type)
+ MMUAccessType access_type, int mmu_idx)
{
int ret = TLBRET_MATCH;
@@ -50,7 +50,8 @@ hwaddr tricore_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
int prot;
int mmu_idx = cpu_mmu_index(&cpu->env, false);
- if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
+ if (get_physical_address(&cpu->env, &phys_addr, &prot, addr,
+ MMU_DATA_LOAD, mmu_idx)) {
return -1;
}
return phys_addr;
@@ -71,13 +72,11 @@ bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
CPUTriCoreState *env = &cpu->env;
hwaddr physical;
int prot;
- int access_type;
int ret = 0;
rw &= 1;
- access_type = ACCESS_INT;
ret = get_physical_address(env, &physical, &prot,
- address, rw, access_type);
+ address, rw, mmu_idx);
qemu_log_mask(CPU_LOG_MMU, "%s address=" TARGET_FMT_lx " ret %d physical "
TARGET_FMT_plx " prot %d\n",
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index 7752630ac1..2a814263de 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -5777,8 +5777,8 @@ static void decode_rcpw_insert(DisasContext *ctx)
switch (op2) {
case OPC2_32_RCPW_IMASK:
CHECK_REG_PAIR(r2);
- /* if pos + width > 31 undefined result */
- if (pos + width <= 31) {
+ /* if pos + width > 32 undefined result */
+ if (pos + width <= 32) {
tcg_gen_movi_tl(cpu_gpr_d[r2+1], ((1u << width) - 1) << pos);
tcg_gen_movi_tl(cpu_gpr_d[r2], (const4 << pos));
}
@@ -6989,6 +6989,7 @@ static void decode_rrpw_extract_insert(DisasContext *ctx)
uint32_t op2;
int r1, r2, r3;
int32_t pos, width;
+ TCGv temp;
op2 = MASK_OP_RRPW_OP2(ctx->opcode);
r1 = MASK_OP_RRPW_S1(ctx->opcode);
@@ -6999,7 +7000,12 @@ static void decode_rrpw_extract_insert(DisasContext *ctx)
switch (op2) {
case OPC2_32_RRPW_EXTR:
- if (pos + width <= 31) {
+ if (width == 0) {
+ tcg_gen_movi_tl(cpu_gpr_d[r3], 0);
+ break;
+ }
+
+ if (pos + width <= 32) {
/* optimize special cases */
if ((pos == 0) && (width == 8)) {
tcg_gen_ext8s_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]);
@@ -7021,10 +7027,15 @@ static void decode_rrpw_extract_insert(DisasContext *ctx)
break;
case OPC2_32_RRPW_IMASK:
CHECK_REG_PAIR(r3);
- if (pos + width <= 31) {
- tcg_gen_movi_tl(cpu_gpr_d[r3+1], ((1u << width) - 1) << pos);
+
+ if (pos + width <= 32) {
+ temp = tcg_temp_new();
+ tcg_gen_movi_tl(temp, ((1u << width) - 1) << pos);
tcg_gen_shli_tl(cpu_gpr_d[r3], cpu_gpr_d[r2], pos);
+ tcg_gen_mov_tl(cpu_gpr_d[r3 + 1], temp);
+ tcg_temp_free(temp);
}
+
break;
case OPC2_32_RRPW_INSERT:
if (pos + width <= 32) {
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 2688e1bfad..66ee9fbf45 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -30,6 +30,9 @@ qtests_generic = [
if config_host.has_key('CONFIG_MODULES')
qtests_generic += [ 'modules-test' ]
endif
+if slirp.found()
+ qtests_generic += [ 'test-query-netdev' ]
+endif
qtests_pci = \
(config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) + \
diff --git a/tests/qtest/test-query-netdev.c b/tests/qtest/test-query-netdev.c
new file mode 100644
index 0000000000..1118537a9f
--- /dev/null
+++ b/tests/qtest/test-query-netdev.c
@@ -0,0 +1,120 @@
+/*
+ * QTest testcase for the query-netdev
+ *
+ * Copyright Yandex N.V., 2019
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqos/libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+GCC_FMT_ATTR(2, 3)
+static QObject *wait_command(QTestState *who, const char *command, ...)
+{
+ va_list ap;
+ QDict *response;
+ QObject *result;
+
+ va_start(ap, command);
+ qtest_qmp_vsend(who, command, ap);
+ va_end(ap);
+
+ response = qtest_qmp_receive(who);
+
+ result = qdict_get(response, "return");
+ g_assert(result);
+ qobject_ref(result);
+ qobject_unref(response);
+
+ return result;
+}
+
+static void qmp_query_netdev_no_error(QTestState *qts, size_t netdevs_count)
+{
+ QObject *resp;
+ QList *netdevs;
+
+ resp = wait_command(qts, "{'execute': 'query-netdev'}");
+
+ netdevs = qobject_to(QList, resp);
+ g_assert(netdevs);
+ g_assert(qlist_size(netdevs) == netdevs_count);
+
+ qobject_unref(resp);
+}
+
+static void test_query_netdev(void)
+{
+ const char *arch = qtest_get_arch();
+ QObject *resp;
+ QTestState *state;
+
+ /* Choosing machine for platforms without default one */
+ if (g_str_equal(arch, "arm") ||
+ g_str_equal(arch, "aarch64")) {
+ state = qtest_init(
+ "-nodefaults "
+ "-M virt "
+ "-netdev user,id=slirp0");
+ } else if (g_str_equal(arch, "tricore")) {
+ state = qtest_init(
+ "-nodefaults "
+ "-M tricore_testboard "
+ "-netdev user,id=slirp0");
+ } else if (g_str_equal(arch, "avr")) {
+ state = qtest_init(
+ "-nodefaults "
+ "-M mega2560 "
+ "-netdev user,id=slirp0");
+ } else if (g_str_equal(arch, "rx")) {
+ state = qtest_init(
+ "-nodefaults "
+ "-M gdbsim-r5f562n8 "
+ "-netdev user,id=slirp0");
+ } else {
+ state = qtest_init(
+ "-nodefaults "
+ "-netdev user,id=slirp0");
+ }
+ g_assert(state);
+
+ qmp_query_netdev_no_error(state, 1);
+
+ resp = wait_command(state,
+ "{'execute': 'netdev_add', 'arguments': {"
+ " 'id': 'slirp1',"
+ " 'type': 'user'}}");
+ qobject_unref(resp);
+
+ qmp_query_netdev_no_error(state, 2);
+
+ resp = wait_command(state,
+ "{'execute': 'netdev_del', 'arguments': {"
+ " 'id': 'slirp1'}}");
+ qobject_unref(resp);
+
+ qmp_query_netdev_no_error(state, 1);
+
+ qtest_quit(state);
+}
+
+int main(int argc, char **argv)
+{
+ int ret = 0;
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/net/qapi/query_netdev", test_query_netdev);
+
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c
index bad3a60993..e025b54c05 100644
--- a/tests/unit/test-cutils.c
+++ b/tests/unit/test-cutils.c
@@ -2128,7 +2128,7 @@ static void test_qemu_strtosz_float(void)
str = "12.345M";
err = qemu_strtosz(str, &endptr, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, (uint64_t) (12.345 * MiB));
+ g_assert_cmpint(res, ==, (uint64_t) (12.345 * MiB + 0.5));
g_assert(endptr == str + 7);
}
diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
index 523ee64fb7..3e13997406 100644
--- a/tools/virtiofsd/fuse_virtio.c
+++ b/tools/virtiofsd/fuse_virtio.c
@@ -792,7 +792,13 @@ static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
assert(0);
}
} else {
+ /*
+ * Temporarily drop write-lock taken in virtio_loop() so that
+ * the queue thread doesn't block in virtio_send_msg().
+ */
+ vu_dispatch_unlock(vud);
fv_queue_cleanup_thread(vud, qidx);
+ vu_dispatch_wrlock(vud);
}
}
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index fc7e1b1e8e..b144320e48 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -37,6 +37,8 @@
#include "qemu/osdep.h"
#include "qemu/timer.h"
+#include "qemu-version.h"
+#include "qemu-common.h"
#include "fuse_virtio.h"
#include "fuse_log.h"
#include "fuse_lowlevel.h"
@@ -221,22 +223,27 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st,
static int xattr_map_client(const struct lo_data *lo, const char *client_name,
char **out_name);
-static int is_dot_or_dotdot(const char *name)
+static bool is_dot_or_dotdot(const char *name)
{
return name[0] == '.' &&
(name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
}
/* Is `path` a single path component that is not "." or ".."? */
-static int is_safe_path_component(const char *path)
+static bool is_safe_path_component(const char *path)
{
if (strchr(path, '/')) {
- return 0;
+ return false;
}
return !is_dot_or_dotdot(path);
}
+static bool is_empty(const char *name)
+{
+ return name[0] == '\0';
+}
+
static struct lo_data *lo_data(fuse_req_t req)
{
return (struct lo_data *)fuse_req_userdata(req);
@@ -1083,6 +1090,11 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n", parent,
name);
+ if (is_empty(name)) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
/*
* Don't use is_safe_path_component(), allow "." and ".." for NFS export
* support.
@@ -1174,6 +1186,11 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
struct fuse_entry_param e;
struct lo_cred old = {};
+ if (is_empty(name)) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
if (!is_safe_path_component(name)) {
fuse_reply_err(req, EINVAL);
return;
@@ -1246,6 +1263,11 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
char procname[64];
int saverr;
+ if (is_empty(name)) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
if (!is_safe_path_component(name)) {
fuse_reply_err(req, EINVAL);
return;
@@ -1308,8 +1330,7 @@ static struct lo_inode *lookup_name(fuse_req_t req, fuse_ino_t parent,
return NULL;
}
- res = do_statx(lo, dir->fd, name, &attr,
- AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, &mnt_id);
+ res = do_statx(lo, dir->fd, name, &attr, AT_SYMLINK_NOFOLLOW, &mnt_id);
lo_inode_put(lo, &dir);
if (res == -1) {
return NULL;
@@ -1324,6 +1345,11 @@ static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
struct lo_inode *inode;
struct lo_data *lo = lo_data(req);
+ if (is_empty(name)) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
if (!is_safe_path_component(name)) {
fuse_reply_err(req, EINVAL);
return;
@@ -1353,6 +1379,11 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
struct lo_inode *newinode = NULL;
struct lo_data *lo = lo_data(req);
+ if (is_empty(name) || is_empty(newname)) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
if (!is_safe_path_component(name) || !is_safe_path_component(newname)) {
fuse_reply_err(req, EINVAL);
return;
@@ -1406,6 +1437,11 @@ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
struct lo_inode *inode;
struct lo_data *lo = lo_data(req);
+ if (is_empty(name)) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
if (!is_safe_path_component(name)) {
fuse_reply_err(req, EINVAL);
return;
@@ -3666,6 +3702,11 @@ static void fuse_lo_data_cleanup(struct lo_data *lo)
free(lo->source);
}
+static void qemu_version(void)
+{
+ printf("virtiofsd version " QEMU_FULL_VERSION "\n" QEMU_COPYRIGHT "\n");
+}
+
int main(int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
@@ -3737,6 +3778,7 @@ int main(int argc, char *argv[])
ret = 0;
goto err_out1;
} else if (opts.show_version) {
+ qemu_version();
fuse_lowlevel_version();
ret = 0;
goto err_out1;
diff --git a/util/cutils.c b/util/cutils.c
index d89a40a8c3..c442882b88 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -275,10 +275,9 @@ static int do_strtosz(const char *nptr, const char **end,
int retval;
const char *endptr, *f;
unsigned char c;
- bool mul_required = false, hex = false;
- uint64_t val;
+ bool hex = false;
+ uint64_t val, valf = 0;
int64_t mul;
- double fraction = 0.0;
/* Parse integral portion as decimal. */
retval = qemu_strtou64(nptr, &endptr, 10, &val);
@@ -308,17 +307,19 @@ static int do_strtosz(const char *nptr, const char **end,
* without fractional digits. If we see an exponent, treat
* the entire input as invalid instead.
*/
+ double fraction;
+
f = endptr;
retval = qemu_strtod_finite(f, &endptr, &fraction);
if (retval) {
- fraction = 0.0;
endptr++;
} else if (memchr(f, 'e', endptr - f) || memchr(f, 'E', endptr - f)) {
endptr = nptr;
retval = -EINVAL;
goto out;
- } else if (fraction != 0) {
- mul_required = true;
+ } else {
+ /* Extract into a 64-bit fixed-point fraction. */
+ valf = (uint64_t)(fraction * 0x1p64);
}
}
c = *endptr;
@@ -333,16 +334,35 @@ static int do_strtosz(const char *nptr, const char **end,
mul = suffix_mul(default_suffix, unit);
assert(mul > 0);
}
- if (mul == 1 && mul_required) {
- endptr = nptr;
- retval = -EINVAL;
- goto out;
- }
- if (val > (UINT64_MAX - ((uint64_t) (fraction * mul))) / mul) {
- retval = -ERANGE;
- goto out;
+ if (mul == 1) {
+ /* When a fraction is present, a scale is required. */
+ if (valf != 0) {
+ endptr = nptr;
+ retval = -EINVAL;
+ goto out;
+ }
+ } else {
+ uint64_t valh, tmp;
+
+ /* Compute exact result: 64.64 x 64.0 -> 128.64 fixed point */
+ mulu64(&val, &valh, val, mul);
+ mulu64(&valf, &tmp, valf, mul);
+ val += tmp;
+ valh += val < tmp;
+
+ /* Round 0.5 upward. */
+ tmp = valf >> 63;
+ val += tmp;
+ valh += val < tmp;
+
+ /* Report overflow. */
+ if (valh != 0) {
+ retval = -ERANGE;
+ goto out;
+ }
}
- *result = val * mul + (uint64_t) (fraction * mul);
+
+ *result = val;
retval = 0;
out: