aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-05-10 17:28:11 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-05-10 17:28:11 +0100
commite58c7a3bba3076890592f02d2b0e596bf191b5c2 (patch)
tree232ed3fefa6cbd2b61f392bb495fb3626e8acc8b
parent74e31681ba05ed1876818df30c581bc530554fb3 (diff)
parentc3080fbdaa381012666428fef2e5f7ce422ecfee (diff)
downloadqemu-e58c7a3bba3076890592f02d2b0e596bf191b5c2.zip
qemu-e58c7a3bba3076890592f02d2b0e596bf191b5c2.tar.gz
qemu-e58c7a3bba3076890592f02d2b0e596bf191b5c2.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210510-1' into staging
target-arm queue: * docs: fix link in sbsa description * linux-user/aarch64: Enable hwcap for RND, BTI, and MTE * target/arm: Fix tlbbits calculation in tlbi_aa64_vae2is_write() * target/arm: Split neon and vfp translation to their own compilation units * target/arm: Make WFI a NOP for userspace emulators * hw/sd/omap_mmc: Use device_cold_reset() instead of device_legacy_reset() * include: More fixes for 'extern "C"' block use * hw/arm/imx25_pdk: Fix error message for invalid RAM size * hw/arm/mps2-tz: Implement AN524 memory remapping via machine property * hw/arm/xlnx: Fix PHY address for xilinx-zynq-a9 # gpg: Signature made Mon 10 May 2021 17:26:55 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210510-1: (26 commits) hw/arm/xlnx: Fix PHY address for xilinx-zynq-a9 hw/arm/mps2-tz: Implement AN524 memory remapping via machine property hw/misc/mps2-scc: Support using CFG0 bit 0 for remapping hw/misc/mps2-scc: Add "QEMU interface" comment hw/arm/imx25_pdk: Fix error message for invalid RAM size include/disas/dis-asm.h: Handle being included outside 'extern "C"' include/qemu/bswap.h: Handle being included outside extern "C" block osdep: Make os-win32.h and os-posix.h handle 'extern "C"' themselves hw/sd/omap_mmc: Use device_cold_reset() instead of device_legacy_reset() target/arm: Make WFI a NOP for userspace emulators target/arm: Make translate-neon.c.inc its own compilation unit target/arm: Make functions used by translate-neon global target/arm: Move NeonGenThreeOpEnvFn typedef to translate.h target/arm: Delete unused typedef target/arm: Move vfp_reg_ptr() to translate-neon.c.inc target/arm: Make translate-vfp.c.inc its own compilation unit target/arm: Make functions used by translate-vfp global target/arm: Move vfp_{load, store}_reg{32, 64} to translate-vfp.c.inc target/arm: Move gen_aa32 functions to translate-a32.h target/arm: Split m-nocp trans functions into their own file ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--disas/arm-a64.cc2
-rw-r--r--disas/nanomips.cpp2
-rw-r--r--docs/system/arm/mps2.rst10
-rw-r--r--docs/system/arm/sbsa.rst2
-rw-r--r--hw/arm/imx25_pdk.c5
-rw-r--r--hw/arm/mps2-tz.c108
-rw-r--r--hw/arm/xilinx_zynq.c2
-rw-r--r--hw/misc/mps2-scc.c13
-rw-r--r--hw/sd/omap_mmc.c2
-rw-r--r--include/disas/dis-asm.h12
-rw-r--r--include/hw/misc/mps2-scc.h21
-rw-r--r--include/qemu/bswap.h26
-rw-r--r--include/qemu/osdep.h8
-rw-r--r--include/sysemu/os-posix.h8
-rw-r--r--include/sysemu/os-win32.h8
-rw-r--r--linux-user/elfload.c13
-rw-r--r--target/arm/helper.c2
-rw-r--r--target/arm/meson.build15
-rw-r--r--target/arm/op_helper.c14
-rw-r--r--target/arm/translate-a32.h144
-rw-r--r--target/arm/translate-a64.c15
-rw-r--r--target/arm/translate-a64.h2
-rw-r--r--target/arm/translate-m-nocp.c221
-rw-r--r--target/arm/translate-neon.c (renamed from target/arm/translate-neon.c.inc)19
-rw-r--r--target/arm/translate-vfp.c (renamed from target/arm/translate-vfp.c.inc)230
-rw-r--r--target/arm/translate.c200
-rw-r--r--target/arm/translate.h29
27 files changed, 720 insertions, 413 deletions
diff --git a/disas/arm-a64.cc b/disas/arm-a64.cc
index 27613d4..a1402a2 100644
--- a/disas/arm-a64.cc
+++ b/disas/arm-a64.cc
@@ -18,9 +18,7 @@
*/
#include "qemu/osdep.h"
-extern "C" {
#include "disas/dis-asm.h"
-}
#include "vixl/a64/disasm-a64.h"
diff --git a/disas/nanomips.cpp b/disas/nanomips.cpp
index 8ddef89..9be8df7 100644
--- a/disas/nanomips.cpp
+++ b/disas/nanomips.cpp
@@ -28,9 +28,7 @@
*/
#include "qemu/osdep.h"
-extern "C" {
#include "disas/dis-asm.h"
-}
#include <cstring>
#include <stdexcept>
diff --git a/docs/system/arm/mps2.rst b/docs/system/arm/mps2.rst
index f83b151..8a75beb 100644
--- a/docs/system/arm/mps2.rst
+++ b/docs/system/arm/mps2.rst
@@ -45,3 +45,13 @@ Differences between QEMU and real hardware:
flash, but only as simple ROM, so attempting to rewrite the flash
from the guest will fail
- QEMU does not model the USB controller in MPS3 boards
+
+Machine-specific options
+""""""""""""""""""""""""
+
+The following machine-specific options are supported:
+
+remap
+ Supported for ``mps3-an524`` only.
+ Set ``BRAM``/``QSPI`` to select the initial memory mapping. The
+ default is ``BRAM``.
diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst
index b8ecfdb..27b0999 100644
--- a/docs/system/arm/sbsa.rst
+++ b/docs/system/arm/sbsa.rst
@@ -4,7 +4,7 @@ Arm Server Base System Architecture Reference board (``sbsa-ref``)
While the `virt` board is a generic board platform that doesn't match
any real hardware the `sbsa-ref` board intends to look like real
hardware. The `Server Base System Architecture
-<https://developer.arm.com/documentation/den0029/latest>` defines a
+<https://developer.arm.com/documentation/den0029/latest>`_ defines a
minimum base line of hardware support and importantly how the firmware
reports that to any operating system. It is a static system that
reports a very minimal DT to the firmware for non-discoverable
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
index 11426e5..bd16acd 100644
--- a/hw/arm/imx25_pdk.c
+++ b/hw/arm/imx25_pdk.c
@@ -65,7 +65,6 @@ static struct arm_boot_info imx25_pdk_binfo;
static void imx25_pdk_init(MachineState *machine)
{
- MachineClass *mc = MACHINE_GET_CLASS(machine);
IMX25PDK *s = g_new0(IMX25PDK, 1);
unsigned int ram_size;
unsigned int alias_offset;
@@ -77,8 +76,8 @@ static void imx25_pdk_init(MachineState *machine)
/* We need to initialize our memory */
if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
- char *sz = size_to_str(mc->default_ram_size);
- error_report("Invalid RAM size, should be %s", sz);
+ char *sz = size_to_str(FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
+ error_report("RAM size more than %s is not supported", sz);
g_free(sz);
exit(EXIT_FAILURE);
}
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 25016e4..70aa31a 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -55,6 +55,7 @@
#include "hw/boards.h"
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
+#include "sysemu/reset.h"
#include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h"
#include "hw/timer/cmsdk-apb-timer.h"
@@ -72,6 +73,7 @@
#include "hw/core/split-irq.h"
#include "hw/qdev-clock.h"
#include "qom/object.h"
+#include "hw/irq.h"
#define MPS2TZ_NUMIRQ_MAX 96
#define MPS2TZ_RAM_MAX 5
@@ -153,6 +155,9 @@ struct MPS2TZMachineState {
SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX];
Clock *sysclk;
Clock *s32kclk;
+
+ bool remap;
+ qemu_irq remap_irq;
};
#define TYPE_MPS2TZ_MACHINE "mps2tz"
@@ -228,6 +233,10 @@ static const RAMInfo an505_raminfo[] = { {
},
};
+/*
+ * Note that the addresses and MPC numbering here should match up
+ * with those used in remap_memory(), which can swap the BRAM and QSPI.
+ */
static const RAMInfo an524_raminfo[] = { {
.name = "bram",
.base = 0x00000000,
@@ -457,6 +466,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC);
sccdev = DEVICE(scc);
+ qdev_prop_set_uint32(sccdev, "scc-cfg0", mms->remap ? 1 : 0);
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
@@ -573,6 +583,52 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
}
+static hwaddr boot_mem_base(MPS2TZMachineState *mms)
+{
+ /*
+ * Return the canonical address of the block which will be mapped
+ * at address 0x0 (i.e. where the vector table is).
+ * This is usually 0, but if the AN524 alternate memory map is
+ * enabled it will be the base address of the QSPI block.
+ */
+ return mms->remap ? 0x28000000 : 0;
+}
+
+static void remap_memory(MPS2TZMachineState *mms, int map)
+{
+ /*
+ * Remap the memory for the AN524. 'map' is the value of
+ * SCC CFG_REG0 bit 0, i.e. 0 for the default map and 1
+ * for the "option 1" mapping where QSPI is at address 0.
+ *
+ * Effectively we need to swap around the "upstream" ends of
+ * MPC 0 and MPC 1.
+ */
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+ int i;
+
+ if (mmc->fpga_type != FPGA_AN524) {
+ return;
+ }
+
+ memory_region_transaction_begin();
+ for (i = 0; i < 2; i++) {
+ TZMPC *mpc = &mms->mpc[i];
+ MemoryRegion *upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
+ hwaddr addr = (i ^ map) ? 0x28000000 : 0;
+
+ memory_region_set_address(upstream, addr);
+ }
+ memory_region_transaction_commit();
+}
+
+static void remap_irq_fn(void *opaque, int n, int level)
+{
+ MPS2TZMachineState *mms = opaque;
+
+ remap_memory(mms, level);
+}
+
static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
const char *name, hwaddr size,
const int *irqs)
@@ -711,7 +767,7 @@ static uint32_t boot_ram_size(MPS2TZMachineState *mms)
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
for (p = mmc->raminfo; p->name; p++) {
- if (p->base == 0) {
+ if (p->base == boot_mem_base(mms)) {
return p->size;
}
}
@@ -1095,6 +1151,16 @@ static void mps2tz_common_init(MachineState *machine)
create_non_mpc_ram(mms);
+ if (mmc->fpga_type == FPGA_AN524) {
+ /*
+ * Connect the line from the SCC so that we can remap when the
+ * guest updates that register.
+ */
+ mms->remap_irq = qemu_allocate_irq(remap_irq_fn, mms, 0);
+ qdev_connect_gpio_out_named(DEVICE(&mms->scc), "remap", 0,
+ mms->remap_irq);
+ }
+
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
boot_ram_size(mms));
}
@@ -1117,12 +1183,47 @@ static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
*iregion = region;
}
+static char *mps2_get_remap(Object *obj, Error **errp)
+{
+ MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj);
+ const char *val = mms->remap ? "QSPI" : "BRAM";
+ return g_strdup(val);
+}
+
+static void mps2_set_remap(Object *obj, const char *value, Error **errp)
+{
+ MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj);
+
+ if (!strcmp(value, "BRAM")) {
+ mms->remap = false;
+ } else if (!strcmp(value, "QSPI")) {
+ mms->remap = true;
+ } else {
+ error_setg(errp, "Invalid remap value");
+ error_append_hint(errp, "Valid values are BRAM and QSPI.\n");
+ }
+}
+
+static void mps2_machine_reset(MachineState *machine)
+{
+ MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
+
+ /*
+ * Set the initial memory mapping before triggering the reset of
+ * the rest of the system, so that the guest image loader and CPU
+ * reset see the correct mapping.
+ */
+ remap_memory(mms, mms->remap);
+ qemu_devices_reset();
+}
+
static void mps2tz_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
mc->init = mps2tz_common_init;
+ mc->reset = mps2_machine_reset;
iic->check = mps2_tz_idau_check;
}
@@ -1225,6 +1326,11 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data)
mmc->raminfo = an524_raminfo;
mmc->armsse_type = TYPE_SSE200;
mps2tz_set_default_ram_info(mmc);
+
+ object_class_property_add_str(oc, "remap", mps2_get_remap, mps2_set_remap);
+ object_class_property_set_description(oc, "remap",
+ "Set memory mapping. Valid values "
+ "are BRAM (default) and QSPI.");
}
static void mps3tz_an547_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 85f25d1..81af32d 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -118,7 +118,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(dev, nd);
}
- object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
+ object_property_set_int(OBJECT(dev), "phy-addr", 7, &error_abort);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, base);
diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c
index c56aca8..b3b42a7 100644
--- a/hw/misc/mps2-scc.c
+++ b/hw/misc/mps2-scc.c
@@ -23,6 +23,7 @@
#include "qemu/bitops.h"
#include "trace.h"
#include "hw/sysbus.h"
+#include "hw/irq.h"
#include "migration/vmstate.h"
#include "hw/registerfields.h"
#include "hw/misc/mps2-scc.h"
@@ -186,10 +187,13 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset) {
case A_CFG0:
/*
- * TODO on some boards bit 0 controls RAM remapping;
- * on others bit 1 is CPU_WAIT.
+ * On some boards bit 0 controls board-specific remapping;
+ * we always reflect bit 0 in the 'remap' GPIO output line,
+ * and let the board wire it up or not as it chooses.
+ * TODO on some boards bit 1 is CPU_WAIT.
*/
s->cfg0 = value;
+ qemu_set_irq(s->remap, s->cfg0 & 1);
break;
case A_CFG1:
s->cfg1 = value;
@@ -283,7 +287,7 @@ static void mps2_scc_reset(DeviceState *dev)
int i;
trace_mps2_scc_reset();
- s->cfg0 = 0;
+ s->cfg0 = s->cfg0_reset;
s->cfg1 = 0;
s->cfg2 = 0;
s->cfg5 = 0;
@@ -308,6 +312,7 @@ static void mps2_scc_init(Object *obj)
memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
+ qdev_init_gpio_out_named(DEVICE(obj), &s->remap, "remap", 1);
}
static void mps2_scc_realize(DeviceState *dev, Error **errp)
@@ -353,6 +358,8 @@ static Property mps2_scc_properties[] = {
DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
+ /* Reset value for CFG0 register */
+ DEFINE_PROP_UINT32("scc-cfg0", MPS2SCC, cfg0_reset, 0),
/*
* These are the initial settings for the source clocks on the board.
* In hardware they can be configured via a config file read by the
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
index 1f94690..b67def6 100644
--- a/hw/sd/omap_mmc.c
+++ b/hw/sd/omap_mmc.c
@@ -318,7 +318,7 @@ void omap_mmc_reset(struct omap_mmc_s *host)
* into any bus, and we must reset it manually. When omap_mmc is
* QOMified this must move into the QOM reset function.
*/
- device_legacy_reset(DEVICE(host->card));
+ device_cold_reset(DEVICE(host->card));
}
static uint64_t omap_mmc_read(void *opaque, hwaddr offset,
diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h
index 13fa1ed..4701445 100644
--- a/include/disas/dis-asm.h
+++ b/include/disas/dis-asm.h
@@ -9,6 +9,12 @@
#ifndef DISAS_DIS_ASM_H
#define DISAS_DIS_ASM_H
+#include "qemu/bswap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_vma;
@@ -479,8 +485,6 @@ bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size);
/* from libbfd */
-#include "qemu/bswap.h"
-
static inline bfd_vma bfd_getl64(const bfd_byte *addr)
{
return ldq_le_p(addr);
@@ -508,4 +512,8 @@ static inline bfd_vma bfd_getb16(const bfd_byte *addr)
typedef bool bfd_boolean;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* DISAS_DIS_ASM_H */
diff --git a/include/hw/misc/mps2-scc.h b/include/hw/misc/mps2-scc.h
index 49d0706..3b2d13a 100644
--- a/include/hw/misc/mps2-scc.h
+++ b/include/hw/misc/mps2-scc.h
@@ -9,6 +9,24 @@
* (at your option) any later version.
*/
+/*
+ * This is a model of the Serial Communication Controller (SCC)
+ * block found in most MPS FPGA images.
+ *
+ * QEMU interface:
+ * + sysbus MMIO region 0: the register bank
+ * + QOM property "scc-cfg4": value of the read-only CFG4 register
+ * + QOM property "scc-aid": value of the read-only SCC_AID register
+ * + QOM property "scc-id": value of the read-only SCC_ID register
+ * + QOM property "scc-cfg0": reset value of the CFG0 register
+ * + QOM property array "oscclk": reset values of the OSCCLK registers
+ * (which are accessed via the SYS_CFG channel provided by this device)
+ * + named GPIO output "remap": this tracks the value of CFG0 register
+ * bit 0. Boards where this bit controls memory remapping should
+ * connect this GPIO line to a function performing that mapping.
+ * Boards where bit 0 has no special function should leave the GPIO
+ * output disconnected.
+ */
#ifndef MPS2_SCC_H
#define MPS2_SCC_H
@@ -43,6 +61,9 @@ struct MPS2SCC {
uint32_t num_oscclk;
uint32_t *oscclk;
uint32_t *oscclk_reset;
+ uint32_t cfg0_reset;
+
+ qemu_irq remap;
};
#endif
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index 4aaf992..2d3bb8b 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -1,8 +1,6 @@
#ifndef BSWAP_H
#define BSWAP_H
-#include "fpu/softfloat-types.h"
-
#ifdef CONFIG_MACHINE_BSWAP_H
# include <sys/endian.h>
# include <machine/bswap.h>
@@ -12,7 +10,18 @@
# include <endian.h>
#elif defined(CONFIG_BYTESWAP_H)
# include <byteswap.h>
+#define BSWAP_FROM_BYTESWAP
+# else
+#define BSWAP_FROM_FALLBACKS
+#endif /* ! CONFIG_MACHINE_BSWAP_H */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "fpu/softfloat-types.h"
+
+#ifdef BSWAP_FROM_BYTESWAP
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
@@ -27,7 +36,9 @@ static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
-# else
+#endif
+
+#ifdef BSWAP_FROM_FALLBACKS
static inline uint16_t bswap16(uint16_t x)
{
return (((x & 0x00ff) << 8) |
@@ -53,7 +64,10 @@ static inline uint64_t bswap64(uint64_t x)
((x & 0x00ff000000000000ULL) >> 40) |
((x & 0xff00000000000000ULL) >> 56));
}
-#endif /* ! CONFIG_MACHINE_BSWAP_H */
+#endif
+
+#undef BSWAP_FROM_BYTESWAP
+#undef BSWAP_FROM_FALLBACKS
static inline void bswap16s(uint16_t *s)
{
@@ -494,4 +508,8 @@ DO_STN_LDN_P(be)
#undef le_bswaps
#undef be_bswaps
+#ifdef __cplusplus
+}
+#endif
+
#endif /* BSWAP_H */
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index cb2a07e..4c6f239 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -131,10 +131,6 @@ QEMU_EXTERN_C int daemon(int, int);
*/
#include "glib-compat.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifdef _WIN32
#include "sysemu/os-win32.h"
#endif
@@ -143,6 +139,10 @@ extern "C" {
#include "sysemu/os-posix.h"
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "qemu/typedefs.h"
/*
diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
index 629c8c6..2edf336 100644
--- a/include/sysemu/os-posix.h
+++ b/include/sysemu/os-posix.h
@@ -38,6 +38,10 @@
#include <sys/sysmacros.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void os_set_line_buffering(void);
void os_set_proc_name(const char *s);
void os_setup_signal_handling(void);
@@ -92,4 +96,8 @@ static inline void qemu_funlockfile(FILE *f)
funlockfile(f);
}
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 5346d51..43f569b 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -30,6 +30,10 @@
#include <windows.h>
#include <ws2tcpip.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if defined(_WIN64)
/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
* If this parameter is NULL, longjump does no stack unwinding.
@@ -194,4 +198,8 @@ ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags);
ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *addr, socklen_t *addrlen);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c673101..fc9c4f1 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -586,6 +586,16 @@ enum {
ARM_HWCAP2_A64_SVESM4 = 1 << 6,
ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
ARM_HWCAP2_A64_FRINT = 1 << 8,
+ ARM_HWCAP2_A64_SVEI8MM = 1 << 9,
+ ARM_HWCAP2_A64_SVEF32MM = 1 << 10,
+ ARM_HWCAP2_A64_SVEF64MM = 1 << 11,
+ ARM_HWCAP2_A64_SVEBF16 = 1 << 12,
+ ARM_HWCAP2_A64_I8MM = 1 << 13,
+ ARM_HWCAP2_A64_BF16 = 1 << 14,
+ ARM_HWCAP2_A64_DGH = 1 << 15,
+ ARM_HWCAP2_A64_RNG = 1 << 16,
+ ARM_HWCAP2_A64_BTI = 1 << 17,
+ ARM_HWCAP2_A64_MTE = 1 << 18,
};
#define ELF_HWCAP get_elf_hwcap()
@@ -640,6 +650,9 @@ static uint32_t get_elf_hwcap2(void)
GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
+ GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
+ GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
+ GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
return hwcaps;
}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 9b1b987..3b365a7 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4742,7 +4742,7 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t pageaddr = sextract64(value << 12, 0, 56);
bool secure = arm_is_secure_below_el3(env);
int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2;
- int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2,
+ int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2,
pageaddr);
tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 15b936c..5bfaf43 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -1,11 +1,11 @@
gen = [
decodetree.process('sve.decode', extra_args: '--decode=disas_sve'),
- decodetree.process('neon-shared.decode', extra_args: '--static-decode=disas_neon_shared'),
- decodetree.process('neon-dp.decode', extra_args: '--static-decode=disas_neon_dp'),
- decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'),
- decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'),
- decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'),
- decodetree.process('m-nocp.decode', extra_args: '--static-decode=disas_m_nocp'),
+ decodetree.process('neon-shared.decode', extra_args: '--decode=disas_neon_shared'),
+ decodetree.process('neon-dp.decode', extra_args: '--decode=disas_neon_dp'),
+ decodetree.process('neon-ls.decode', extra_args: '--decode=disas_neon_ls'),
+ decodetree.process('vfp.decode', extra_args: '--decode=disas_vfp'),
+ decodetree.process('vfp-uncond.decode', extra_args: '--decode=disas_vfp_uncond'),
+ decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'),
decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'),
decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'),
decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'),
@@ -26,6 +26,9 @@ arm_ss.add(files(
'op_helper.c',
'tlb_helper.c',
'translate.c',
+ 'translate-m-nocp.c',
+ 'translate-neon.c',
+ 'translate-vfp.c',
'vec_helper.c',
'vfp_helper.c',
'cpu_tcg.c',
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 78b831f..efcb600 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -228,6 +228,7 @@ void HELPER(setend)(CPUARMState *env)
arm_rebuild_hflags(env);
}
+#ifndef CONFIG_USER_ONLY
/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
* The function returns the target EL (1-3) if the instruction is to be trapped;
* otherwise it returns 0 indicating it is not trapped.
@@ -282,9 +283,21 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
return 0;
}
+#endif
void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
{
+#ifdef CONFIG_USER_ONLY
+ /*
+ * WFI in the user-mode emulator is technically permitted but not
+ * something any real-world code would do. AArch64 Linux kernels
+ * trap it via SCTRL_EL1.nTWI and make it an (expensive) NOP;
+ * AArch32 kernels don't trap it so it will delay a bit.
+ * For QEMU, make it NOP here, because trying to raise EXCP_HLT
+ * would trigger an abort.
+ */
+ return;
+#else
CPUState *cs = env_cpu(env);
int target_el = check_wfx_trap(env, false);
@@ -309,6 +322,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
cs->exception_index = EXCP_HLT;
cs->halted = 1;
cpu_loop_exit(cs);
+#endif
}
void HELPER(wfe)(CPUARMState *env)
diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h
new file mode 100644
index 0000000..c997f4e
--- /dev/null
+++ b/target/arm/translate-a32.h
@@ -0,0 +1,144 @@
+/*
+ * AArch32 translation, common definitions.
+ *
+ * Copyright (c) 2021 Linaro, Ltd.
+ *
+ * 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.1 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 TARGET_ARM_TRANSLATE_A64_H
+#define TARGET_ARM_TRANSLATE_A64_H
+
+/* Prototypes for autogenerated disassembler functions */
+bool disas_m_nocp(DisasContext *dc, uint32_t insn);
+bool disas_vfp(DisasContext *s, uint32_t insn);
+bool disas_vfp_uncond(DisasContext *s, uint32_t insn);
+bool disas_neon_dp(DisasContext *s, uint32_t insn);
+bool disas_neon_ls(DisasContext *s, uint32_t insn);
+bool disas_neon_shared(DisasContext *s, uint32_t insn);
+
+void load_reg_var(DisasContext *s, TCGv_i32 var, int reg);
+void arm_gen_condlabel(DisasContext *s);
+bool vfp_access_check(DisasContext *s);
+void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop);
+void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop);
+void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop);
+void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop);
+TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs);
+void gen_set_cpsr(TCGv_i32 var, uint32_t mask);
+void gen_set_condexec(DisasContext *s);
+void gen_set_pc_im(DisasContext *s, target_ulong val);
+void gen_lookup_tb(DisasContext *s);
+long vfp_reg_offset(bool dp, unsigned reg);
+long neon_full_reg_offset(unsigned reg);
+long neon_element_offset(int reg, int element, MemOp memop);
+void gen_rev16(TCGv_i32 dest, TCGv_i32 var);
+
+static inline TCGv_i32 load_cpu_offset(int offset)
+{
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ tcg_gen_ld_i32(tmp, cpu_env, offset);
+ return tmp;
+}
+
+#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
+
+static inline void store_cpu_offset(TCGv_i32 var, int offset)
+{
+ tcg_gen_st_i32(var, cpu_env, offset);
+ tcg_temp_free_i32(var);
+}
+
+#define store_cpu_field(var, name) \
+ store_cpu_offset(var, offsetof(CPUARMState, name))
+
+/* Create a new temporary and set it to the value of a CPU register. */
+static inline TCGv_i32 load_reg(DisasContext *s, int reg)
+{
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ load_reg_var(s, tmp, reg);
+ return tmp;
+}
+
+void store_reg(DisasContext *s, int reg, TCGv_i32 var);
+
+void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
+ TCGv_i32 a32, int index, MemOp opc);
+void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
+ TCGv_i32 a32, int index, MemOp opc);
+void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
+ TCGv_i32 a32, int index, MemOp opc);
+void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
+ TCGv_i32 a32, int index, MemOp opc);
+void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
+ int index, MemOp opc);
+void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
+ int index, MemOp opc);
+void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
+ int index, MemOp opc);
+void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
+ int index, MemOp opc);
+
+#define DO_GEN_LD(SUFF, OPC) \
+ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
+ TCGv_i32 a32, int index) \
+ { \
+ gen_aa32_ld_i32(s, val, a32, index, OPC); \
+ }
+
+#define DO_GEN_ST(SUFF, OPC) \
+ static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
+ TCGv_i32 a32, int index) \
+ { \
+ gen_aa32_st_i32(s, val, a32, index, OPC); \
+ }
+
+static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
+ TCGv_i32 a32, int index)
+{
+ gen_aa32_ld_i64(s, val, a32, index, MO_Q);
+}
+
+static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
+ TCGv_i32 a32, int index)
+{
+ gen_aa32_st_i64(s, val, a32, index, MO_Q);
+}
+
+DO_GEN_LD(8u, MO_UB)
+DO_GEN_LD(16u, MO_UW)
+DO_GEN_LD(32u, MO_UL)
+DO_GEN_ST(8, MO_UB)
+DO_GEN_ST(16, MO_UW)
+DO_GEN_ST(32, MO_UL)
+
+#undef DO_GEN_LD
+#undef DO_GEN_ST
+
+#if defined(CONFIG_USER_ONLY)
+#define IS_USER(s) 1
+#else
+#define IS_USER(s) (s->user)
+#endif
+
+/* Set NZCV flags from the high 4 bits of var. */
+#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
+
+/* Swap low and high halfwords. */
+static inline void gen_swap_half(TCGv_i32 dest, TCGv_i32 var)
+{
+ tcg_gen_rotri_i32(dest, var, 16);
+}
+
+#endif
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 95897e6..0c80d0b 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -359,14 +359,6 @@ static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
s->base.is_jmp = DISAS_NORETURN;
}
-static void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
- uint32_t syndrome, uint32_t target_el)
-{
- gen_a64_set_pc_im(pc);
- gen_exception(excp, syndrome, target_el);
- s->base.is_jmp = DISAS_NORETURN;
-}
-
static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
{
TCGv_i32 tcg_syn;
@@ -437,13 +429,6 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
}
}
-void unallocated_encoding(DisasContext *s)
-{
- /* Unallocated and reserved encodings are uncategorized */
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
- default_exception_el(s));
-}
-
static void init_tmp_a64_array(DisasContext *s)
{
#ifdef CONFIG_DEBUG_TCG
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index 868d355..8943727 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -18,8 +18,6 @@
#ifndef TARGET_ARM_TRANSLATE_A64_H
#define TARGET_ARM_TRANSLATE_A64_H
-void unallocated_encoding(DisasContext *s);
-
#define unsupported_encoding(s, insn) \
do { \
qemu_log_mask(LOG_UNIMP, \
diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c
new file mode 100644
index 0000000..d47eb8e
--- /dev/null
+++ b/target/arm/translate-m-nocp.c
@@ -0,0 +1,221 @@
+/*
+ * ARM translation: M-profile NOCP special-case instructions
+ *
+ * Copyright (c) 2020 Linaro, Ltd.
+ *
+ * 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.1 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 "tcg/tcg-op.h"
+#include "translate.h"
+#include "translate-a32.h"
+
+#include "decode-m-nocp.c.inc"
+
+/*
+ * Decode VLLDM and VLSTM are nonstandard because:
+ * * if there is no FPU then these insns must NOP in
+ * Secure state and UNDEF in Nonsecure state
+ * * if there is an FPU then these insns do not have
+ * the usual behaviour that vfp_access_check() provides of
+ * being controlled by CPACR/NSACR enable bits or the
+ * lazy-stacking logic.
+ */
+static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
+{
+ TCGv_i32 fptr;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M) ||
+ !arm_dc_feature(s, ARM_FEATURE_V8)) {
+ return false;
+ }
+
+ if (a->op) {
+ /*
+ * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not
+ * to take the IMPDEF option to make memory accesses to the stack
+ * slots that correspond to the D16-D31 registers (discarding
+ * read data and writing UNKNOWN values), so for us the T2
+ * encoding behaves identically to the T1 encoding.
+ */
+ if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
+ return false;
+ }
+ } else {
+ /*
+ * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs.
+ * This is currently architecturally impossible, but we add the
+ * check to stay in line with the pseudocode. Note that we must
+ * emit code for the UNDEF so it takes precedence over the NOCP.
+ */
+ if (dc_isar_feature(aa32_simd_r32, s)) {
+ unallocated_encoding(s);
+ return true;
+ }
+ }
+
+ /*
+ * If not secure, UNDEF. We must emit code for this
+ * rather than returning false so that this takes
+ * precedence over the m-nocp.decode NOCP fallback.
+ */
+ if (!s->v8m_secure) {
+ unallocated_encoding(s);
+ return true;
+ }
+ /* If no fpu, NOP. */
+ if (!dc_isar_feature(aa32_vfp, s)) {
+ return true;
+ }
+
+ fptr = load_reg(s, a->rn);
+ if (a->l) {
+ gen_helper_v7m_vlldm(cpu_env, fptr);
+ } else {
+ gen_helper_v7m_vlstm(cpu_env, fptr);
+ }
+ tcg_temp_free_i32(fptr);
+
+ /* End the TB, because we have updated FP control bits */
+ s->base.is_jmp = DISAS_UPDATE_EXIT;
+ return true;
+}
+
+static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
+{
+ int btmreg, topreg;
+ TCGv_i64 zero;
+ TCGv_i32 aspen, sfpa;
+
+ if (!dc_isar_feature(aa32_m_sec_state, s)) {
+ /* Before v8.1M, fall through in decode to NOCP check */
+ return false;
+ }
+
+ /* Explicitly UNDEF because this takes precedence over NOCP */
+ if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ if (!dc_isar_feature(aa32_vfp_simd, s)) {
+ /* NOP if we have neither FP nor MVE */
+ return true;
+ }
+
+ /*
+ * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
+ * active floating point context so we must NOP (without doing
+ * any lazy state preservation or the NOCP check).
+ */
+ aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
+ sfpa = load_cpu_field(v7m.control[M_REG_S]);
+ tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
+ tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
+ tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
+ tcg_gen_or_i32(sfpa, sfpa, aspen);
+ arm_gen_condlabel(s);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
+
+ if (s->fp_excp_el != 0) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), s->fp_excp_el);
+ return true;
+ }
+
+ topreg = a->vd + a->imm - 1;
+ btmreg = a->vd;
+
+ /* Convert to Sreg numbers if the insn specified in Dregs */
+ if (a->size == 3) {
+ topreg = topreg * 2 + 1;
+ btmreg *= 2;
+ }
+
+ if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
+ /* UNPREDICTABLE: we choose to undef */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ /* Silently ignore requests to clear D16-D31 if they don't exist */
+ if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
+ topreg = 31;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /* Zero the Sregs from btmreg to topreg inclusive. */
+ zero = tcg_const_i64(0);
+ if (btmreg & 1) {
+ write_neon_element64(zero, btmreg >> 1, 1, MO_32);
+ btmreg++;
+ }
+ for (; btmreg + 1 <= topreg; btmreg += 2) {
+ write_neon_element64(zero, btmreg >> 1, 0, MO_64);
+ }
+ if (btmreg == topreg) {
+ write_neon_element64(zero, btmreg >> 1, 0, MO_32);
+ btmreg++;
+ }
+ assert(btmreg == topreg + 1);
+ /* TODO: when MVE is implemented, zero VPR here */
+ return true;
+}
+
+static bool trans_NOCP(DisasContext *s, arg_nocp *a)
+{
+ /*
+ * Handle M-profile early check for disabled coprocessor:
+ * all we need to do here is emit the NOCP exception if
+ * the coprocessor is disabled. Otherwise we return false
+ * and the real VFP/etc decode will handle the insn.
+ */
+ assert(arm_dc_feature(s, ARM_FEATURE_M));
+
+ if (a->cp == 11) {
+ a->cp = 10;
+ }
+ if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
+ (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
+ /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
+ a->cp = 10;
+ }
+
+ if (a->cp != 10) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), default_exception_el(s));
+ return true;
+ }
+
+ if (s->fp_excp_el != 0) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), s->fp_excp_el);
+ return true;
+ }
+
+ return false;
+}
+
+static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
+{
+ /* This range needs a coprocessor check for v8.1M and later only */
+ if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
+ return false;
+ }
+ return trans_NOCP(s, a);
+}
diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c
index a02b836..658bd27 100644
--- a/target/arm/translate-neon.c.inc
+++ b/target/arm/translate-neon.c
@@ -20,11 +20,13 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * This file is intended to be included from translate.c; it uses
- * some macros and definitions provided by that file.
- * It might be possible to convert it to a standalone .c file eventually.
- */
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
+#include "exec/exec-all.h"
+#include "exec/gen-icount.h"
+#include "translate.h"
+#include "translate-a32.h"
static inline int plus1(DisasContext *s, int x)
{
@@ -60,6 +62,13 @@ static inline int neon_3same_fp_size(DisasContext *s, int x)
#include "decode-neon-ls.c.inc"
#include "decode-neon-shared.c.inc"
+static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
+{
+ TCGv_ptr ret = tcg_temp_new_ptr();
+ tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg));
+ return ret;
+}
+
static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
{
long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c
index e20d9c7..3da84f3 100644
--- a/target/arm/translate-vfp.c.inc
+++ b/target/arm/translate-vfp.c
@@ -20,16 +20,38 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * This file is intended to be included from translate.c; it uses
- * some macros and definitions provided by that file.
- * It might be possible to convert it to a standalone .c file eventually.
- */
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
+#include "exec/exec-all.h"
+#include "exec/gen-icount.h"
+#include "translate.h"
+#include "translate-a32.h"
/* Include the generated VFP decoder */
#include "decode-vfp.c.inc"
#include "decode-vfp-uncond.c.inc"
+static inline void vfp_load_reg64(TCGv_i64 var, int reg)
+{
+ tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg));
+}
+
+static inline void vfp_store_reg64(TCGv_i64 var, int reg)
+{
+ tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg));
+}
+
+static inline void vfp_load_reg32(TCGv_i32 var, int reg)
+{
+ tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg));
+}
+
+static inline void vfp_store_reg32(TCGv_i32 var, int reg)
+{
+ tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg));
+}
+
/*
* The imm8 encodes the sign bit, enough bits to represent an exponent in
* the range 01....1xx to 10....0xx, and the most significant 4 bits of
@@ -191,7 +213,7 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
* The most usual kind of VFP access check, for everything except
* FMXR/FMRX to the always-available special registers.
*/
-static bool vfp_access_check(DisasContext *s)
+bool vfp_access_check(DisasContext *s)
{
return full_vfp_access_check(s, false);
}
@@ -3800,202 +3822,6 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
return true;
}
-/*
- * Decode VLLDM and VLSTM are nonstandard because:
- * * if there is no FPU then these insns must NOP in
- * Secure state and UNDEF in Nonsecure state
- * * if there is an FPU then these insns do not have
- * the usual behaviour that vfp_access_check() provides of
- * being controlled by CPACR/NSACR enable bits or the
- * lazy-stacking logic.
- */
-static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
-{
- TCGv_i32 fptr;
-
- if (!arm_dc_feature(s, ARM_FEATURE_M) ||
- !arm_dc_feature(s, ARM_FEATURE_V8)) {
- return false;
- }
-
- if (a->op) {
- /*
- * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not
- * to take the IMPDEF option to make memory accesses to the stack
- * slots that correspond to the D16-D31 registers (discarding
- * read data and writing UNKNOWN values), so for us the T2
- * encoding behaves identically to the T1 encoding.
- */
- if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
- return false;
- }
- } else {
- /*
- * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs.
- * This is currently architecturally impossible, but we add the
- * check to stay in line with the pseudocode. Note that we must
- * emit code for the UNDEF so it takes precedence over the NOCP.
- */
- if (dc_isar_feature(aa32_simd_r32, s)) {
- unallocated_encoding(s);
- return true;
- }
- }
-
- /*
- * If not secure, UNDEF. We must emit code for this
- * rather than returning false so that this takes
- * precedence over the m-nocp.decode NOCP fallback.
- */
- if (!s->v8m_secure) {
- unallocated_encoding(s);
- return true;
- }
- /* If no fpu, NOP. */
- if (!dc_isar_feature(aa32_vfp, s)) {
- return true;
- }
-
- fptr = load_reg(s, a->rn);
- if (a->l) {
- gen_helper_v7m_vlldm(cpu_env, fptr);
- } else {
- gen_helper_v7m_vlstm(cpu_env, fptr);
- }
- tcg_temp_free_i32(fptr);
-
- /* End the TB, because we have updated FP control bits */
- s->base.is_jmp = DISAS_UPDATE_EXIT;
- return true;
-}
-
-static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
-{
- int btmreg, topreg;
- TCGv_i64 zero;
- TCGv_i32 aspen, sfpa;
-
- if (!dc_isar_feature(aa32_m_sec_state, s)) {
- /* Before v8.1M, fall through in decode to NOCP check */
- return false;
- }
-
- /* Explicitly UNDEF because this takes precedence over NOCP */
- if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
- unallocated_encoding(s);
- return true;
- }
-
- if (!dc_isar_feature(aa32_vfp_simd, s)) {
- /* NOP if we have neither FP nor MVE */
- return true;
- }
-
- /*
- * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
- * active floating point context so we must NOP (without doing
- * any lazy state preservation or the NOCP check).
- */
- aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
- sfpa = load_cpu_field(v7m.control[M_REG_S]);
- tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
- tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
- tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
- tcg_gen_or_i32(sfpa, sfpa, aspen);
- arm_gen_condlabel(s);
- tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
-
- if (s->fp_excp_el != 0) {
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
- syn_uncategorized(), s->fp_excp_el);
- return true;
- }
-
- topreg = a->vd + a->imm - 1;
- btmreg = a->vd;
-
- /* Convert to Sreg numbers if the insn specified in Dregs */
- if (a->size == 3) {
- topreg = topreg * 2 + 1;
- btmreg *= 2;
- }
-
- if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
- /* UNPREDICTABLE: we choose to undef */
- unallocated_encoding(s);
- return true;
- }
-
- /* Silently ignore requests to clear D16-D31 if they don't exist */
- if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
- topreg = 31;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- /* Zero the Sregs from btmreg to topreg inclusive. */
- zero = tcg_const_i64(0);
- if (btmreg & 1) {
- write_neon_element64(zero, btmreg >> 1, 1, MO_32);
- btmreg++;
- }
- for (; btmreg + 1 <= topreg; btmreg += 2) {
- write_neon_element64(zero, btmreg >> 1, 0, MO_64);
- }
- if (btmreg == topreg) {
- write_neon_element64(zero, btmreg >> 1, 0, MO_32);
- btmreg++;
- }
- assert(btmreg == topreg + 1);
- /* TODO: when MVE is implemented, zero VPR here */
- return true;
-}
-
-static bool trans_NOCP(DisasContext *s, arg_nocp *a)
-{
- /*
- * Handle M-profile early check for disabled coprocessor:
- * all we need to do here is emit the NOCP exception if
- * the coprocessor is disabled. Otherwise we return false
- * and the real VFP/etc decode will handle the insn.
- */
- assert(arm_dc_feature(s, ARM_FEATURE_M));
-
- if (a->cp == 11) {
- a->cp = 10;
- }
- if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
- (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
- /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
- a->cp = 10;
- }
-
- if (a->cp != 10) {
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
- syn_uncategorized(), default_exception_el(s));
- return true;
- }
-
- if (s->fp_excp_el != 0) {
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
- syn_uncategorized(), s->fp_excp_el);
- return true;
- }
-
- return false;
-}
-
-static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
-{
- /* This range needs a coprocessor check for v8.1M and later only */
- if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
- return false;
- }
- return trans_NOCP(s, a);
-}
-
static bool trans_VINS(DisasContext *s, arg_VINS *a)
{
TCGv_i32 rd, rm;
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 43ff0d4..455352b 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -50,12 +50,7 @@
#define ENABLE_ARCH_8 arm_dc_feature(s, ARM_FEATURE_V8)
#include "translate.h"
-
-#if defined(CONFIG_USER_ONLY)
-#define IS_USER(s) 1
-#else
-#define IS_USER(s) (s->user)
-#endif
+#include "translate-a32.h"
/* These are TCG temporaries used only by the legacy iwMMXt decoder */
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
@@ -71,11 +66,6 @@ static const char * const regnames[] =
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };
-/* Function prototypes for gen_ functions calling Neon helpers. */
-typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32,
- TCGv_i32, TCGv_i32);
-/* Function prototypes for gen_ functions for fix point conversions */
-typedef void VFPGenFixPointFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
/* initialize TCG globals. */
void arm_translate_init(void)
@@ -101,7 +91,7 @@ void arm_translate_init(void)
}
/* Generate a label used for skipping this instruction */
-static void arm_gen_condlabel(DisasContext *s)
+void arm_gen_condlabel(DisasContext *s)
{
if (!s->condjmp) {
s->condlabel = gen_new_label();
@@ -109,30 +99,6 @@ static void arm_gen_condlabel(DisasContext *s)
}
}
-/*
- * Constant expanders for the decoders.
- */
-
-static int negate(DisasContext *s, int x)
-{
- return -x;
-}
-
-static int plus_2(DisasContext *s, int x)
-{
- return x + 2;
-}
-
-static int times_2(DisasContext *s, int x)
-{
- return x * 2;
-}
-
-static int times_4(DisasContext *s, int x)
-{
- return x * 4;
-}
-
/* Flags for the disas_set_da_iss info argument:
* lower bits hold the Rt register number, higher bits are flags.
*/
@@ -211,24 +177,6 @@ static inline int get_a32_user_mem_index(DisasContext *s)
}
}
-static inline TCGv_i32 load_cpu_offset(int offset)
-{
- TCGv_i32 tmp = tcg_temp_new_i32();
- tcg_gen_ld_i32(tmp, cpu_env, offset);
- return tmp;
-}
-
-#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
-
-static inline void store_cpu_offset(TCGv_i32 var, int offset)
-{
- tcg_gen_st_i32(var, cpu_env, offset);
- tcg_temp_free_i32(var);
-}
-
-#define store_cpu_field(var, name) \
- store_cpu_offset(var, offsetof(CPUARMState, name))
-
/* The architectural value of PC. */
static uint32_t read_pc(DisasContext *s)
{
@@ -236,7 +184,7 @@ static uint32_t read_pc(DisasContext *s)
}
/* Set a variable to the value of a CPU register. */
-static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
+void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
{
if (reg == 15) {
tcg_gen_movi_i32(var, read_pc(s));
@@ -245,20 +193,12 @@ static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
}
}
-/* Create a new temporary and set it to the value of a CPU register. */
-static inline TCGv_i32 load_reg(DisasContext *s, int reg)
-{
- TCGv_i32 tmp = tcg_temp_new_i32();
- load_reg_var(s, tmp, reg);
- return tmp;
-}
-
/*
* Create a new temp, REG + OFS, except PC is ALIGN(PC, 4).
* This is used for load/store for which use of PC implies (literal),
* or ADD that implies ADR.
*/
-static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
+TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
{
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -272,7 +212,7 @@ static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
/* Set a CPU register. The source must be a temporary and will be
marked as dead. */
-static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
+void store_reg(DisasContext *s, int reg, TCGv_i32 var)
{
if (reg == 15) {
/* In Thumb mode, we must ignore bit 0.
@@ -313,15 +253,12 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var)
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
-
-static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
+void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
{
TCGv_i32 tmp_mask = tcg_const_i32(mask);
gen_helper_cpsr_write(cpu_env, var, tmp_mask);
tcg_temp_free_i32(tmp_mask);
}
-/* Set NZCV flags from the high 4 bits of var. */
-#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
static void gen_exception_internal(int excp)
{
@@ -388,7 +325,7 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
}
/* Byteswap each halfword. */
-static void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
+void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
{
TCGv_i32 tmp = tcg_temp_new_i32();
TCGv_i32 mask = tcg_const_i32(0x00ff00ff);
@@ -409,12 +346,6 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var)
tcg_gen_ext16s_i32(dest, var);
}
-/* Swap low and high halfwords. */
-static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var)
-{
- tcg_gen_rotri_i32(dest, var, 16);
-}
-
/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
tmp = (t0 ^ t1) & 0x8000;
t0 &= ~0x8000;
@@ -746,7 +677,7 @@ void arm_gen_test_cc(int cc, TCGLabel *label)
arm_free_cc(&cmp);
}
-static inline void gen_set_condexec(DisasContext *s)
+void gen_set_condexec(DisasContext *s)
{
if (s->condexec_mask) {
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
@@ -756,7 +687,7 @@ static inline void gen_set_condexec(DisasContext *s)
}
}
-static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
+void gen_set_pc_im(DisasContext *s, target_ulong val)
{
tcg_gen_movi_i32(cpu_R[15], val);
}
@@ -948,24 +879,24 @@ static TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op)
* Internal routines are used for NEON cases where the endianness
* and/or alignment has already been taken into account and manipulated.
*/
-static void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
- TCGv_i32 a32, int index, MemOp opc)
+void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
+ TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_ld_i32(val, addr, index, opc);
tcg_temp_free(addr);
}
-static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
- TCGv_i32 a32, int index, MemOp opc)
+void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
+ TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_st_i32(val, addr, index, opc);
tcg_temp_free(addr);
}
-static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
- TCGv_i32 a32, int index, MemOp opc)
+void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
+ TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
@@ -978,8 +909,8 @@ static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
tcg_temp_free(addr);
}
-static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
- TCGv_i32 a32, int index, MemOp opc)
+void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
+ TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
@@ -995,26 +926,26 @@ static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
tcg_temp_free(addr);
}
-static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
- int index, MemOp opc)
+void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
+ int index, MemOp opc)
{
gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, opc));
}
-static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
- int index, MemOp opc)
+void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
+ int index, MemOp opc)
{
gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc));
}
-static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
- int index, MemOp opc)
+void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
+ int index, MemOp opc)
{
gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, opc));
}
-static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
- int index, MemOp opc)
+void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
+ int index, MemOp opc)
{
gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, opc));
}
@@ -1033,25 +964,6 @@ static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
gen_aa32_st_i32(s, val, a32, index, OPC); \
}
-static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
- TCGv_i32 a32, int index)
-{
- gen_aa32_ld_i64(s, val, a32, index, MO_Q);
-}
-
-static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
- TCGv_i32 a32, int index)
-{
- gen_aa32_st_i64(s, val, a32, index, MO_Q);
-}
-
-DO_GEN_LD(8u, MO_UB)
-DO_GEN_LD(16u, MO_UW)
-DO_GEN_LD(32u, MO_UL)
-DO_GEN_ST(8, MO_UB)
-DO_GEN_ST(16, MO_UW)
-DO_GEN_ST(32, MO_UL)
-
static inline void gen_hvc(DisasContext *s, int imm16)
{
/* The pre HVC helper handles cases when HVC gets trapped
@@ -1093,11 +1005,15 @@ static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp)
s->base.is_jmp = DISAS_NORETURN;
}
-static void gen_exception_insn(DisasContext *s, uint32_t pc, int excp,
- int syn, uint32_t target_el)
+void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
+ uint32_t syn, uint32_t target_el)
{
- gen_set_condexec(s);
- gen_set_pc_im(s, pc);
+ if (s->aarch64) {
+ gen_a64_set_pc_im(pc);
+ } else {
+ gen_set_condexec(s);
+ gen_set_pc_im(s, pc);
+ }
gen_exception(excp, syn, target_el);
s->base.is_jmp = DISAS_NORETURN;
}
@@ -1114,7 +1030,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
s->base.is_jmp = DISAS_NORETURN;
}
-static void unallocated_encoding(DisasContext *s)
+void unallocated_encoding(DisasContext *s)
{
/* Unallocated and reserved encodings are uncategorized */
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
@@ -1138,7 +1054,7 @@ static void gen_exception_el(DisasContext *s, int excp, uint32_t syn,
}
/* Force a TB lookup after an instruction that changes the CPU state. */
-static inline void gen_lookup_tb(DisasContext *s)
+void gen_lookup_tb(DisasContext *s)
{
tcg_gen_movi_i32(cpu_R[15], s->base.pc_next);
s->base.is_jmp = DISAS_EXIT;
@@ -1173,7 +1089,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
/*
* Return the offset of a "full" NEON Dreg.
*/
-static long neon_full_reg_offset(unsigned reg)
+long neon_full_reg_offset(unsigned reg)
{
return offsetof(CPUARMState, vfp.zregs[reg >> 1].d[reg & 1]);
}
@@ -1182,7 +1098,7 @@ static long neon_full_reg_offset(unsigned reg)
* Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
* where 0 is the least significant end of the register.
*/
-static long neon_element_offset(int reg, int element, MemOp memop)
+long neon_element_offset(int reg, int element, MemOp memop)
{
int element_size = 1 << (memop & MO_SIZE);
int ofs = element * element_size;
@@ -1199,7 +1115,7 @@ static long neon_element_offset(int reg, int element, MemOp memop)
}
/* Return the offset of a VFP Dreg (dp = true) or VFP Sreg (dp = false). */
-static long vfp_reg_offset(bool dp, unsigned reg)
+long vfp_reg_offset(bool dp, unsigned reg)
{
if (dp) {
return neon_element_offset(reg, 0, MO_64);
@@ -1208,27 +1124,7 @@ static long vfp_reg_offset(bool dp, unsigned reg)
}
}
-static inline void vfp_load_reg64(TCGv_i64 var, int reg)
-{
- tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg));
-}
-
-static inline void vfp_store_reg64(TCGv_i64 var, int reg)
-{
- tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg));
-}
-
-static inline void vfp_load_reg32(TCGv_i32 var, int reg)
-{
- tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg));
-}
-
-static inline void vfp_store_reg32(TCGv_i32 var, int reg)
-{
- tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg));
-}
-
-static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
+void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@@ -1254,7 +1150,7 @@ static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
}
}
-static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
+void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@@ -1273,7 +1169,7 @@ static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
}
}
-static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
+void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@@ -1292,7 +1188,7 @@ static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
}
}
-static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
+void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@@ -1308,20 +1204,8 @@ static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
}
}
-static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
-{
- TCGv_ptr ret = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg));
- return ret;
-}
-
#define ARM_CP_RW_BIT (1 << 20)
-/* Include the VFP and Neon decoders */
-#include "decode-m-nocp.c.inc"
-#include "translate-vfp.c.inc"
-#include "translate-neon.c.inc"
-
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
{
tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
diff --git a/target/arm/translate.h b/target/arm/translate.h
index ccf60c9..12c28b0 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -118,6 +118,30 @@ extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
extern TCGv_i64 cpu_exclusive_addr;
extern TCGv_i64 cpu_exclusive_val;
+/*
+ * Constant expanders for the decoders.
+ */
+
+static inline int negate(DisasContext *s, int x)
+{
+ return -x;
+}
+
+static inline int plus_2(DisasContext *s, int x)
+{
+ return x + 2;
+}
+
+static inline int times_2(DisasContext *s, int x)
+{
+ return x * 2;
+}
+
+static inline int times_4(DisasContext *s, int x)
+{
+ return x * 4;
+}
+
static inline int arm_dc_feature(DisasContext *dc, int feature)
{
return (dc->features & (1ULL << feature)) != 0;
@@ -205,6 +229,9 @@ void arm_free_cc(DisasCompare *cmp);
void arm_jump_cc(DisasCompare *cmp, TCGLabel *label);
void arm_gen_test_cc(int cc, TCGLabel *label);
MemOp pow2_align(unsigned i);
+void unallocated_encoding(DisasContext *s);
+void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
+ uint32_t syn, uint32_t target_el);
/* Return state of Alternate Half-precision flag, caller frees result */
static inline TCGv_i32 get_ahp_flag(void)
@@ -382,6 +409,8 @@ typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32);
typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
+typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32,
+ TCGv_i32, TCGv_i32);
typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);