target-arm queue:

* fix GIC region size in xlnx-zynqmp
  * xlnx-zynqmp: Remove unnecessary brackets
  * improve A64 generated TCG code
  * add GPIO devices to i.MX25 and i.MX31
  * more missing pieces for EL2 support
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJV9tDQAAoJEDwlJe0UNgzePgMQAI1FfA0pBlKnjuS9nAZtjsMn
 SHGda9+Rp1tbChN4ct2LFnfthk1VIwqcifYufdd+AgLCGsf2w1RK5jG46+UH9Ku7
 33R/opzmBX+ZkZ11AH9w9dqnUzo88bnvf4C8PyPP8mdcAU/PeTse27+bPoyqp/ef
 3WhyUuC+Dk3i5Wwq4TQ7CNKl9aQG2DMw/A84Mjakh0T/WYbiKR5Kgq88FVnNwOI9
 MdcHY5LelSvVtagjnaxEYwjaRd3Ib0tdgd5J6iucTGmhPD+tCuyZl6aLmo0D8pyn
 ub0ltYifewvUGWgYqCI4vTXyhk6fGPBUyjJxwu8upgpryPACOngBkXDBojVIp1tC
 rkh5Wh/JE/iO6ky8Ds+MCQY7F5JpgM7oOQ0lXB+6TNwzuRcvnTyHhP4NtRsRkpT0
 MJdL6R5PwS4DoTswueKW0HwjFXVFri3hZOZXhHXk6VPrtpEibO8XFb92djp5Tzb4
 nB4XNqwTjz2dXvGFr5Y1Nas/pBQPT2sm/8e6fQJ0h06zB+VJ7ECCKvC5yguo9fFs
 DX9DBNeAd0vNTy/twzpJ1zqS98X1TtlGi8GLbTTaV1vQ4BfymAlaZClok8cUrOh4
 0Azn8FKA+bj0L4voTLrHanCf+6mXLv3qusKF5SnG/jj1BzEa7cW1Y85sPCKMMwsI
 B1k63SiEIBXWsIwsTHby
 =PsEE
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150914' into staging

target-arm queue:
 * fix GIC region size in xlnx-zynqmp
 * xlnx-zynqmp: Remove unnecessary brackets
 * improve A64 generated TCG code
 * add GPIO devices to i.MX25 and i.MX31
 * more missing pieces for EL2 support

# gpg: Signature made Mon 14 Sep 2015 14:51:12 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"

* remotes/pmaydell/tags/pull-target-arm-20150914: (24 commits)
  target-arm: Add VMPIDR_EL2
  target-arm: Break out mpidr_read_val()
  target-arm: Add VPIDR_EL2
  target-arm: Suppress EPD for S2, EL2 and EL3 translations
  target-arm: Suppress TBI for S2 translations
  target-arm: Add VTTBR_EL2
  target-arm: Add VTCR_EL2
  hw/cpu/{a15mpcore, a9mpcore}: Handle missing has_el3 CPU props gracefully
  i.MX: Add GPIO devices to i.MX25 SOC
  i.MX: Add GPIO devices to i.MX31 SOC
  i.MX: Add GPIO device
  target-arm: Use tcg_gen_extrh_i64_i32
  target-arm: Recognize ROR
  target-arm: Eliminate unnecessary zero-extend in disas_bitfield
  target-arm: Recognize UXTB, UXTH, LSR, LSL
  target-arm: Recognize SXTB, SXTH, SXTW, ASR
  target-arm: Implement fcsel with movcond
  target-arm: Implement ccmp branchless
  target-arm: Use setcond and movcond for csel
  target-arm: Handle always condition codes within arm_test_cc
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-09-14 14:57:50 +01:00
commit 7e4804dafd
16 changed files with 949 additions and 209 deletions

View File

@ -63,6 +63,11 @@ static void fsl_imx25_init(Object *obj)
object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
}
for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
}
}
static void fsl_imx25_realize(DeviceState *dev, Error **errp)
@ -214,6 +219,30 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
i2c_table[i].irq));
}
/* Initialize all GPIOs */
for (i = 0; i < FSL_IMX25_NUM_GPIOS; i++) {
static const struct {
hwaddr addr;
unsigned int irq;
} gpio_table[FSL_IMX25_NUM_GPIOS] = {
{ FSL_IMX25_GPIO1_ADDR, FSL_IMX25_GPIO1_IRQ },
{ FSL_IMX25_GPIO2_ADDR, FSL_IMX25_GPIO2_IRQ },
{ FSL_IMX25_GPIO3_ADDR, FSL_IMX25_GPIO3_IRQ },
{ FSL_IMX25_GPIO4_ADDR, FSL_IMX25_GPIO4_IRQ }
};
object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
/* Connect GPIO IRQ to PIC */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
qdev_get_gpio_in(DEVICE(&s->avic),
gpio_table[i].irq));
}
/* initialize 2 x 16 KB ROM */
memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL,
"imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);

View File

@ -55,6 +55,11 @@ static void fsl_imx31_init(Object *obj)
object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
}
for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) {
object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
}
}
static void fsl_imx31_realize(DeviceState *dev, Error **errp)
@ -184,6 +189,31 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
i2c_table[i].irq));
}
/* Initialize all GPIOs */
for (i = 0; i < FSL_IMX31_NUM_GPIOS; i++) {
static const struct {
hwaddr addr;
unsigned int irq;
} gpio_table[FSL_IMX31_NUM_GPIOS] = {
{ FSL_IMX31_GPIO1_ADDR, FSL_IMX31_GPIO1_IRQ },
{ FSL_IMX31_GPIO2_ADDR, FSL_IMX31_GPIO2_IRQ },
{ FSL_IMX31_GPIO3_ADDR, FSL_IMX31_GPIO3_IRQ }
};
object_property_set_bool(OBJECT(&s->gpio[i]), false, "has-edge-sel",
&error_abort);
object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
/* Connect GPIO IRQ to PIC */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
qdev_get_gpio_in(DEVICE(&s->avic),
gpio_table[i].irq));
}
/* On a real system, the first 16k is a `secure boot rom' */
memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL,
"imx31.secure_rom",

View File

@ -128,7 +128,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS);
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
if (err) {
error_propagate((errp), (err));
error_propagate(errp, err);
return;
}
assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
@ -173,7 +173,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
&err);
if (err) {
error_propagate((errp), (err));
error_propagate(errp, err);
return;
}
@ -206,7 +206,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized",
&err);
if (err) {
error_propagate((errp), (err));
error_propagate(errp, err);
return;
}
}
@ -229,7 +229,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
if (err) {
error_propagate((errp), (err));
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
@ -240,7 +240,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
if (err) {
error_propagate((errp), (err));
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]);

View File

@ -64,7 +64,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
* either all the CPUs have TZ, or none do.
*/
cpuobj = OBJECT(qemu_get_cpu(0));
has_el3 = object_property_find(cpuobj, "has_el3", &error_abort) &&
has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
object_property_get_bool(cpuobj, "has_el3", &error_abort);
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
}

View File

@ -69,7 +69,7 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
* either all the CPUs have TZ, or none do.
*/
cpuobj = OBJECT(qemu_get_cpu(0));
has_el3 = object_property_find(cpuobj, "has_el3", &error_abort) &&
has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
object_property_get_bool(cpuobj, "has_el3", &error_abort);
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);

View File

@ -5,3 +5,4 @@ common-obj-$(CONFIG_ZAURUS) += zaurus.o
common-obj-$(CONFIG_E500) += mpc8xxx.o
obj-$(CONFIG_OMAP) += omap_gpio.o
obj-$(CONFIG_IMX) += imx_gpio.o

340
hw/gpio/imx_gpio.c Normal file
View File

@ -0,0 +1,340 @@
/*
* i.MX processors GPIO emulation.
*
* Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/gpio/imx_gpio.h"
#ifndef DEBUG_IMX_GPIO
#define DEBUG_IMX_GPIO 0
#endif
typedef enum IMXGPIOLevel {
IMX_GPIO_LEVEL_LOW = 0,
IMX_GPIO_LEVEL_HIGH = 1,
} IMXGPIOLevel;
#define DPRINTF(fmt, args...) \
do { \
if (DEBUG_IMX_GPIO) { \
fprintf(stderr, "%s: " fmt , __func__, ##args); \
} \
} while (0)
static const char *imx_gpio_reg_name(uint32_t reg)
{
switch (reg) {
case DR_ADDR:
return "DR";
case GDIR_ADDR:
return "GDIR";
case PSR_ADDR:
return "PSR";
case ICR1_ADDR:
return "ICR1";
case ICR2_ADDR:
return "ICR2";
case IMR_ADDR:
return "IMR";
case ISR_ADDR:
return "ISR";
case EDGE_SEL_ADDR:
return "EDGE_SEL";
default:
return "[?]";
}
}
static void imx_gpio_update_int(IMXGPIOState *s)
{
qemu_set_irq(s->irq, (s->isr & s->imr) ? 1 : 0);
}
static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
{
/* if this signal isn't configured as an input signal, nothing to do */
if (!extract32(s->gdir, line, 1)) {
return;
}
/* When set, EDGE_SEL overrides the ICR config */
if (extract32(s->edge_sel, line, 1)) {
/* we detect interrupt on rising and falling edge */
if (extract32(s->psr, line, 1) != level) {
/* level changed */
s->isr = deposit32(s->isr, line, 1, 1);
}
} else if (extract64(s->icr, 2*line + 1, 1)) {
/* interrupt is edge sensitive */
if (extract32(s->psr, line, 1) != level) {
/* level changed */
if (extract64(s->icr, 2*line, 1) != level) {
s->isr = deposit32(s->isr, line, 1, 1);
}
}
} else {
/* interrupt is level sensitive */
if (extract64(s->icr, 2*line, 1) == level) {
s->isr = deposit32(s->isr, line, 1, 1);
}
}
}
static void imx_gpio_set(void *opaque, int line, int level)
{
IMXGPIOState *s = IMX_GPIO(opaque);
IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW;
imx_gpio_set_int_line(s, line, imx_level);
/* this is an input signal, so set PSR */
s->psr = deposit32(s->psr, line, 1, imx_level);
imx_gpio_update_int(s);
}
static void imx_gpio_set_all_int_lines(IMXGPIOState *s)
{
int i;
for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
IMXGPIOLevel imx_level = extract32(s->psr, i, 1);
imx_gpio_set_int_line(s, i, imx_level);
}
imx_gpio_update_int(s);
}
static inline void imx_gpio_set_all_output_lines(IMXGPIOState *s)
{
int i;
for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
/*
* if the line is set as output, then forward the line
* level to its user.
*/
if (extract32(s->gdir, i, 1) && s->output[i]) {
qemu_set_irq(s->output[i], extract32(s->dr, i, 1));
}
}
}
static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size)
{
IMXGPIOState *s = IMX_GPIO(opaque);
uint32_t reg_value = 0;
switch (offset) {
case DR_ADDR:
/*
* depending on the "line" configuration, the bit values
* are coming either from DR or PSR
*/
reg_value = (s->dr & s->gdir) | (s->psr & ~s->gdir);
break;
case GDIR_ADDR:
reg_value = s->gdir;
break;
case PSR_ADDR:
reg_value = s->psr & ~s->gdir;
break;
case ICR1_ADDR:
reg_value = extract64(s->icr, 0, 32);
break;
case ICR2_ADDR:
reg_value = extract64(s->icr, 32, 32);
break;
case IMR_ADDR:
reg_value = s->imr;
break;
case ISR_ADDR:
reg_value = s->isr;
break;
case EDGE_SEL_ADDR:
if (s->has_edge_sel) {
reg_value = s->edge_sel;
} else {
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: EDGE_SEL register not "
"present on this version of GPIO device\n",
TYPE_IMX_GPIO, __func__);
}
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad register at offset %d\n",
TYPE_IMX_GPIO, __func__, (int)offset);
break;
}
DPRINTF("(%s) = 0x%"PRIx32"\n", imx_gpio_reg_name(offset), reg_value);
return reg_value;
}
static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
IMXGPIOState *s = IMX_GPIO(opaque);
DPRINTF("(%s, value = 0x%"PRIx32")\n", imx_gpio_reg_name(offset),
(uint32_t)value);
switch (offset) {
case DR_ADDR:
s->dr = value;
imx_gpio_set_all_output_lines(s);
break;
case GDIR_ADDR:
s->gdir = value;
imx_gpio_set_all_output_lines(s);
imx_gpio_set_all_int_lines(s);
break;
case ICR1_ADDR:
s->icr = deposit64(s->icr, 0, 32, value);
imx_gpio_set_all_int_lines(s);
break;
case ICR2_ADDR:
s->icr = deposit64(s->icr, 32, 32, value);
imx_gpio_set_all_int_lines(s);
break;
case IMR_ADDR:
s->imr = value;
imx_gpio_update_int(s);
break;
case ISR_ADDR:
s->isr |= ~value;
imx_gpio_set_all_int_lines(s);
break;
case EDGE_SEL_ADDR:
if (s->has_edge_sel) {
s->edge_sel = value;
imx_gpio_set_all_int_lines(s);
} else {
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: EDGE_SEL register not "
"present on this version of GPIO device\n",
TYPE_IMX_GPIO, __func__);
}
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad register at offset %d\n",
TYPE_IMX_GPIO, __func__, (int)offset);
break;
}
return;
}
static const MemoryRegionOps imx_gpio_ops = {
.read = imx_gpio_read,
.write = imx_gpio_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static const VMStateDescription vmstate_imx_gpio = {
.name = TYPE_IMX_GPIO,
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(dr, IMXGPIOState),
VMSTATE_UINT32(gdir, IMXGPIOState),
VMSTATE_UINT32(psr, IMXGPIOState),
VMSTATE_UINT64(icr, IMXGPIOState),
VMSTATE_UINT32(imr, IMXGPIOState),
VMSTATE_UINT32(isr, IMXGPIOState),
VMSTATE_BOOL(has_edge_sel, IMXGPIOState),
VMSTATE_UINT32(edge_sel, IMXGPIOState),
VMSTATE_END_OF_LIST()
}
};
static Property imx_gpio_properties[] = {
DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
DEFINE_PROP_END_OF_LIST(),
};
static void imx_gpio_reset(DeviceState *dev)
{
IMXGPIOState *s = IMX_GPIO(dev);
s->dr = 0;
s->gdir = 0;
s->psr = 0;
s->icr = 0;
s->imr = 0;
s->isr = 0;
s->edge_sel = 0;
imx_gpio_set_all_output_lines(s);
imx_gpio_update_int(s);
}
static void imx_gpio_realize(DeviceState *dev, Error **errp)
{
IMXGPIOState *s = IMX_GPIO(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpio_ops, s,
TYPE_IMX_GPIO, IMX_GPIO_MEM_SIZE);
qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
static void imx_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_gpio_realize;
dc->reset = imx_gpio_reset;
dc->props = imx_gpio_properties;
dc->vmsd = &vmstate_imx_gpio;
dc->desc = "i.MX GPIO controller";
}
static const TypeInfo imx_gpio_info = {
.name = TYPE_IMX_GPIO,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IMXGPIOState),
.class_init = imx_gpio_class_init,
};
static void imx_gpio_register_types(void)
{
type_register_static(&imx_gpio_info);
}
type_init(imx_gpio_register_types)

View File

@ -25,6 +25,7 @@
#include "hw/timer/imx_epit.h"
#include "hw/net/imx_fec.h"
#include "hw/i2c/imx_i2c.h"
#include "hw/gpio/imx_gpio.h"
#include "exec/memory.h"
#define TYPE_FSL_IMX25 "fsl,imx25"
@ -34,6 +35,7 @@
#define FSL_IMX25_NUM_GPTS 4
#define FSL_IMX25_NUM_EPITS 2
#define FSL_IMX25_NUM_I2CS 3
#define FSL_IMX25_NUM_GPIOS 4
typedef struct FslIMX25State {
/*< private >*/
@ -48,6 +50,7 @@ typedef struct FslIMX25State {
IMXEPITState epit[FSL_IMX25_NUM_EPITS];
IMXFECState fec;
IMXI2CState i2c[FSL_IMX25_NUM_I2CS];
IMXGPIOState gpio[FSL_IMX25_NUM_GPIOS];
MemoryRegion rom[2];
MemoryRegion iram;
MemoryRegion iram_alias;
@ -204,6 +207,14 @@ typedef struct FslIMX25State {
#define FSL_IMX25_EPIT1_SIZE 0x4000
#define FSL_IMX25_EPIT2_ADDR 0x53F98000
#define FSL_IMX25_EPIT2_SIZE 0x4000
#define FSL_IMX25_GPIO4_ADDR 0x53F9C000
#define FSL_IMX25_GPIO4_SIZE 0x4000
#define FSL_IMX25_GPIO3_ADDR 0x53FA4000
#define FSL_IMX25_GPIO3_SIZE 0x4000
#define FSL_IMX25_GPIO1_ADDR 0x53FCC000
#define FSL_IMX25_GPIO1_SIZE 0x4000
#define FSL_IMX25_GPIO2_ADDR 0x53FD0000
#define FSL_IMX25_GPIO2_SIZE 0x4000
#define FSL_IMX25_AVIC_ADDR 0x68000000
#define FSL_IMX25_AVIC_SIZE 0x4000
#define FSL_IMX25_IRAM_ADDR 0x78000000
@ -230,5 +241,9 @@ typedef struct FslIMX25State {
#define FSL_IMX25_I2C1_IRQ 3
#define FSL_IMX25_I2C2_IRQ 4
#define FSL_IMX25_I2C3_IRQ 10
#define FSL_IMX25_GPIO1_IRQ 52
#define FSL_IMX25_GPIO2_IRQ 51
#define FSL_IMX25_GPIO3_IRQ 16
#define FSL_IMX25_GPIO4_IRQ 23
#endif /* FSL_IMX25_H */

View File

@ -24,6 +24,7 @@
#include "hw/timer/imx_gpt.h"
#include "hw/timer/imx_epit.h"
#include "hw/i2c/imx_i2c.h"
#include "hw/gpio/imx_gpio.h"
#include "exec/memory.h"
#define TYPE_FSL_IMX31 "fsl,imx31"
@ -32,6 +33,7 @@
#define FSL_IMX31_NUM_UARTS 2
#define FSL_IMX31_NUM_EPITS 2
#define FSL_IMX31_NUM_I2CS 3
#define FSL_IMX31_NUM_GPIOS 3
typedef struct FslIMX31State {
/*< private >*/
@ -45,6 +47,7 @@ typedef struct FslIMX31State {
IMXGPTState gpt;
IMXEPITState epit[FSL_IMX31_NUM_EPITS];
IMXI2CState i2c[FSL_IMX31_NUM_I2CS];
IMXGPIOState gpio[FSL_IMX31_NUM_GPIOS];
MemoryRegion secure_rom;
MemoryRegion rom;
MemoryRegion iram;
@ -77,6 +80,12 @@ typedef struct FslIMX31State {
#define FSL_IMX31_EPIT1_SIZE 0x4000
#define FSL_IMX31_EPIT2_ADDR 0x53F98000
#define FSL_IMX31_EPIT2_SIZE 0x4000
#define FSL_IMX31_GPIO3_ADDR 0x53FA4000
#define FSL_IMX31_GPIO3_SIZE 0x4000
#define FSL_IMX31_GPIO1_ADDR 0x53FCC000
#define FSL_IMX31_GPIO1_SIZE 0x4000
#define FSL_IMX31_GPIO2_ADDR 0x53FD0000
#define FSL_IMX31_GPIO2_SIZE 0x4000
#define FSL_IMX31_AVIC_ADDR 0x68000000
#define FSL_IMX31_AVIC_SIZE 0x100
#define FSL_IMX31_SDRAM0_ADDR 0x80000000
@ -106,5 +115,8 @@ typedef struct FslIMX31State {
#define FSL_IMX31_I2C1_IRQ 10
#define FSL_IMX31_I2C2_IRQ 4
#define FSL_IMX31_I2C3_IRQ 3
#define FSL_IMX31_GPIO1_IRQ 52
#define FSL_IMX31_GPIO2_IRQ 51
#define FSL_IMX31_GPIO3_IRQ 56
#endif /* FSL_IMX31_H */

View File

@ -46,7 +46,7 @@
* number of memory region aliases.
*/
#define XLNX_ZYNQMP_GIC_REGION_SIZE 0x4000
#define XLNX_ZYNQMP_GIC_REGION_SIZE 0x1000
#define XLNX_ZYNQMP_GIC_ALIASES (0x10000 / XLNX_ZYNQMP_GIC_REGION_SIZE - 1)
typedef struct XlnxZynqMPState {

View File

@ -0,0 +1,62 @@
/*
* i.MX processors GPIO registers definition.
*
* Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IMX_GPIO_H_
#define __IMX_GPIO_H_
#include <hw/sysbus.h>
#define TYPE_IMX_GPIO "imx.gpio"
#define IMX_GPIO(obj) OBJECT_CHECK(IMXGPIOState, (obj), TYPE_IMX_GPIO)
#define IMX_GPIO_MEM_SIZE 0x20
/* i.MX GPIO memory map */
#define DR_ADDR 0x00 /* DATA REGISTER */
#define GDIR_ADDR 0x04 /* DIRECTION REGISTER */
#define PSR_ADDR 0x08 /* PAD STATUS REGISTER */
#define ICR1_ADDR 0x0c /* INTERRUPT CONFIGURATION REGISTER 1 */
#define ICR2_ADDR 0x10 /* INTERRUPT CONFIGURATION REGISTER 2 */
#define IMR_ADDR 0x14 /* INTERRUPT MASK REGISTER */
#define ISR_ADDR 0x18 /* INTERRUPT STATUS REGISTER */
#define EDGE_SEL_ADDR 0x1c /* EDGE SEL REGISTER */
#define IMX_GPIO_PIN_COUNT 32
typedef struct IMXGPIOState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
uint32_t dr;
uint32_t gdir;
uint32_t psr;
uint64_t icr;
uint32_t imr;
uint32_t isr;
bool has_edge_sel;
uint32_t edge_sel;
qemu_irq irq;
qemu_irq output[IMX_GPIO_PIN_COUNT];
} IMXGPIOState;
#endif /* __IMX_GPIO_H_ */

View File

@ -222,8 +222,10 @@ typedef struct CPUARMState {
};
uint64_t ttbr1_el[4];
};
uint64_t vttbr_el2; /* Virtualization Translation Table Base. */
/* MMU translation table base control. */
TCR tcr_el[4];
TCR vtcr_el2; /* Virtualization Translation Control. */
uint32_t c2_data; /* MPU data cacheable bits. */
uint32_t c2_insn; /* MPU instruction cacheable bits. */
union { /* MMU domain access control register
@ -383,6 +385,8 @@ typedef struct CPUARMState {
*/
uint64_t c15_ccnt;
uint64_t pmccfiltr_el0; /* Performance Monitor Filter Register */
uint64_t vpidr_el2; /* Virtualization Processor ID Register */
uint64_t vmpidr_el2; /* Virtualization Multiprocessor ID Register */
} cp15;
struct {

View File

@ -325,6 +325,34 @@ void init_cpreg_list(ARMCPU *cpu)
g_list_free(keys);
}
/*
* Some registers are not accessible if EL3.NS=0 and EL3 is using AArch32 but
* they are accessible when EL3 is using AArch64 regardless of EL3.NS.
*
* access_el3_aa32ns: Used to check AArch32 register views.
* access_el3_aa32ns_aa64any: Used to check both AArch32/64 register views.
*/
static CPAccessResult access_el3_aa32ns(CPUARMState *env,
const ARMCPRegInfo *ri)
{
bool secure = arm_is_secure_below_el3(env);
assert(!arm_el_is_aa64(env, 3));
if (secure) {
return CP_ACCESS_TRAP_UNCATEGORIZED;
}
return CP_ACCESS_OK;
}
static CPAccessResult access_el3_aa32ns_aa64any(CPUARMState *env,
const ARMCPRegInfo *ri)
{
if (!arm_el_is_aa64(env, 3)) {
return access_el3_aa32ns(env, ri);
}
return CP_ACCESS_OK;
}
static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@ -2185,6 +2213,20 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
raw_write(env, ri, value);
}
static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
CPUState *cs = CPU(cpu);
/* Accesses to VTTBR may change the VMID so we must flush the TLB. */
if (raw_read(env, ri) != value) {
tlb_flush_by_mmuidx(cs, ARMMMUIdx_S12NSE1, ARMMMUIdx_S12NSE0,
ARMMMUIdx_S2NS, -1);
raw_write(env, ri, value);
}
}
static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
{ .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_ALIAS,
@ -2403,7 +2445,19 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
REGINFO_SENTINEL
};
static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = arm_env_get_cpu(env);
unsigned int cur_el = arm_current_el(env);
bool secure = arm_is_secure(env);
if (arm_feature(&cpu->env, ARM_FEATURE_EL2) && !secure && cur_el == 1) {
return env->cp15.vpidr_el2;
}
return raw_read(env, ri);
}
static uint64_t mpidr_read_val(CPUARMState *env)
{
ARMCPU *cpu = ARM_CPU(arm_env_get_cpu(env));
uint64_t mpidr = cpu->mp_affinity;
@ -2421,6 +2475,17 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
return mpidr;
}
static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
unsigned int cur_el = arm_current_el(env);
bool secure = arm_is_secure(env);
if (arm_feature(env, ARM_FEATURE_EL2) && !secure && cur_el == 1) {
return env->cp15.vmpidr_el2;
}
return mpidr_read_val(env);
}
static const ARMCPRegInfo mpidr_cp_reginfo[] = {
{ .name = "MPIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5,
@ -3112,6 +3177,17 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
{ .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "VTCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2,
.access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
.type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "VTTBR", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 6, .crm = 2,
.access = PL2_RW, .accessfn = access_el3_aa32ns,
.type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
{ .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
@ -3246,6 +3322,24 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
.access = PL2_RW, .writefn = vmsa_tcr_el1_write,
.resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
.fieldoffset = offsetof(CPUARMState, cp15.tcr_el[2]) },
{ .name = "VTCR", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2,
.access = PL2_RW, .accessfn = access_el3_aa32ns,
.fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) },
{ .name = "VTCR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) },
{ .name = "VTTBR", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 6, .crm = 2,
.type = ARM_CP_64BIT | ARM_CP_ALIAS,
.access = PL2_RW, .accessfn = access_el3_aa32ns,
.fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2),
.writefn = vttbr_write },
{ .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0,
.access = PL2_RW, .writefn = vttbr_write,
.fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2) },
{ .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
.access = PL2_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
@ -4050,6 +4144,30 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, v8_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_EL2)) {
uint64_t vmpidr_def = mpidr_read_val(env);
ARMCPRegInfo vpidr_regs[] = {
{ .name = "VPIDR", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
.access = PL2_RW, .accessfn = access_el3_aa32ns,
.resetvalue = cpu->midr,
.fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) },
{ .name = "VPIDR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
.access = PL2_RW, .resetvalue = cpu->midr,
.fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) },
{ .name = "VMPIDR", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
.access = PL2_RW, .accessfn = access_el3_aa32ns,
.resetvalue = vmpidr_def,
.fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) },
{ .name = "VMPIDR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
.access = PL2_RW,
.resetvalue = vmpidr_def,
.fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) },
REGINFO_SENTINEL
};
define_arm_cp_regs(cpu, vpidr_regs);
define_arm_cp_regs(cpu, el2_cp_reginfo);
/* RVBAR_EL2 is only implemented if EL2 is the highest EL */
if (!arm_feature(env, ARM_FEATURE_EL3)) {
@ -4065,6 +4183,23 @@ void register_cp_regs_for_features(ARMCPU *cpu)
* register the no_el2 reginfos.
*/
if (arm_feature(env, ARM_FEATURE_EL3)) {
/* When EL3 exists but not EL2, VPIDR and VMPIDR take the value
* of MIDR_EL1 and MPIDR_EL1.
*/
ARMCPRegInfo vpidr_regs[] = {
{ .name = "VPIDR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
.access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
.type = ARM_CP_CONST, .resetvalue = cpu->midr,
.fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) },
{ .name = "VMPIDR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
.access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
.type = ARM_CP_NO_RAW,
.writefn = arm_cp_write_ignore, .readfn = mpidr_read },
REGINFO_SENTINEL
};
define_arm_cp_regs(cpu, vpidr_regs);
define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo);
}
}
@ -4142,6 +4277,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = CP_ANY,
.access = PL1_R, .resetvalue = cpu->midr,
.writefn = arm_cp_write_ignore, .raw_writefn = raw_write,
.readfn = midr_read,
.fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid),
.type = ARM_CP_OVERRIDE },
/* crn = 0 op1 = 0 crm = 3..7 : currently unassigned; we RAZ. */
@ -4165,7 +4301,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
{ .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr },
.access = PL1_R, .type = ARM_CP_NO_RAW, .resetvalue = cpu->midr,
.fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid),
.readfn = midr_read },
/* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */
{ .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
@ -5741,8 +5879,7 @@ static inline bool regime_translation_disabled(CPUARMState *env,
static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
{
if (mmu_idx == ARMMMUIdx_S2NS) {
/* TODO: return VTCR_EL2 */
g_assert_not_reached();
return &env->cp15.vtcr_el2;
}
return &env->cp15.tcr_el[regime_el(env, mmu_idx)];
}
@ -5752,8 +5889,7 @@ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx,
int ttbrn)
{
if (mmu_idx == ARMMMUIdx_S2NS) {
/* TODO: return VTTBR_EL2 */
g_assert_not_reached();
return env->cp15.vttbr_el2;
}
if (ttbrn == 0) {
return env->cp15.ttbr0_el[regime_el(env, mmu_idx)];
@ -6275,7 +6411,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
/* Read an LPAE long-descriptor translation table. */
MMUFaultType fault_type = translation_fault;
uint32_t level = 1;
uint32_t epd;
uint32_t epd = 0;
int32_t tsz;
uint32_t tg;
uint64_t ttbr;
@ -6301,7 +6437,9 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
if (arm_el_is_aa64(env, el)) {
va_size = 64;
if (el > 1) {
tbi = extract64(tcr->raw_tcr, 20, 1);
if (mmu_idx != ARMMMUIdx_S2NS) {
tbi = extract64(tcr->raw_tcr, 20, 1);
}
} else {
if (extract64(address, 55, 1)) {
tbi = extract64(tcr->raw_tcr, 38, 1);
@ -6367,7 +6505,9 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
*/
if (ttbr_select == 0) {
ttbr = regime_ttbr(env, mmu_idx, 0);
epd = extract32(tcr->raw_tcr, 7, 1);
if (el < 2) {
epd = extract32(tcr->raw_tcr, 7, 1);
}
tsz = t0sz;
tg = extract32(tcr->raw_tcr, 14, 2);

View File

@ -40,16 +40,9 @@
static TCGv_i64 cpu_X[32];
static TCGv_i64 cpu_pc;
static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
/* Load/store exclusive handling */
static TCGv_i64 cpu_exclusive_addr;
static TCGv_i64 cpu_exclusive_val;
static TCGv_i64 cpu_exclusive_high;
#ifdef CONFIG_USER_ONLY
static TCGv_i64 cpu_exclusive_test;
static TCGv_i32 cpu_exclusive_info;
#endif
static const char *regnames[] = {
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
@ -105,23 +98,8 @@ void a64_translate_init(void)
regnames[i]);
}
cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
cpu_exclusive_addr = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUARMState, exclusive_val), "exclusive_val");
cpu_exclusive_high = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUARMState, exclusive_high), "exclusive_high");
#ifdef CONFIG_USER_ONLY
cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUARMState, exclusive_test), "exclusive_test");
cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUARMState, exclusive_info), "exclusive_info");
#endif
}
static inline ARMMMUIdx get_a64_user_mem_index(DisasContext *s)
@ -189,6 +167,31 @@ void gen_a64_set_pc_im(uint64_t val)
tcg_gen_movi_i64(cpu_pc, val);
}
typedef struct DisasCompare64 {
TCGCond cond;
TCGv_i64 value;
} DisasCompare64;
static void a64_test_cc(DisasCompare64 *c64, int cc)
{
DisasCompare c32;
arm_test_cc(&c32, cc);
/* Sign-extend the 32-bit value so that the GE/LT comparisons work
* properly. The NE/EQ comparisons are also fine with this choice. */
c64->cond = c32.cond;
c64->value = tcg_temp_new_i64();
tcg_gen_ext_i32_i64(c64->value, c32.value);
arm_free_cc(&c32);
}
static void a64_free_cc(DisasCompare64 *c64)
{
tcg_temp_free_i64(c64->value);
}
static void gen_exception_internal(int excp)
{
TCGv_i32 tcg_excp = tcg_const_i32(excp);
@ -526,13 +529,8 @@ static TCGv_ptr get_fpstatus_ptr(void)
*/
static inline void gen_set_NZ64(TCGv_i64 result)
{
TCGv_i64 flag = tcg_temp_new_i64();
tcg_gen_setcondi_i64(TCG_COND_NE, flag, result, 0);
tcg_gen_extrl_i64_i32(cpu_ZF, flag);
tcg_gen_shri_i64(flag, result, 32);
tcg_gen_extrl_i64_i32(cpu_NF, flag);
tcg_temp_free_i64(flag);
tcg_gen_extr_i64_i32(cpu_ZF, cpu_NF, result);
tcg_gen_or_i32(cpu_ZF, cpu_ZF, cpu_NF);
}
/* Set NZCV as for a logical operation: NZ as per result, CV cleared. */
@ -542,7 +540,7 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result)
gen_set_NZ64(result);
} else {
tcg_gen_extrl_i64_i32(cpu_ZF, result);
tcg_gen_extrl_i64_i32(cpu_NF, result);
tcg_gen_mov_i32(cpu_NF, cpu_ZF);
}
tcg_gen_movi_i32(cpu_CF, 0);
tcg_gen_movi_i32(cpu_VF, 0);
@ -568,8 +566,7 @@ static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
tcg_gen_xor_i64(tmp, t0, t1);
tcg_gen_andc_i64(flag, flag, tmp);
tcg_temp_free_i64(tmp);
tcg_gen_shri_i64(flag, flag, 32);
tcg_gen_extrl_i64_i32(cpu_VF, flag);
tcg_gen_extrh_i64_i32(cpu_VF, flag);
tcg_gen_mov_i64(dest, result);
tcg_temp_free_i64(result);
@ -617,8 +614,7 @@ static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
tcg_gen_xor_i64(tmp, t0, t1);
tcg_gen_and_i64(flag, flag, tmp);
tcg_temp_free_i64(tmp);
tcg_gen_shri_i64(flag, flag, 32);
tcg_gen_extrl_i64_i32(cpu_VF, flag);
tcg_gen_extrh_i64_i32(cpu_VF, flag);
tcg_gen_mov_i64(dest, result);
tcg_temp_free_i64(flag);
tcg_temp_free_i64(result);
@ -677,8 +673,7 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
tcg_gen_xor_i64(vf_64, result, t0);
tcg_gen_xor_i64(tmp, t0, t1);
tcg_gen_andc_i64(vf_64, vf_64, tmp);
tcg_gen_shri_i64(vf_64, vf_64, 32);
tcg_gen_extrl_i64_i32(cpu_VF, vf_64);
tcg_gen_extrh_i64_i32(cpu_VF, vf_64);
tcg_gen_mov_i64(dest, result);
@ -3012,9 +3007,51 @@ static void disas_bitfield(DisasContext *s, uint32_t insn)
}
tcg_rd = cpu_reg(s, rd);
tcg_tmp = read_cpu_reg(s, rn, sf);
/* OPTME: probably worth recognizing common cases of ext{8,16,32}{u,s} */
/* Suppress the zero-extend for !sf. Since RI and SI are constrained
to be smaller than bitsize, we'll never reference data outside the
low 32-bits anyway. */
tcg_tmp = read_cpu_reg(s, rn, 1);
/* Recognize the common aliases. */
if (opc == 0) { /* SBFM */
if (ri == 0) {
if (si == 7) { /* SXTB */
tcg_gen_ext8s_i64(tcg_rd, tcg_tmp);
goto done;
} else if (si == 15) { /* SXTH */
tcg_gen_ext16s_i64(tcg_rd, tcg_tmp);
goto done;
} else if (si == 31) { /* SXTW */
tcg_gen_ext32s_i64(tcg_rd, tcg_tmp);
goto done;
}
}
if (si == 63 || (si == 31 && ri <= si)) { /* ASR */
if (si == 31) {
tcg_gen_ext32s_i64(tcg_tmp, tcg_tmp);
}
tcg_gen_sari_i64(tcg_rd, tcg_tmp, ri);
goto done;
}
} else if (opc == 2) { /* UBFM */
if (ri == 0) { /* UXTB, UXTH, plus non-canonical AND */
tcg_gen_andi_i64(tcg_rd, tcg_tmp, bitmask64(si + 1));
return;
}
if (si == 63 || (si == 31 && ri <= si)) { /* LSR */
if (si == 31) {
tcg_gen_ext32u_i64(tcg_tmp, tcg_tmp);
}
tcg_gen_shri_i64(tcg_rd, tcg_tmp, ri);
return;
}
if (si + 1 == ri && si != bitsize - 1) { /* LSL */
int shift = bitsize - 1 - si;
tcg_gen_shli_i64(tcg_rd, tcg_tmp, shift);
goto done;
}
}
if (opc != 1) { /* SBFM or UBFM */
tcg_gen_movi_i64(tcg_rd, 0);
@ -3039,6 +3076,7 @@ static void disas_bitfield(DisasContext *s, uint32_t insn)
tcg_gen_sari_i64(tcg_rd, tcg_rd, 64 - (pos + len));
}
done:
if (!sf) { /* zero extend final result */
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
@ -3071,17 +3109,7 @@ static void disas_extract(DisasContext *s, uint32_t insn)
tcg_rd = cpu_reg(s, rd);
if (imm) {
/* OPTME: we can special case rm==rn as a rotate */
tcg_rm = read_cpu_reg(s, rm, sf);
tcg_rn = read_cpu_reg(s, rn, sf);
tcg_gen_shri_i64(tcg_rm, tcg_rm, imm);
tcg_gen_shli_i64(tcg_rn, tcg_rn, bitsize - imm);
tcg_gen_or_i64(tcg_rd, tcg_rm, tcg_rn);
if (!sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
} else {
if (unlikely(imm == 0)) {
/* tcg shl_i32/shl_i64 is undefined for 32/64 bit shifts,
* so an extract from bit 0 is a special case.
*/
@ -3090,8 +3118,27 @@ static void disas_extract(DisasContext *s, uint32_t insn)
} else {
tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rm));
}
} else if (rm == rn) { /* ROR */
tcg_rm = cpu_reg(s, rm);
if (sf) {
tcg_gen_rotri_i64(tcg_rd, tcg_rm, imm);
} else {
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(tmp, tcg_rm);
tcg_gen_rotri_i32(tmp, tmp, imm);
tcg_gen_extu_i32_i64(tcg_rd, tmp);
tcg_temp_free_i32(tmp);
}
} else {
tcg_rm = read_cpu_reg(s, rm, sf);
tcg_rn = read_cpu_reg(s, rn, sf);
tcg_gen_shri_i64(tcg_rm, tcg_rm, imm);
tcg_gen_shli_i64(tcg_rn, tcg_rn, bitsize - imm);
tcg_gen_or_i64(tcg_rd, tcg_rm, tcg_rn);
if (!sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
}
}
}
@ -3567,8 +3614,9 @@ static void disas_adc_sbc(DisasContext *s, uint32_t insn)
static void disas_cc(DisasContext *s, uint32_t insn)
{
unsigned int sf, op, y, cond, rn, nzcv, is_imm;
TCGLabel *label_continue = NULL;
TCGv_i32 tcg_t0, tcg_t1, tcg_t2;
TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
DisasCompare c;
if (!extract32(insn, 29, 1)) {
unallocated_encoding(s);
@ -3586,19 +3634,13 @@ static void disas_cc(DisasContext *s, uint32_t insn)
rn = extract32(insn, 5, 5);
nzcv = extract32(insn, 0, 4);
if (cond < 0x0e) { /* not always */
TCGLabel *label_match = gen_new_label();
label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
tcg_tmp = tcg_temp_new_i64();
tcg_gen_movi_i64(tcg_tmp, nzcv << 28);
gen_set_nzcv(tcg_tmp);
tcg_temp_free_i64(tcg_tmp);
tcg_gen_br(label_continue);
gen_set_label(label_match);
}
/* match, or condition is always */
/* Set T0 = !COND. */
tcg_t0 = tcg_temp_new_i32();
arm_test_cc(&c, cond);
tcg_gen_setcondi_i32(tcg_invert_cond(c.cond), tcg_t0, c.value, 0);
arm_free_cc(&c);
/* Load the arguments for the new comparison. */
if (is_imm) {
tcg_y = new_tmp_a64(s);
tcg_gen_movi_i64(tcg_y, y);
@ -3607,6 +3649,7 @@ static void disas_cc(DisasContext *s, uint32_t insn)
}
tcg_rn = cpu_reg(s, rn);
/* Set the flags for the new comparison. */
tcg_tmp = tcg_temp_new_i64();
if (op) {
gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
@ -3615,9 +3658,55 @@ static void disas_cc(DisasContext *s, uint32_t insn)
}
tcg_temp_free_i64(tcg_tmp);
if (cond < 0x0e) { /* continue */
gen_set_label(label_continue);
/* If COND was false, force the flags to #nzcv. Compute two masks
* to help with this: T1 = (COND ? 0 : -1), T2 = (COND ? -1 : 0).
* For tcg hosts that support ANDC, we can make do with just T1.
* In either case, allow the tcg optimizer to delete any unused mask.
*/
tcg_t1 = tcg_temp_new_i32();
tcg_t2 = tcg_temp_new_i32();
tcg_gen_neg_i32(tcg_t1, tcg_t0);
tcg_gen_subi_i32(tcg_t2, tcg_t0, 1);
if (nzcv & 8) { /* N */
tcg_gen_or_i32(cpu_NF, cpu_NF, tcg_t1);
} else {
if (TCG_TARGET_HAS_andc_i32) {
tcg_gen_andc_i32(cpu_NF, cpu_NF, tcg_t1);
} else {
tcg_gen_and_i32(cpu_NF, cpu_NF, tcg_t2);
}
}
if (nzcv & 4) { /* Z */
if (TCG_TARGET_HAS_andc_i32) {
tcg_gen_andc_i32(cpu_ZF, cpu_ZF, tcg_t1);
} else {
tcg_gen_and_i32(cpu_ZF, cpu_ZF, tcg_t2);
}
} else {
tcg_gen_or_i32(cpu_ZF, cpu_ZF, tcg_t0);
}
if (nzcv & 2) { /* C */
tcg_gen_or_i32(cpu_CF, cpu_CF, tcg_t0);
} else {
if (TCG_TARGET_HAS_andc_i32) {
tcg_gen_andc_i32(cpu_CF, cpu_CF, tcg_t1);
} else {
tcg_gen_and_i32(cpu_CF, cpu_CF, tcg_t2);
}
}
if (nzcv & 1) { /* V */
tcg_gen_or_i32(cpu_VF, cpu_VF, tcg_t1);
} else {
if (TCG_TARGET_HAS_andc_i32) {
tcg_gen_andc_i32(cpu_VF, cpu_VF, tcg_t1);
} else {
tcg_gen_and_i32(cpu_VF, cpu_VF, tcg_t2);
}
}
tcg_temp_free_i32(tcg_t0);
tcg_temp_free_i32(tcg_t1);
tcg_temp_free_i32(tcg_t2);
}
/* C3.5.6 Conditional select
@ -3629,7 +3718,8 @@ static void disas_cc(DisasContext *s, uint32_t insn)
static void disas_cond_select(DisasContext *s, uint32_t insn)
{
unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
TCGv_i64 tcg_rd, tcg_src;
TCGv_i64 tcg_rd, zero;
DisasCompare64 c;
if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
/* S == 1 or op2<1> == 1 */
@ -3644,48 +3734,35 @@ static void disas_cond_select(DisasContext *s, uint32_t insn)
rn = extract32(insn, 5, 5);
rd = extract32(insn, 0, 5);
if (rd == 31) {
/* silly no-op write; until we use movcond we must special-case
* this to avoid a dead temporary across basic blocks.
*/
return;
}
tcg_rd = cpu_reg(s, rd);
if (cond >= 0x0e) { /* condition "always" */
tcg_src = read_cpu_reg(s, rn, sf);
tcg_gen_mov_i64(tcg_rd, tcg_src);
a64_test_cc(&c, cond);
zero = tcg_const_i64(0);
if (rn == 31 && rm == 31 && (else_inc ^ else_inv)) {
/* CSET & CSETM. */
tcg_gen_setcond_i64(tcg_invert_cond(c.cond), tcg_rd, c.value, zero);
if (else_inv) {
tcg_gen_neg_i64(tcg_rd, tcg_rd);
}
} else {
/* OPTME: we could use movcond here, at the cost of duplicating
* a lot of the arm_gen_test_cc() logic.
*/
TCGLabel *label_match = gen_new_label();
TCGLabel *label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
tcg_src = cpu_reg(s, rm);
TCGv_i64 t_true = cpu_reg(s, rn);
TCGv_i64 t_false = read_cpu_reg(s, rm, 1);
if (else_inv && else_inc) {
tcg_gen_neg_i64(tcg_rd, tcg_src);
tcg_gen_neg_i64(t_false, t_false);
} else if (else_inv) {
tcg_gen_not_i64(tcg_rd, tcg_src);
tcg_gen_not_i64(t_false, t_false);
} else if (else_inc) {
tcg_gen_addi_i64(tcg_rd, tcg_src, 1);
} else {
tcg_gen_mov_i64(tcg_rd, tcg_src);
tcg_gen_addi_i64(t_false, t_false, 1);
}
if (!sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
tcg_gen_br(label_continue);
/* match: */
gen_set_label(label_match);
tcg_src = read_cpu_reg(s, rn, sf);
tcg_gen_mov_i64(tcg_rd, tcg_src);
/* continue: */
gen_set_label(label_continue);
tcg_gen_movcond_i64(c.cond, tcg_rd, c.value, zero, t_true, t_false);
}
tcg_temp_free_i64(zero);
a64_free_cc(&c);
if (!sf) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
}
@ -4172,20 +4249,6 @@ static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
}
}
/* copy src FP register to dst FP register; type specifies single or double */
static void gen_mov_fp2fp(DisasContext *s, int type, int dst, int src)
{
if (type) {
TCGv_i64 v = read_fp_dreg(s, src);
write_fp_dreg(s, dst, v);
tcg_temp_free_i64(v);
} else {
TCGv_i32 v = read_fp_sreg(s, src);
write_fp_sreg(s, dst, v);
tcg_temp_free_i32(v);
}
}
/* C3.6.24 Floating point conditional select
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
* +---+---+---+-----------+------+---+------+------+-----+------+------+
@ -4195,7 +4258,8 @@ static void gen_mov_fp2fp(DisasContext *s, int type, int dst, int src)
static void disas_fp_csel(DisasContext *s, uint32_t insn)
{
unsigned int mos, type, rm, cond, rn, rd;
TCGLabel *label_continue = NULL;
TCGv_i64 t_true, t_false, t_zero;
DisasCompare64 c;
mos = extract32(insn, 29, 3);
type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
@ -4213,21 +4277,23 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn)
return;
}
if (cond < 0x0e) { /* not always */
TCGLabel *label_match = gen_new_label();
label_continue = gen_new_label();
arm_gen_test_cc(cond, label_match);
/* nomatch: */
gen_mov_fp2fp(s, type, rd, rm);
tcg_gen_br(label_continue);
gen_set_label(label_match);
}
/* Zero extend sreg inputs to 64 bits now. */
t_true = tcg_temp_new_i64();
t_false = tcg_temp_new_i64();
read_vec_element(s, t_true, rn, 0, type ? MO_64 : MO_32);
read_vec_element(s, t_false, rm, 0, type ? MO_64 : MO_32);
gen_mov_fp2fp(s, type, rd, rn);
a64_test_cc(&c, cond);
t_zero = tcg_const_i64(0);
tcg_gen_movcond_i64(c.cond, t_true, c.value, t_zero, t_true, t_false);
tcg_temp_free_i64(t_zero);
tcg_temp_free_i64(t_false);
a64_free_cc(&c);
if (cond < 0x0e) { /* continue */
gen_set_label(label_continue);
}
/* Note that sregs write back zeros to the high bits,
and we've already done the zero-extension. */
write_fp_dreg(s, rd, t_true);
tcg_temp_free_i64(t_true);
}
/* C3.6.25 Floating-point data-processing (1 source) - single precision */
@ -7701,10 +7767,8 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
} else {
TCGv_i32 tcg_lo = tcg_temp_new_i32();
TCGv_i32 tcg_hi = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(tcg_lo, tcg_op);
tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, cpu_env);
tcg_gen_shri_i64(tcg_op, tcg_op, 32);
tcg_gen_extrl_i64_i32(tcg_hi, tcg_op);
gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, cpu_env);
tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
tcg_temp_free_i32(tcg_lo);
@ -8610,16 +8674,10 @@ static void handle_3rd_wide(DisasContext *s, int is_q, int is_u, int size,
}
}
static void do_narrow_high_u32(TCGv_i32 res, TCGv_i64 in)
{
tcg_gen_shri_i64(in, in, 32);
tcg_gen_extrl_i64_i32(res, in);
}
static void do_narrow_round_high_u32(TCGv_i32 res, TCGv_i64 in)
{
tcg_gen_addi_i64(in, in, 1U << 31);
do_narrow_high_u32(res, in);
tcg_gen_extrh_i64_i32(res, in);
}
static void handle_3rd_narrowing(DisasContext *s, int is_q, int is_u, int size,
@ -8638,7 +8696,7 @@ static void handle_3rd_narrowing(DisasContext *s, int is_q, int is_u, int size,
gen_helper_neon_narrow_round_high_u8 },
{ gen_helper_neon_narrow_high_u16,
gen_helper_neon_narrow_round_high_u16 },
{ do_narrow_high_u32, do_narrow_round_high_u32 },
{ tcg_gen_extrh_i64_i32, do_narrow_round_high_u32 },
};
NeonGenNarrowFn *gennarrow = narrowfns[size][is_u];

View File

@ -64,12 +64,12 @@ TCGv_ptr cpu_env;
/* We reuse the same 64-bit temporaries for efficiency. */
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
static TCGv_i32 cpu_R[16];
static TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
static TCGv_i64 cpu_exclusive_addr;
static TCGv_i64 cpu_exclusive_val;
TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
TCGv_i64 cpu_exclusive_addr;
TCGv_i64 cpu_exclusive_val;
#ifdef CONFIG_USER_ONLY
static TCGv_i64 cpu_exclusive_test;
static TCGv_i32 cpu_exclusive_info;
TCGv_i64 cpu_exclusive_test;
TCGv_i32 cpu_exclusive_info;
#endif
/* FIXME: These should be removed. */
@ -738,81 +738,113 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
#undef PAS_OP
/*
* generate a conditional branch based on ARM condition code cc.
* Generate a conditional based on ARM condition code cc.
* This is common between ARM and Aarch64 targets.
*/
void arm_gen_test_cc(int cc, TCGLabel *label)
void arm_test_cc(DisasCompare *cmp, int cc)
{
TCGv_i32 tmp;
TCGLabel *inv;
TCGv_i32 value;
TCGCond cond;
bool global = true;
switch (cc) {
case 0: /* eq: Z */
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label);
break;
case 1: /* ne: !Z */
tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label);
cond = TCG_COND_EQ;
value = cpu_ZF;
break;
case 2: /* cs: C */
tcg_gen_brcondi_i32(TCG_COND_NE, cpu_CF, 0, label);
break;
case 3: /* cc: !C */
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label);
cond = TCG_COND_NE;
value = cpu_CF;
break;
case 4: /* mi: N */
tcg_gen_brcondi_i32(TCG_COND_LT, cpu_NF, 0, label);
break;
case 5: /* pl: !N */
tcg_gen_brcondi_i32(TCG_COND_GE, cpu_NF, 0, label);
cond = TCG_COND_LT;
value = cpu_NF;
break;
case 6: /* vs: V */
tcg_gen_brcondi_i32(TCG_COND_LT, cpu_VF, 0, label);
break;
case 7: /* vc: !V */
tcg_gen_brcondi_i32(TCG_COND_GE, cpu_VF, 0, label);
cond = TCG_COND_LT;
value = cpu_VF;
break;
case 8: /* hi: C && !Z */
inv = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, inv);
tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label);
gen_set_label(inv);
break;
case 9: /* ls: !C || Z */
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label);
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label);
case 9: /* ls: !C || Z -> !(C && !Z) */
cond = TCG_COND_NE;
value = tcg_temp_new_i32();
global = false;
/* CF is 1 for C, so -CF is an all-bits-set mask for C;
ZF is non-zero for !Z; so AND the two subexpressions. */
tcg_gen_neg_i32(value, cpu_CF);
tcg_gen_and_i32(value, value, cpu_ZF);
break;
case 10: /* ge: N == V -> N ^ V == 0 */
tmp = tcg_temp_new_i32();
tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
tcg_temp_free_i32(tmp);
break;
case 11: /* lt: N != V -> N ^ V != 0 */
tmp = tcg_temp_new_i32();
tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
tcg_temp_free_i32(tmp);
/* Since we're only interested in the sign bit, == 0 is >= 0. */
cond = TCG_COND_GE;
value = tcg_temp_new_i32();
global = false;
tcg_gen_xor_i32(value, cpu_VF, cpu_NF);
break;
case 12: /* gt: !Z && N == V */
inv = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, inv);
tmp = tcg_temp_new_i32();
tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
tcg_temp_free_i32(tmp);
gen_set_label(inv);
break;
case 13: /* le: Z || N != V */
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label);
tmp = tcg_temp_new_i32();
tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
tcg_temp_free_i32(tmp);
cond = TCG_COND_NE;
value = tcg_temp_new_i32();
global = false;
/* (N == V) is equal to the sign bit of ~(NF ^ VF). Propagate
* the sign bit then AND with ZF to yield the result. */
tcg_gen_xor_i32(value, cpu_VF, cpu_NF);
tcg_gen_sari_i32(value, value, 31);
tcg_gen_andc_i32(value, cpu_ZF, value);
break;
case 14: /* always */
case 15: /* always */
/* Use the ALWAYS condition, which will fold early.
* It doesn't matter what we use for the value. */
cond = TCG_COND_ALWAYS;
value = cpu_ZF;
goto no_invert;
default:
fprintf(stderr, "Bad condition code 0x%x\n", cc);
abort();
}
if (cc & 1) {
cond = tcg_invert_cond(cond);
}
no_invert:
cmp->cond = cond;
cmp->value = value;
cmp->value_global = global;
}
void arm_free_cc(DisasCompare *cmp)
{
if (!cmp->value_global) {
tcg_temp_free_i32(cmp->value);
}
}
void arm_jump_cc(DisasCompare *cmp, TCGLabel *label)
{
tcg_gen_brcondi_i32(cmp->cond, cmp->value, 0, label);
}
void arm_gen_test_cc(int cc, TCGLabel *label)
{
DisasCompare cmp;
arm_test_cc(&cmp, cc);
arm_jump_cc(&cmp, label);
arm_free_cc(&cmp);
}
static const uint8_t table_logic_cc[16] = {

View File

@ -63,7 +63,21 @@ typedef struct DisasContext {
TCGv_i64 tmp_a64[TMP_A64_MAX];
} DisasContext;
typedef struct DisasCompare {
TCGCond cond;
TCGv_i32 value;
bool value_global;
} DisasCompare;
/* Share the TCG temporaries common between 32 and 64 bit modes. */
extern TCGv_ptr cpu_env;
extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
extern TCGv_i64 cpu_exclusive_addr;
extern TCGv_i64 cpu_exclusive_val;
#ifdef CONFIG_USER_ONLY
extern TCGv_i64 cpu_exclusive_test;
extern TCGv_i32 cpu_exclusive_info;
#endif
static inline int arm_dc_feature(DisasContext *dc, int feature)
{
@ -136,6 +150,9 @@ static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
}
#endif
void arm_test_cc(DisasCompare *cmp, int cc);
void arm_free_cc(DisasCompare *cmp);
void arm_jump_cc(DisasCompare *cmp, TCGLabel *label);
void arm_gen_test_cc(int cc, TCGLabel *label);
#endif /* TARGET_ARM_TRANSLATE_H */