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
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmCZXs8ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3iDKD/4+RmKuaIRgbeyLT6hyfSKi
 iWgYbfQsvc99awdKqIWMgmsJx5YQLoeleKkjkFMjqYH5ehRk4qtKp1/FXH3DsVYk
 D1NBheiL7wfsublDCugIFBRQEtOB0sHlLJtUdhvKCgjO0+8HNasehXhHppD/RhnW
 RNfFSTDvLyQNS8DyAOfIcsmwtcILgsfDQmkrQiHTYTVZi8Hlg8WbemgPAEjS0yCB
 ngVZCeZLIgNiq5Xtq/rK39v89QT1CnWjOOtZYDGKV/hmPm5ge/oofPA/O0dYSwPf
 8y0htonR0cM/qO4tv7vfEW9zqAu+6MYoJsH3JT221sCqX5gsAGBAjyUgPsamMcdc
 J+yMg0PFFOTIJ2GQUnE2mSDuwRvo4F0kWzrm0c3S7+jfRc7/FCOmpo8F0S3rs/IH
 SdhkMucDvCdjoLbXE5slr2Nz2HrWXKOsUaBnTxzzOF5lSu4MXix+Zpaj+7crBVIj
 NB6ooeTqaM6X1cE7bwwnTKdZT0rv01uj8IcU/H74UGCfLc+I/6fophMzUCwy7p4S
 6BrhnGzAfQrmPCk2JPlVR40Z2C8E6yAwX35OihZGhFEXBLvO9SbyAXY5yXlolxsV
 w/ryagSkPoU/O0ZIWwuu6sF3szvXXvPEtT5+6oM/wlxgUvIEHqZ0YrVNniIh1n/S
 y6FtY/BXwkjp1bwNeOcpqQ==
 =E7yJ
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2021-05-10 17:28:11 +01:00
commit e58c7a3bba
27 changed files with 720 additions and 413 deletions

View File

@ -18,9 +18,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
extern "C" {
#include "disas/dis-asm.h" #include "disas/dis-asm.h"
}
#include "vixl/a64/disasm-a64.h" #include "vixl/a64/disasm-a64.h"

View File

@ -28,9 +28,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
extern "C" {
#include "disas/dis-asm.h" #include "disas/dis-asm.h"
}
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>

View File

@ -45,3 +45,13 @@ Differences between QEMU and real hardware:
flash, but only as simple ROM, so attempting to rewrite the flash flash, but only as simple ROM, so attempting to rewrite the flash
from the guest will fail from the guest will fail
- QEMU does not model the USB controller in MPS3 boards - 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``.

View File

@ -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 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 any real hardware the `sbsa-ref` board intends to look like real
hardware. The `Server Base System Architecture 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 minimum base line of hardware support and importantly how the firmware
reports that to any operating system. It is a static system that reports that to any operating system. It is a static system that
reports a very minimal DT to the firmware for non-discoverable reports a very minimal DT to the firmware for non-discoverable

View File

@ -65,7 +65,6 @@ static struct arm_boot_info imx25_pdk_binfo;
static void imx25_pdk_init(MachineState *machine) static void imx25_pdk_init(MachineState *machine)
{ {
MachineClass *mc = MACHINE_GET_CLASS(machine);
IMX25PDK *s = g_new0(IMX25PDK, 1); IMX25PDK *s = g_new0(IMX25PDK, 1);
unsigned int ram_size; unsigned int ram_size;
unsigned int alias_offset; unsigned int alias_offset;
@ -77,8 +76,8 @@ static void imx25_pdk_init(MachineState *machine)
/* We need to initialize our memory */ /* We need to initialize our memory */
if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
char *sz = size_to_str(mc->default_ram_size); char *sz = size_to_str(FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
error_report("Invalid RAM size, should be %s", sz); error_report("RAM size more than %s is not supported", sz);
g_free(sz); g_free(sz);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -55,6 +55,7 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/reset.h"
#include "hw/misc/unimp.h" #include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h" #include "hw/char/cmsdk-apb-uart.h"
#include "hw/timer/cmsdk-apb-timer.h" #include "hw/timer/cmsdk-apb-timer.h"
@ -72,6 +73,7 @@
#include "hw/core/split-irq.h" #include "hw/core/split-irq.h"
#include "hw/qdev-clock.h" #include "hw/qdev-clock.h"
#include "qom/object.h" #include "qom/object.h"
#include "hw/irq.h"
#define MPS2TZ_NUMIRQ_MAX 96 #define MPS2TZ_NUMIRQ_MAX 96
#define MPS2TZ_RAM_MAX 5 #define MPS2TZ_RAM_MAX 5
@ -153,6 +155,9 @@ struct MPS2TZMachineState {
SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX]; SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX];
Clock *sysclk; Clock *sysclk;
Clock *s32kclk; Clock *s32kclk;
bool remap;
qemu_irq remap_irq;
}; };
#define TYPE_MPS2TZ_MACHINE "mps2tz" #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[] = { { static const RAMInfo an524_raminfo[] = { {
.name = "bram", .name = "bram",
.base = 0x00000000, .base = 0x00000000,
@ -457,6 +466,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC); object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC);
sccdev = DEVICE(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-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); 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); 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, static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
const char *name, hwaddr size, const char *name, hwaddr size,
const int *irqs) const int *irqs)
@ -711,7 +767,7 @@ static uint32_t boot_ram_size(MPS2TZMachineState *mms)
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
for (p = mmc->raminfo; p->name; p++) { for (p = mmc->raminfo; p->name; p++) {
if (p->base == 0) { if (p->base == boot_mem_base(mms)) {
return p->size; return p->size;
} }
} }
@ -1095,6 +1151,16 @@ static void mps2tz_common_init(MachineState *machine)
create_non_mpc_ram(mms); 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, armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
boot_ram_size(mms)); boot_ram_size(mms));
} }
@ -1117,12 +1183,47 @@ static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
*iregion = region; *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) static void mps2tz_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
mc->init = mps2tz_common_init; mc->init = mps2tz_common_init;
mc->reset = mps2_machine_reset;
iic->check = mps2_tz_idau_check; 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->raminfo = an524_raminfo;
mmc->armsse_type = TYPE_SSE200; mmc->armsse_type = TYPE_SSE200;
mps2tz_set_default_ram_info(mmc); 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) static void mps3tz_an547_class_init(ObjectClass *oc, void *data)

View File

@ -118,7 +118,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(dev, nd); 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); s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal); sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 0, base);

View File

@ -23,6 +23,7 @@
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "trace.h" #include "trace.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/irq.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "hw/registerfields.h" #include "hw/registerfields.h"
#include "hw/misc/mps2-scc.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) { switch (offset) {
case A_CFG0: case A_CFG0:
/* /*
* TODO on some boards bit 0 controls RAM remapping; * On some boards bit 0 controls board-specific remapping;
* on others bit 1 is CPU_WAIT. * 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; s->cfg0 = value;
qemu_set_irq(s->remap, s->cfg0 & 1);
break; break;
case A_CFG1: case A_CFG1:
s->cfg1 = value; s->cfg1 = value;
@ -283,7 +287,7 @@ static void mps2_scc_reset(DeviceState *dev)
int i; int i;
trace_mps2_scc_reset(); trace_mps2_scc_reset();
s->cfg0 = 0; s->cfg0 = s->cfg0_reset;
s->cfg1 = 0; s->cfg1 = 0;
s->cfg2 = 0; s->cfg2 = 0;
s->cfg5 = 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); memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000);
sysbus_init_mmio(sbd, &s->iomem); 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) 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-cfg4", MPS2SCC, cfg4, 0),
DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0), DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 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. * 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 * In hardware they can be configured via a config file read by the

View File

@ -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 * into any bus, and we must reset it manually. When omap_mmc is
* QOMified this must move into the QOM reset function. * 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, static uint64_t omap_mmc_read(void *opaque, hwaddr offset,

View File

@ -9,6 +9,12 @@
#ifndef DISAS_DIS_ASM_H #ifndef DISAS_DIS_ASM_H
#define DISAS_DIS_ASM_H #define DISAS_DIS_ASM_H
#include "qemu/bswap.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *PTR; typedef void *PTR;
typedef uint64_t bfd_vma; typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_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 */ /* from libbfd */
#include "qemu/bswap.h"
static inline bfd_vma bfd_getl64(const bfd_byte *addr) static inline bfd_vma bfd_getl64(const bfd_byte *addr)
{ {
return ldq_le_p(addr); return ldq_le_p(addr);
@ -508,4 +512,8 @@ static inline bfd_vma bfd_getb16(const bfd_byte *addr)
typedef bool bfd_boolean; typedef bool bfd_boolean;
#ifdef __cplusplus
}
#endif
#endif /* DISAS_DIS_ASM_H */ #endif /* DISAS_DIS_ASM_H */

View File

@ -9,6 +9,24 @@
* (at your option) any later version. * (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 #ifndef MPS2_SCC_H
#define MPS2_SCC_H #define MPS2_SCC_H
@ -43,6 +61,9 @@ struct MPS2SCC {
uint32_t num_oscclk; uint32_t num_oscclk;
uint32_t *oscclk; uint32_t *oscclk;
uint32_t *oscclk_reset; uint32_t *oscclk_reset;
uint32_t cfg0_reset;
qemu_irq remap;
}; };
#endif #endif

View File

@ -1,8 +1,6 @@
#ifndef BSWAP_H #ifndef BSWAP_H
#define BSWAP_H #define BSWAP_H
#include "fpu/softfloat-types.h"
#ifdef CONFIG_MACHINE_BSWAP_H #ifdef CONFIG_MACHINE_BSWAP_H
# include <sys/endian.h> # include <sys/endian.h>
# include <machine/bswap.h> # include <machine/bswap.h>
@ -12,7 +10,18 @@
# include <endian.h> # include <endian.h>
#elif defined(CONFIG_BYTESWAP_H) #elif defined(CONFIG_BYTESWAP_H)
# include <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) static inline uint16_t bswap16(uint16_t x)
{ {
return bswap_16(x); return bswap_16(x);
@ -27,7 +36,9 @@ static inline uint64_t bswap64(uint64_t x)
{ {
return bswap_64(x); return bswap_64(x);
} }
# else #endif
#ifdef BSWAP_FROM_FALLBACKS
static inline uint16_t bswap16(uint16_t x) static inline uint16_t bswap16(uint16_t x)
{ {
return (((x & 0x00ff) << 8) | return (((x & 0x00ff) << 8) |
@ -53,7 +64,10 @@ static inline uint64_t bswap64(uint64_t x)
((x & 0x00ff000000000000ULL) >> 40) | ((x & 0x00ff000000000000ULL) >> 40) |
((x & 0xff00000000000000ULL) >> 56)); ((x & 0xff00000000000000ULL) >> 56));
} }
#endif /* ! CONFIG_MACHINE_BSWAP_H */ #endif
#undef BSWAP_FROM_BYTESWAP
#undef BSWAP_FROM_FALLBACKS
static inline void bswap16s(uint16_t *s) static inline void bswap16s(uint16_t *s)
{ {
@ -494,4 +508,8 @@ DO_STN_LDN_P(be)
#undef le_bswaps #undef le_bswaps
#undef be_bswaps #undef be_bswaps
#ifdef __cplusplus
}
#endif
#endif /* BSWAP_H */ #endif /* BSWAP_H */

View File

@ -131,10 +131,6 @@ QEMU_EXTERN_C int daemon(int, int);
*/ */
#include "glib-compat.h" #include "glib-compat.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32 #ifdef _WIN32
#include "sysemu/os-win32.h" #include "sysemu/os-win32.h"
#endif #endif
@ -143,6 +139,10 @@ extern "C" {
#include "sysemu/os-posix.h" #include "sysemu/os-posix.h"
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
#include "qemu/typedefs.h" #include "qemu/typedefs.h"
/* /*

View File

@ -38,6 +38,10 @@
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
void os_set_line_buffering(void); void os_set_line_buffering(void);
void os_set_proc_name(const char *s); void os_set_proc_name(const char *s);
void os_setup_signal_handling(void); void os_setup_signal_handling(void);
@ -92,4 +96,8 @@ static inline void qemu_funlockfile(FILE *f)
funlockfile(f); funlockfile(f);
} }
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -30,6 +30,10 @@
#include <windows.h> #include <windows.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN64) #if defined(_WIN64)
/* On w64, setjmp is implemented by _setjmp which needs a second parameter. /* On w64, setjmp is implemented by _setjmp which needs a second parameter.
* If this parameter is NULL, longjump does no stack unwinding. * 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, ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *addr, socklen_t *addrlen); struct sockaddr *addr, socklen_t *addrlen);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -586,6 +586,16 @@ enum {
ARM_HWCAP2_A64_SVESM4 = 1 << 6, ARM_HWCAP2_A64_SVESM4 = 1 << 6,
ARM_HWCAP2_A64_FLAGM2 = 1 << 7, ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
ARM_HWCAP2_A64_FRINT = 1 << 8, 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() #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_dcpodp, ARM_HWCAP2_A64_DCPODP);
GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2); GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT); 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; return hwcaps;
} }

View File

@ -4742,7 +4742,7 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t pageaddr = sextract64(value << 12, 0, 56); uint64_t pageaddr = sextract64(value << 12, 0, 56);
bool secure = arm_is_secure_below_el3(env); bool secure = arm_is_secure_below_el3(env);
int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2; 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); pageaddr);
tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits); tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);

View File

@ -1,11 +1,11 @@
gen = [ gen = [
decodetree.process('sve.decode', extra_args: '--decode=disas_sve'), decodetree.process('sve.decode', extra_args: '--decode=disas_sve'),
decodetree.process('neon-shared.decode', extra_args: '--static-decode=disas_neon_shared'), decodetree.process('neon-shared.decode', extra_args: '--decode=disas_neon_shared'),
decodetree.process('neon-dp.decode', extra_args: '--static-decode=disas_neon_dp'), decodetree.process('neon-dp.decode', extra_args: '--decode=disas_neon_dp'),
decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'), decodetree.process('neon-ls.decode', extra_args: '--decode=disas_neon_ls'),
decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'), decodetree.process('vfp.decode', extra_args: '--decode=disas_vfp'),
decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'), decodetree.process('vfp-uncond.decode', extra_args: '--decode=disas_vfp_uncond'),
decodetree.process('m-nocp.decode', extra_args: '--static-decode=disas_m_nocp'), decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'),
decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'), decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'),
decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'), decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'),
decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'), decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'),
@ -26,6 +26,9 @@ arm_ss.add(files(
'op_helper.c', 'op_helper.c',
'tlb_helper.c', 'tlb_helper.c',
'translate.c', 'translate.c',
'translate-m-nocp.c',
'translate-neon.c',
'translate-vfp.c',
'vec_helper.c', 'vec_helper.c',
'vfp_helper.c', 'vfp_helper.c',
'cpu_tcg.c', 'cpu_tcg.c',

View File

@ -228,6 +228,7 @@ void HELPER(setend)(CPUARMState *env)
arm_rebuild_hflags(env); arm_rebuild_hflags(env);
} }
#ifndef CONFIG_USER_ONLY
/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped. /* 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; * The function returns the target EL (1-3) if the instruction is to be trapped;
* otherwise it returns 0 indicating it is not 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; return 0;
} }
#endif
void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) 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); CPUState *cs = env_cpu(env);
int target_el = check_wfx_trap(env, false); 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->exception_index = EXCP_HLT;
cs->halted = 1; cs->halted = 1;
cpu_loop_exit(cs); cpu_loop_exit(cs);
#endif
} }
void HELPER(wfe)(CPUARMState *env) void HELPER(wfe)(CPUARMState *env)

144
target/arm/translate-a32.h Normal file
View File

@ -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

View File

@ -359,14 +359,6 @@ static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
s->base.is_jmp = DISAS_NORETURN; 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) static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
{ {
TCGv_i32 tcg_syn; 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) static void init_tmp_a64_array(DisasContext *s)
{ {
#ifdef CONFIG_DEBUG_TCG #ifdef CONFIG_DEBUG_TCG

View File

@ -18,8 +18,6 @@
#ifndef TARGET_ARM_TRANSLATE_A64_H #ifndef TARGET_ARM_TRANSLATE_A64_H
#define TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H
void unallocated_encoding(DisasContext *s);
#define unsupported_encoding(s, insn) \ #define unsupported_encoding(s, insn) \
do { \ do { \
qemu_log_mask(LOG_UNIMP, \ qemu_log_mask(LOG_UNIMP, \

View File

@ -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);
}

View File

@ -20,11 +20,13 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
/* #include "qemu/osdep.h"
* This file is intended to be included from translate.c; it uses #include "tcg/tcg-op.h"
* some macros and definitions provided by that file. #include "tcg/tcg-op-gvec.h"
* It might be possible to convert it to a standalone .c file eventually. #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) 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-ls.c.inc"
#include "decode-neon-shared.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) static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
{ {
long offset = neon_element_offset(reg, ele, mop & MO_SIZE); long offset = neon_element_offset(reg, ele, mop & MO_SIZE);

View File

@ -20,16 +20,38 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
/* #include "qemu/osdep.h"
* This file is intended to be included from translate.c; it uses #include "tcg/tcg-op.h"
* some macros and definitions provided by that file. #include "tcg/tcg-op-gvec.h"
* It might be possible to convert it to a standalone .c file eventually. #include "exec/exec-all.h"
*/ #include "exec/gen-icount.h"
#include "translate.h"
#include "translate-a32.h"
/* Include the generated VFP decoder */ /* Include the generated VFP decoder */
#include "decode-vfp.c.inc" #include "decode-vfp.c.inc"
#include "decode-vfp-uncond.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 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 * 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 * The most usual kind of VFP access check, for everything except
* FMXR/FMRX to the always-available special registers. * 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); 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; 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) static bool trans_VINS(DisasContext *s, arg_VINS *a)
{ {
TCGv_i32 rd, rm; TCGv_i32 rd, rm;

View File

@ -50,12 +50,7 @@
#define ENABLE_ARCH_8 arm_dc_feature(s, ARM_FEATURE_V8) #define ENABLE_ARCH_8 arm_dc_feature(s, ARM_FEATURE_V8)
#include "translate.h" #include "translate.h"
#include "translate-a32.h"
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s) (s->user)
#endif
/* These are TCG temporaries used only by the legacy iwMMXt decoder */ /* These are TCG temporaries used only by the legacy iwMMXt decoder */
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; 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", { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" }; "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. */ /* initialize TCG globals. */
void arm_translate_init(void) void arm_translate_init(void)
@ -101,7 +91,7 @@ void arm_translate_init(void)
} }
/* Generate a label used for skipping this instruction */ /* Generate a label used for skipping this instruction */
static void arm_gen_condlabel(DisasContext *s) void arm_gen_condlabel(DisasContext *s)
{ {
if (!s->condjmp) { if (!s->condjmp) {
s->condlabel = gen_new_label(); 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: /* Flags for the disas_set_da_iss info argument:
* lower bits hold the Rt register number, higher bits are flags. * 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. */ /* The architectural value of PC. */
static uint32_t read_pc(DisasContext *s) 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. */ /* 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) { if (reg == 15) {
tcg_gen_movi_i32(var, read_pc(s)); 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). * 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), * This is used for load/store for which use of PC implies (literal),
* or ADD that implies ADR. * 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(); 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 /* Set a CPU register. The source must be a temporary and will be
marked as dead. */ 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) { if (reg == 15) {
/* In Thumb mode, we must ignore bit 0. /* 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_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var) #define gen_uxtb16(var) gen_helper_uxtb16(var, var)
void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
{ {
TCGv_i32 tmp_mask = tcg_const_i32(mask); TCGv_i32 tmp_mask = tcg_const_i32(mask);
gen_helper_cpsr_write(cpu_env, var, tmp_mask); gen_helper_cpsr_write(cpu_env, var, tmp_mask);
tcg_temp_free_i32(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) 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. */ /* 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 tmp = tcg_temp_new_i32();
TCGv_i32 mask = tcg_const_i32(0x00ff00ff); 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); 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. /* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
tmp = (t0 ^ t1) & 0x8000; tmp = (t0 ^ t1) & 0x8000;
t0 &= ~0x8000; t0 &= ~0x8000;
@ -746,7 +677,7 @@ void arm_gen_test_cc(int cc, TCGLabel *label)
arm_free_cc(&cmp); arm_free_cc(&cmp);
} }
static inline void gen_set_condexec(DisasContext *s) void gen_set_condexec(DisasContext *s)
{ {
if (s->condexec_mask) { if (s->condexec_mask) {
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); 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); 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 * Internal routines are used for NEON cases where the endianness
* and/or alignment has already been taken into account and manipulated. * and/or alignment has already been taken into account and manipulated.
*/ */
static void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc) TCGv_i32 a32, int index, MemOp opc)
{ {
TCGv addr = gen_aa32_addr(s, a32, opc); TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_ld_i32(val, addr, index, opc); tcg_gen_qemu_ld_i32(val, addr, index, opc);
tcg_temp_free(addr); tcg_temp_free(addr);
} }
static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc) TCGv_i32 a32, int index, MemOp opc)
{ {
TCGv addr = gen_aa32_addr(s, a32, opc); TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_st_i32(val, addr, index, opc); tcg_gen_qemu_st_i32(val, addr, index, opc);
tcg_temp_free(addr); tcg_temp_free(addr);
} }
static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc) TCGv_i32 a32, int index, MemOp opc)
{ {
TCGv addr = gen_aa32_addr(s, a32, 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); tcg_temp_free(addr);
} }
static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc) TCGv_i32 a32, int index, MemOp opc)
{ {
TCGv addr = gen_aa32_addr(s, a32, 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); tcg_temp_free(addr);
} }
static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc) int index, MemOp opc)
{ {
gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, 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, void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc) int index, MemOp opc)
{ {
gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, 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, void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc) int index, MemOp opc)
{ {
gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, 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, void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc) int index, MemOp opc)
{ {
gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, 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); \ 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) static inline void gen_hvc(DisasContext *s, int imm16)
{ {
/* The pre HVC helper handles cases when HVC gets trapped /* 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; s->base.is_jmp = DISAS_NORETURN;
} }
static void gen_exception_insn(DisasContext *s, uint32_t pc, int excp, void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
int syn, uint32_t target_el) uint32_t syn, uint32_t target_el)
{ {
gen_set_condexec(s); if (s->aarch64) {
gen_set_pc_im(s, pc); gen_a64_set_pc_im(pc);
} else {
gen_set_condexec(s);
gen_set_pc_im(s, pc);
}
gen_exception(excp, syn, target_el); gen_exception(excp, syn, target_el);
s->base.is_jmp = DISAS_NORETURN; 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; s->base.is_jmp = DISAS_NORETURN;
} }
static void unallocated_encoding(DisasContext *s) void unallocated_encoding(DisasContext *s)
{ {
/* Unallocated and reserved encodings are uncategorized */ /* Unallocated and reserved encodings are uncategorized */
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_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. */ /* 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); tcg_gen_movi_i32(cpu_R[15], s->base.pc_next);
s->base.is_jmp = DISAS_EXIT; 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. * 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]); 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, * 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. * 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 element_size = 1 << (memop & MO_SIZE);
int ofs = element * element_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). */ /* 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) { if (dp) {
return neon_element_offset(reg, 0, MO_64); 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) void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
{
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)
{ {
long off = neon_element_offset(reg, ele, 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); 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); 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); 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) #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) static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
{ {
tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg])); tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));

View File

@ -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_addr;
extern TCGv_i64 cpu_exclusive_val; 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) static inline int arm_dc_feature(DisasContext *dc, int feature)
{ {
return (dc->features & (1ULL << feature)) != 0; 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_jump_cc(DisasCompare *cmp, TCGLabel *label);
void arm_gen_test_cc(int cc, TCGLabel *label); void arm_gen_test_cc(int cc, TCGLabel *label);
MemOp pow2_align(unsigned i); 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 */ /* Return state of Alternate Half-precision flag, caller frees result */
static inline TCGv_i32 get_ahp_flag(void) 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 NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, 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 NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);