aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.target1
-rw-r--r--exec-all.h2
-rw-r--r--fpu/softfloat.c4
-rw-r--r--gdbstub.c3
-rw-r--r--hw/arm_mptimer.c3
-rw-r--r--hw/realview.c83
-rw-r--r--hw/versatile_i2c.c105
-rw-r--r--hw/versatilepb.c22
-rw-r--r--qtest.h18
-rw-r--r--target-arm/cpu-qom.h37
-rw-r--r--target-arm/cpu.c625
-rw-r--r--target-arm/cpu.h10
-rw-r--r--target-arm/helper.c446
-rw-r--r--target-sparc/cpu.c4
-rw-r--r--target-xtensa/translate.c2
-rw-r--r--tci.c4
-rw-r--r--tests/Makefile3
-rw-r--r--tests/m48t59-test.c259
-rw-r--r--tests/rtc-test.c17
-rw-r--r--tests/tcg/xtensa/test_loop.S36
20 files changed, 1185 insertions, 499 deletions
diff --git a/Makefile.target b/Makefile.target
index a0540cd663..7eda443bc0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -365,6 +365,7 @@ endif
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
+obj-arm-y += versatile_i2c.o
obj-arm-y += cadence_uart.o
obj-arm-y += cadence_ttc.o
obj-arm-y += cadence_gem.o
diff --git a/exec-all.h b/exec-all.h
index 6bcc07538f..937d3cef01 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -283,7 +283,7 @@ extern int tb_invalidated_flag;
/* Alpha and SH4 user mode emulations and Softmmu call GETPC().
For all others, GETPC remains undefined (which makes TCI a little faster. */
# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4)
-extern void *tci_tb_ptr;
+extern uintptr_t tci_tb_ptr;
# define GETPC() tci_tb_ptr
# endif
#elif defined(__s390__) && !defined(__s390x__)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index d37090ac53..9e1b5f9cab 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2219,7 +2219,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
- return c ^ (signflip << 31);
+ return make_float32(float32_val(c) ^ (signflip << 31));
}
if (aExp == 0) {
@@ -3772,7 +3772,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
- return c ^ ((uint64_t)signflip << 63);
+ return make_float64(float64_val(c) ^ ((uint64_t)signflip << 63));
}
if (aExp == 0) {
diff --git a/gdbstub.c b/gdbstub.c
index 6a7e2c4934..6a77a6696b 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1903,8 +1903,8 @@ static void gdb_breakpoint_remove_all(void)
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
{
-#if defined(TARGET_I386)
cpu_synchronize_state(s->c_cpu);
+#if defined(TARGET_I386)
s->c_cpu->eip = pc;
#elif defined (TARGET_PPC)
s->c_cpu->nip = pc;
@@ -1929,7 +1929,6 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
#elif defined (TARGET_ALPHA)
s->c_cpu->pc = pc;
#elif defined (TARGET_S390X)
- cpu_synchronize_state(s->c_cpu);
s->c_cpu->psw.addr = pc;
#elif defined (TARGET_LM32)
s->c_cpu->pc = pc;
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index df7fb4c9bd..fe43cbb5f1 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -228,6 +228,9 @@ static void timerblock_reset(timerblock *tb)
tb->control = 0;
tb->status = 0;
tb->tick = 0;
+ if (tb->timer) {
+ qemu_del_timer(tb->timer);
+ }
}
static void arm_mptimer_reset(DeviceState *dev)
diff --git a/hw/realview.c b/hw/realview.c
index cf55204c96..ecf470179a 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -15,91 +15,13 @@
#include "net.h"
#include "sysemu.h"
#include "boards.h"
-#include "bitbang_i2c.h"
+#include "i2c.h"
#include "blockdev.h"
#include "exec-memory.h"
#define SMP_BOOT_ADDR 0xe0000000
#define SMP_BOOTREG_ADDR 0x10000030
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- bitbang_i2c_interface *bitbang;
- int out;
- int in;
-} RealViewI2CState;
-
-static uint64_t realview_i2c_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- RealViewI2CState *s = (RealViewI2CState *)opaque;
-
- if (offset == 0) {
- return (s->out & 1) | (s->in << 1);
- } else {
- hw_error("realview_i2c_read: Bad offset 0x%x\n", (int)offset);
- return -1;
- }
-}
-
-static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- RealViewI2CState *s = (RealViewI2CState *)opaque;
-
- switch (offset) {
- case 0:
- s->out |= value & 3;
- break;
- case 4:
- s->out &= ~value;
- break;
- default:
- hw_error("realview_i2c_write: Bad offset 0x%x\n", (int)offset);
- }
- bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
- s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
-}
-
-static const MemoryRegionOps realview_i2c_ops = {
- .read = realview_i2c_read,
- .write = realview_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int realview_i2c_init(SysBusDevice *dev)
-{
- RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev);
- i2c_bus *bus;
-
- bus = i2c_init_bus(&dev->qdev, "i2c");
- s->bitbang = bitbang_i2c_init(bus);
- memory_region_init_io(&s->iomem, &realview_i2c_ops, s,
- "realview-i2c", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static void realview_i2c_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = realview_i2c_init;
-}
-
-static TypeInfo realview_i2c_info = {
- .name = "realview_i2c",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(RealViewI2CState),
- .class_init = realview_i2c_class_init,
-};
-
-static void realview_register_types(void)
-{
- type_register_static(&realview_i2c_info);
-}
-
/* Board init. */
static struct arm_boot_info realview_binfo = {
@@ -328,7 +250,7 @@ static void realview_init(ram_addr_t ram_size,
}
}
- dev = sysbus_create_simple("realview_i2c", 0x10002000, NULL);
+ dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
i2c_create_slave(i2c, "ds1338", 0x68);
@@ -492,4 +414,3 @@ static void realview_machine_init(void)
}
machine_init(realview_machine_init);
-type_init(realview_register_types)
diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c
new file mode 100644
index 0000000000..88f530aefc
--- /dev/null
+++ b/hw/versatile_i2c.c
@@ -0,0 +1,105 @@
+/*
+ * ARM Versatile I2C controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
+ *
+ * This file is derived from hw/realview.c by Paul Brook
+ *
+ * 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
+ * of the License, or (at your option) any later version.
+ *
+ * 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 "sysbus.h"
+#include "bitbang_i2c.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ bitbang_i2c_interface *bitbang;
+ int out;
+ int in;
+} VersatileI2CState;
+
+static uint64_t versatile_i2c_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+ if (offset == 0) {
+ return (s->out & 1) | (s->in << 1);
+ } else {
+ hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+ return -1;
+ }
+}
+
+static void versatile_i2c_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+ switch (offset) {
+ case 0:
+ s->out |= value & 3;
+ break;
+ case 4:
+ s->out &= ~value;
+ break;
+ default:
+ hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+ }
+ bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+ s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+}
+
+static const MemoryRegionOps versatile_i2c_ops = {
+ .read = versatile_i2c_read,
+ .write = versatile_i2c_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int versatile_i2c_init(SysBusDevice *dev)
+{
+ VersatileI2CState *s = FROM_SYSBUS(VersatileI2CState, dev);
+ i2c_bus *bus;
+
+ bus = i2c_init_bus(&dev->qdev, "i2c");
+ s->bitbang = bitbang_i2c_init(bus);
+ memory_region_init_io(&s->iomem, &versatile_i2c_ops, s,
+ "versatile_i2c", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ return 0;
+}
+
+static void versatile_i2c_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = versatile_i2c_init;
+}
+
+static const TypeInfo versatile_i2c_info = {
+ .name = "versatile_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VersatileI2CState),
+ .class_init = versatile_i2c_class_init,
+};
+
+static void versatile_i2c_register_types(void)
+{
+ type_register_static(&versatile_i2c_info);
+}
+
+type_init(versatile_i2c_register_types)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 25afb1eb31..7c79c54d08 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -13,9 +13,15 @@
#include "net.h"
#include "sysemu.h"
#include "pci.h"
+#include "i2c.h"
#include "boards.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "flash.h"
+
+#define VERSATILE_FLASH_ADDR 0x34000000
+#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
+#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
/* Primary interrupt controller. */
@@ -178,8 +184,10 @@ static void versatile_init(ram_addr_t ram_size,
DeviceState *pl041;
PCIBus *pci_bus;
NICInfo *nd;
+ i2c_bus *i2c;
int n;
int done_smc = 0;
+ DriveInfo *dinfo;
if (!cpu_model)
cpu_model = "arm926";
@@ -268,6 +276,10 @@ static void versatile_init(ram_addr_t ram_size,
/* Add PL031 Real Time Clock. */
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
+ dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
+ i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+ i2c_create_slave(i2c, "ds1338", 0x68);
+
/* Add PL041 AACI Interface to the LM4549 codec */
pl041 = qdev_create(NULL, "pl041");
qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
@@ -310,6 +322,16 @@ static void versatile_init(ram_addr_t ram_size,
/* 0x101f2000 UART1. */
/* 0x101f3000 UART2. */
/* 0x101f4000 SSPI. */
+ /* 0x34000000 NOR Flash */
+
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
+ VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
+ VERSATILE_FLASH_SECT_SIZE,
+ VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
+ 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
+ fprintf(stderr, "qemu: Error registering flash memory.\n");
+ }
versatile_binfo.ram_size = ram_size;
versatile_binfo.kernel_filename = kernel_filename;
diff --git a/qtest.h b/qtest.h
index 1478343ff0..723a4f9536 100644
--- a/qtest.h
+++ b/qtest.h
@@ -16,6 +16,7 @@
#include "qemu-common.h"
+#if !defined(CONFIG_USER_ONLY)
extern int qtest_allowed;
extern const char *qtest_chrdev;
extern const char *qtest_log;
@@ -31,5 +32,22 @@ static inline int qtest_available(void)
}
int qtest_init(void);
+#else
+static inline bool qtest_enabled(void)
+{
+ return false;
+}
+
+static inline int qtest_available(void)
+{
+ return 0;
+}
+
+static inline int qtest_init(void)
+{
+ return 0;
+}
+
+#endif
#endif
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 42d2a6b63b..b6c044a251 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -58,6 +58,42 @@ typedef struct ARMCPU {
/*< public >*/
CPUARMState env;
+
+ /* The instance init functions for implementation-specific subclasses
+ * set these fields to specify the implementation-dependent values of
+ * various constant registers and reset values of non-constant
+ * registers.
+ * Some of these might become QOM properties eventually.
+ * Field names match the official register names as defined in the
+ * ARMv7AR ARM Architecture Reference Manual. A reset_ prefix
+ * is used for reset values of non-constant registers; no reset_
+ * prefix means a constant register.
+ */
+ uint32_t midr;
+ uint32_t reset_fpsid;
+ uint32_t mvfr0;
+ uint32_t mvfr1;
+ uint32_t ctr;
+ uint32_t reset_sctlr;
+ uint32_t id_pfr0;
+ uint32_t id_pfr1;
+ uint32_t id_dfr0;
+ uint32_t id_afr0;
+ uint32_t id_mmfr0;
+ uint32_t id_mmfr1;
+ uint32_t id_mmfr2;
+ uint32_t id_mmfr3;
+ uint32_t id_isar0;
+ uint32_t id_isar1;
+ uint32_t id_isar2;
+ uint32_t id_isar3;
+ uint32_t id_isar4;
+ uint32_t id_isar5;
+ uint32_t clidr;
+ /* The elements of this array are the CCSIDR values for each cache,
+ * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
+ */
+ uint32_t ccsidr[16];
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
@@ -67,5 +103,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
#define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e))
+void arm_cpu_realize(ARMCPU *cpu);
#endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index c3ed45b0bc..cc67d4d9f4 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -20,20 +20,618 @@
#include "cpu-qom.h"
#include "qemu-common.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
/* CPUClass::reset() */
static void arm_cpu_reset(CPUState *s)
{
ARMCPU *cpu = ARM_CPU(s);
ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+ CPUARMState *env = &cpu->env;
+ uint32_t tmp = 0;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
acc->parent_reset(s);
- /* TODO Inline the current contents of cpu_state_reset(),
- once cpu_reset_model_id() is eliminated. */
- cpu_state_reset(&cpu->env);
+ tmp = env->cp15.c15_config_base_address;
+ memset(env, 0, offsetof(CPUARMState, breakpoints));
+ env->cp15.c15_config_base_address = tmp;
+ env->cp15.c0_cpuid = cpu->midr;
+ env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+ env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
+ env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
+ env->cp15.c0_cachetype = cpu->ctr;
+ env->cp15.c1_sys = cpu->reset_sctlr;
+ env->cp15.c0_c1[0] = cpu->id_pfr0;
+ env->cp15.c0_c1[1] = cpu->id_pfr1;
+ env->cp15.c0_c1[2] = cpu->id_dfr0;
+ env->cp15.c0_c1[3] = cpu->id_afr0;
+ env->cp15.c0_c1[4] = cpu->id_mmfr0;
+ env->cp15.c0_c1[5] = cpu->id_mmfr1;
+ env->cp15.c0_c1[6] = cpu->id_mmfr2;
+ env->cp15.c0_c1[7] = cpu->id_mmfr3;
+ env->cp15.c0_c2[0] = cpu->id_isar0;
+ env->cp15.c0_c2[1] = cpu->id_isar1;
+ env->cp15.c0_c2[2] = cpu->id_isar2;
+ env->cp15.c0_c2[3] = cpu->id_isar3;
+ env->cp15.c0_c2[4] = cpu->id_isar4;
+ env->cp15.c0_c2[5] = cpu->id_isar5;
+ env->cp15.c15_i_min = 0xff0;
+ env->cp15.c0_clid = cpu->clidr;
+ memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
+
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+ }
+
+#if defined(CONFIG_USER_ONLY)
+ env->uncached_cpsr = ARM_CPU_MODE_USR;
+ /* For user mode we must enable access to coprocessors */
+ env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ env->cp15.c15_cpar = 3;
+ } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ env->cp15.c15_cpar = 1;
+ }
+#else
+ /* SVC mode with interrupts disabled. */
+ env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+ /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
+ clear at reset. Initial SP and PC are loaded from ROM. */
+ if (IS_M(env)) {
+ uint32_t pc;
+ uint8_t *rom;
+ env->uncached_cpsr &= ~CPSR_I;
+ rom = rom_ptr(0);
+ if (rom) {
+ /* We should really use ldl_phys here, in case the guest
+ modified flash and reset itself. However images
+ loaded via -kernel have not been copied yet, so load the
+ values directly from there. */
+ env->regs[13] = ldl_p(rom);
+ pc = ldl_p(rom + 4);
+ env->thumb = pc & 1;
+ env->regs[15] = pc & ~1;
+ }
+ }
+ env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+ env->cp15.c2_base_mask = 0xffffc000u;
+ /* v7 performance monitor control register: same implementor
+ * field as main ID register, and we implement no event counters.
+ */
+ env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
+#endif
+ set_flush_to_zero(1, &env->vfp.standard_fp_status);
+ set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
+ set_default_nan_mode(1, &env->vfp.standard_fp_status);
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->vfp.fp_status);
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->vfp.standard_fp_status);
+ tlb_flush(env, 1);
+ /* Reset is a state change for some CPUARMState fields which we
+ * bake assumptions about into translated code, so we need to
+ * tb_flush().
+ */
+ tb_flush(env);
+}
+
+static inline void set_feature(CPUARMState *env, int feature)
+{
+ env->features |= 1u << feature;
+}
+
+static void arm_cpu_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ cpu_exec_init(&cpu->env);
+}
+
+void arm_cpu_realize(ARMCPU *cpu)
+{
+ /* This function is called by cpu_arm_init() because it
+ * needs to do common actions based on feature bits, etc
+ * that have been set by the subclass init functions.
+ * When we have QOM realize support it should become
+ * a true realize function instead.
+ */
+ CPUARMState *env = &cpu->env;
+ /* Some features automatically imply others: */
+ if (arm_feature(env, ARM_FEATURE_V7)) {
+ set_feature(env, ARM_FEATURE_VAPA);
+ set_feature(env, ARM_FEATURE_THUMB2);
+ if (!arm_feature(env, ARM_FEATURE_M)) {
+ set_feature(env, ARM_FEATURE_V6K);
+ } else {
+ set_feature(env, ARM_FEATURE_V6);
+ }
+ }
+ if (arm_feature(env, ARM_FEATURE_V6K)) {
+ set_feature(env, ARM_FEATURE_V6);
+ set_feature(env, ARM_FEATURE_MVFR);
+ }
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ set_feature(env, ARM_FEATURE_V5);
+ if (!arm_feature(env, ARM_FEATURE_M)) {
+ set_feature(env, ARM_FEATURE_AUXCR);
+ }
+ }
+ if (arm_feature(env, ARM_FEATURE_V5)) {
+ set_feature(env, ARM_FEATURE_V4T);
+ }
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ set_feature(env, ARM_FEATURE_THUMB_DIV);
+ }
+ if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+ set_feature(env, ARM_FEATURE_THUMB_DIV);
+ }
+ if (arm_feature(env, ARM_FEATURE_VFP4)) {
+ set_feature(env, ARM_FEATURE_VFP3);
+ }
+ if (arm_feature(env, ARM_FEATURE_VFP3)) {
+ set_feature(env, ARM_FEATURE_VFP);
+ }
+}
+
+/* CPU models */
+
+static void arm926_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ cpu->midr = ARM_CPUID_ARM926;
+ cpu->reset_fpsid = 0x41011090;
+ cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00090078;
+}
+
+static void arm946_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_MPU);
+ cpu->midr = ARM_CPUID_ARM946;
+ cpu->ctr = 0x0f004006;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void arm1026_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ set_feature(&cpu->env, ARM_FEATURE_AUXCR);
+ cpu->midr = ARM_CPUID_ARM1026;
+ cpu->reset_fpsid = 0x410110a0;
+ cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00090078;
+}
+
+static void arm1136_r2_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
+ * older core than plain "arm1136". In particular this does not
+ * have the v6K features.
+ * These ID register values are correct for 1136 but may be wrong
+ * for 1136_r2 (in particular r0p2 does not actually implement most
+ * of the ID registers).
+ */
+ set_feature(&cpu->env, ARM_FEATURE_V6);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ cpu->midr = ARM_CPUID_ARM1136_R2;
+ cpu->reset_fpsid = 0x410120b4;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00050078;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x1;
+ cpu->id_dfr0 = 0x2;
+ cpu->id_afr0 = 0x3;
+ cpu->id_mmfr0 = 0x01130003;
+ cpu->id_mmfr1 = 0x10030302;
+ cpu->id_mmfr2 = 0x01222110;
+ cpu->id_isar0 = 0x00140011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11231111;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x141;
+}
+
+static void arm1136_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6K);
+ set_feature(&cpu->env, ARM_FEATURE_V6);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ cpu->midr = ARM_CPUID_ARM1136;
+ cpu->reset_fpsid = 0x410120b4;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00050078;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x1;
+ cpu->id_dfr0 = 0x2;
+ cpu->id_afr0 = 0x3;
+ cpu->id_mmfr0 = 0x01130003;
+ cpu->id_mmfr1 = 0x10030302;
+ cpu->id_mmfr2 = 0x01222110;
+ cpu->id_isar0 = 0x00140011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11231111;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x141;
+}
+
+static void arm1176_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6K);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ set_feature(&cpu->env, ARM_FEATURE_VAPA);
+ cpu->midr = ARM_CPUID_ARM1176;
+ cpu->reset_fpsid = 0x410120b5;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00050078;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x11;
+ cpu->id_dfr0 = 0x33;
+ cpu->id_afr0 = 0;
+ cpu->id_mmfr0 = 0x01130003;
+ cpu->id_mmfr1 = 0x10030302;
+ cpu->id_mmfr2 = 0x01222100;
+ cpu->id_isar0 = 0x0140011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11231121;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x01141;
+}
+
+static void arm11mpcore_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6K);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ set_feature(&cpu->env, ARM_FEATURE_VAPA);
+ cpu->midr = ARM_CPUID_ARM11MPCORE;
+ cpu->reset_fpsid = 0x410120b4;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x1;
+ cpu->id_dfr0 = 0;
+ cpu->id_afr0 = 0x2;
+ cpu->id_mmfr0 = 0x01100103;
+ cpu->id_mmfr1 = 0x10020302;
+ cpu->id_mmfr2 = 0x01222000;
+ cpu->id_isar0 = 0x00100011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11221011;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x141;
+}
+
+static void cortex_m3_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_M);
+ cpu->midr = ARM_CPUID_CORTEXM3;
+}
+
+static void cortex_a8_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP3);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ cpu->midr = ARM_CPUID_CORTEXA8;
+ cpu->reset_fpsid = 0x410330c0;
+ cpu->mvfr0 = 0x11110222;
+ cpu->mvfr1 = 0x00011100;
+ cpu->ctr = 0x82048004;
+ cpu->reset_sctlr = 0x00c50078;
+ cpu->id_pfr0 = 0x1031;
+ cpu->id_pfr1 = 0x11;
+ cpu->id_dfr0 = 0x400;
+ cpu->id_afr0 = 0;
+ cpu->id_mmfr0 = 0x31100003;
+ cpu->id_mmfr1 = 0x20000000;
+ cpu->id_mmfr2 = 0x01202000;
+ cpu->id_mmfr3 = 0x11;
+ cpu->id_isar0 = 0x00101111;
+ cpu->id_isar1 = 0x12112111;
+ cpu->id_isar2 = 0x21232031;
+ cpu->id_isar3 = 0x11112131;
+ cpu->id_isar4 = 0x00111142;
+ cpu->clidr = (1 << 27) | (2 << 24) | 3;
+ cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
+ cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
+ cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
+}
+
+static void cortex_a9_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP3);
+ set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ /* Note that A9 supports the MP extensions even for
+ * A9UP and single-core A9MP (which are both different
+ * and valid configurations; we don't model A9UP).
+ */
+ set_feature(&cpu->env, ARM_FEATURE_V7MP);
+ cpu->midr = ARM_CPUID_CORTEXA9;
+ cpu->reset_fpsid = 0x41033090;
+ cpu->mvfr0 = 0x11110222;
+ cpu->mvfr1 = 0x01111111;
+ cpu->ctr = 0x80038003;
+ cpu->reset_sctlr = 0x00c50078;
+ cpu->id_pfr0 = 0x1031;
+ cpu->id_pfr1 = 0x11;
+ cpu->id_dfr0 = 0x000;
+ cpu->id_afr0 = 0;
+ cpu->id_mmfr0 = 0x00100103;
+ cpu->id_mmfr1 = 0x20000000;
+ cpu->id_mmfr2 = 0x01230000;
+ cpu->id_mmfr3 = 0x00002111;
+ cpu->id_isar0 = 0x00101111;
+ cpu->id_isar1 = 0x13112111;
+ cpu->id_isar2 = 0x21232041;
+ cpu->id_isar3 = 0x11112131;
+ cpu->id_isar4 = 0x00111142;
+ cpu->clidr = (1 << 27) | (1 << 24) | 3;
+ cpu->ccsidr[0] = 0xe00fe015; /* 16k L1 dcache. */
+ cpu->ccsidr[1] = 0x200fe015; /* 16k L1 icache. */
+}
+
+static void cortex_a15_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP4);
+ set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
+ set_feature(&cpu->env, ARM_FEATURE_V7MP);
+ set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
+ cpu->midr = ARM_CPUID_CORTEXA15;
+ cpu->reset_fpsid = 0x410430f0;
+ cpu->mvfr0 = 0x10110222;
+ cpu->mvfr1 = 0x11111111;
+ cpu->ctr = 0x8444c004;
+ cpu->reset_sctlr = 0x00c50078;
+ cpu->id_pfr0 = 0x00001131;
+ cpu->id_pfr1 = 0x00011011;
+ cpu->id_dfr0 = 0x02010555;
+ cpu->id_afr0 = 0x00000000;
+ cpu->id_mmfr0 = 0x10201105;
+ cpu->id_mmfr1 = 0x20000000;
+ cpu->id_mmfr2 = 0x01240000;
+ cpu->id_mmfr3 = 0x02102211;
+ cpu->id_isar0 = 0x02101110;
+ cpu->id_isar1 = 0x13112111;
+ cpu->id_isar2 = 0x21232041;
+ cpu->id_isar3 = 0x11112131;
+ cpu->id_isar4 = 0x10011142;
+ cpu->clidr = 0x0a200023;
+ cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
+ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
+ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
+}
+
+static void ti925t_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V4T);
+ set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
+ cpu->midr = ARM_CPUID_TI925T;
+ cpu->ctr = 0x5109149;
+ cpu->reset_sctlr = 0x00000070;
+}
+
+static void sa1100_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
+ cpu->midr = ARM_CPUID_SA1100;
+ cpu->reset_sctlr = 0x00000070;
+}
+
+static void sa1110_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
+ cpu->midr = ARM_CPUID_SA1110;
+ cpu->reset_sctlr = 0x00000070;
+}
+
+static void pxa250_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ cpu->midr = ARM_CPUID_PXA250;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa255_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ cpu->midr = ARM_CPUID_PXA255;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa260_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ cpu->midr = ARM_CPUID_PXA260;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa261_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ cpu->midr = ARM_CPUID_PXA261;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa262_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ cpu->midr = ARM_CPUID_PXA262;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa270a0_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+ cpu->midr = ARM_CPUID_PXA270_A0;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa270a1_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+ cpu->midr = ARM_CPUID_PXA270_A1;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
+static void pxa270b0_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+ cpu->midr = ARM_CPUID_PXA270_B0;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa270b1_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+ cpu->midr = ARM_CPUID_PXA270_B1;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa270c0_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+ cpu->midr = ARM_CPUID_PXA270_C0;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void pxa270c5_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
+ cpu->midr = ARM_CPUID_PXA270_C5;
+ cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
+}
+
+static void arm_any_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP4);
+ set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
+ set_feature(&cpu->env, ARM_FEATURE_V7MP);
+ cpu->midr = ARM_CPUID_ANY;
+}
+
+typedef struct ARMCPUInfo {
+ const char *name;
+ void (*initfn)(Object *obj);
+} ARMCPUInfo;
+
+static const ARMCPUInfo arm_cpus[] = {
+ { .name = "arm926", .initfn = arm926_initfn },
+ { .name = "arm946", .initfn = arm946_initfn },
+ { .name = "arm1026", .initfn = arm1026_initfn },
+ /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
+ * older core than plain "arm1136". In particular this does not
+ * have the v6K features.
+ */
+ { .name = "arm1136-r2", .initfn = arm1136_r2_initfn },
+ { .name = "arm1136", .initfn = arm1136_initfn },
+ { .name = "arm1176", .initfn = arm1176_initfn },
+ { .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
+ { .name = "cortex-m3", .initfn = cortex_m3_initfn },
+ { .name = "cortex-a8", .initfn = cortex_a8_initfn },
+ { .name = "cortex-a9", .initfn = cortex_a9_initfn },
+ { .name = "cortex-a15", .initfn = cortex_a15_initfn },
+ { .name = "ti925t", .initfn = ti925t_initfn },
+ { .name = "sa1100", .initfn = sa1100_initfn },
+ { .name = "sa1110", .initfn = sa1110_initfn },
+ { .name = "pxa250", .initfn = pxa250_initfn },
+ { .name = "pxa255", .initfn = pxa255_initfn },
+ { .name = "pxa260", .initfn = pxa260_initfn },
+ { .name = "pxa261", .initfn = pxa261_initfn },
+ { .name = "pxa262", .initfn = pxa262_initfn },
+ /* "pxa270" is an alias for "pxa270-a0" */
+ { .name = "pxa270", .initfn = pxa270a0_initfn },
+ { .name = "pxa270-a0", .initfn = pxa270a0_initfn },
+ { .name = "pxa270-a1", .initfn = pxa270a1_initfn },
+ { .name = "pxa270-b0", .initfn = pxa270b0_initfn },
+ { .name = "pxa270-b1", .initfn = pxa270b1_initfn },
+ { .name = "pxa270-c0", .initfn = pxa270c0_initfn },
+ { .name = "pxa270-c5", .initfn = pxa270c5_initfn },
+ { .name = "any", .initfn = arm_any_initfn },
+};
+
static void arm_cpu_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -43,18 +641,37 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->reset = arm_cpu_reset;
}
+static void cpu_register(const ARMCPUInfo *info)
+{
+ TypeInfo type_info = {
+ .name = info->name,
+ .parent = TYPE_ARM_CPU,
+ .instance_size = sizeof(ARMCPU),
+ .instance_init = info->initfn,
+ .class_size = sizeof(ARMCPUClass),
+ };
+
+ type_register_static(&type_info);
+}
+
static const TypeInfo arm_cpu_type_info = {
.name = TYPE_ARM_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(ARMCPU),
- .abstract = false,
+ .instance_init = arm_cpu_initfn,
+ .abstract = true,
.class_size = sizeof(ARMCPUClass),
.class_init = arm_cpu_class_init,
};
static void arm_cpu_register_types(void)
{
+ int i;
+
type_register_static(&arm_cpu_type_info);
+ for (i = 0; i < ARRAY_SIZE(arm_cpus); i++) {
+ cpu_register(&arm_cpus[i]);
+ }
}
type_init(arm_cpu_register_types)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c208c804aa..01e0e36c2f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -170,9 +170,6 @@ typedef struct CPUARMState {
uint32_t teecr;
uint32_t teehbr;
- /* Internal CPU feature flags. */
- uint32_t features;
-
/* VFP coprocessor state. */
struct {
float64 regs[32];
@@ -228,6 +225,9 @@ typedef struct CPUARMState {
/* These fields after the common ones so they are preserved on reset. */
+ /* Internal CPU feature flags. */
+ uint32_t features;
+
/* Coprocessor IO used by peripherals */
struct {
ARMReadCPFunc *cp_read;
@@ -360,6 +360,10 @@ enum arm_cpu_mode {
#define ARM_IWMMXT_wCGR2 10
#define ARM_IWMMXT_wCGR3 11
+/* If adding a feature bit which corresponds to a Linux ELF
+ * HWCAP bit, remember to update the feature-bit-to-hwcap
+ * mapping in linux-user/elfload.c:get_elf_hwcap().
+ */
enum arm_features {
ARM_FEATURE_VFP,
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 28f127baf8..101031dd75 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2,353 +2,11 @@
#include "gdbstub.h"
#include "helper.h"
#include "host-utils.h"
-#if !defined(CONFIG_USER_ONLY)
-#include "hw/loader.h"
-#endif
#include "sysemu.h"
-static uint32_t cortexa15_cp15_c0_c1[8] = {
- 0x00001131, 0x00011011, 0x02010555, 0x00000000,
- 0x10201105, 0x20000000, 0x01240000, 0x02102211
-};
-
-static uint32_t cortexa15_cp15_c0_c2[8] = {
- 0x02101110, 0x13112111, 0x21232041, 0x11112131, 0x10011142, 0, 0, 0
-};
-
-static uint32_t cortexa9_cp15_c0_c1[8] =
-{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
-
-static uint32_t cortexa9_cp15_c0_c2[8] =
-{ 0x00101111, 0x13112111, 0x21232041, 0x11112131, 0x00111142, 0, 0, 0 };
-
-static uint32_t cortexa8_cp15_c0_c1[8] =
-{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 };
-
-static uint32_t cortexa8_cp15_c0_c2[8] =
-{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
-
-static uint32_t mpcore_cp15_c0_c1[8] =
-{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
-
-static uint32_t mpcore_cp15_c0_c2[8] =
-{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 };
-
-static uint32_t arm1136_cp15_c0_c1[8] =
-{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 };
-
-static uint32_t arm1136_cp15_c0_c2[8] =
-{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 };
-
-static uint32_t arm1176_cp15_c0_c1[8] =
-{ 0x111, 0x11, 0x33, 0, 0x01130003, 0x10030302, 0x01222100, 0 };
-
-static uint32_t arm1176_cp15_c0_c2[8] =
-{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
-
-static uint32_t cpu_arm_find_by_name(const char *name);
-
-static inline void set_feature(CPUARMState *env, int feature)
-{
- env->features |= 1u << feature;
-}
-
-static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
-{
- env->cp15.c0_cpuid = id;
- switch (id) {
- case ARM_CPUID_ARM926:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_VFP);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
- env->cp15.c0_cachetype = 0x1dd20d2;
- env->cp15.c1_sys = 0x00090078;
- break;
- case ARM_CPUID_ARM946:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_MPU);
- env->cp15.c0_cachetype = 0x0f004006;
- env->cp15.c1_sys = 0x00000078;
- break;
- case ARM_CPUID_ARM1026:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_VFP);
- set_feature(env, ARM_FEATURE_AUXCR);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
- env->cp15.c0_cachetype = 0x1dd20d2;
- env->cp15.c1_sys = 0x00090078;
- break;
- case ARM_CPUID_ARM1136:
- /* This is the 1136 r1, which is a v6K core */
- set_feature(env, ARM_FEATURE_V6K);
- /* Fall through */
- case ARM_CPUID_ARM1136_R2:
- /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
- * older core than plain "arm1136". In particular this does not
- * have the v6K features.
- */
- set_feature(env, ARM_FEATURE_V6);
- set_feature(env, ARM_FEATURE_VFP);
- /* These ID register values are correct for 1136 but may be wrong
- * for 1136_r2 (in particular r0p2 does not actually implement most
- * of the ID registers).
- */
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
- memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
- env->cp15.c1_sys = 0x00050078;
- break;
- case ARM_CPUID_ARM1176:
- set_feature(env, ARM_FEATURE_V6K);
- set_feature(env, ARM_FEATURE_VFP);
- set_feature(env, ARM_FEATURE_VAPA);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
- memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
- env->cp15.c1_sys = 0x00050078;
- break;
- case ARM_CPUID_ARM11MPCORE:
- set_feature(env, ARM_FEATURE_V6K);
- set_feature(env, ARM_FEATURE_VFP);
- set_feature(env, ARM_FEATURE_VAPA);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
- memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
- break;
- case ARM_CPUID_CORTEXA8:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP3);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
- memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x82048004;
- env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
- env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
- env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
- env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
- env->cp15.c1_sys = 0x00c50078;
- break;
- case ARM_CPUID_CORTEXA9:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP3);
- set_feature(env, ARM_FEATURE_VFP_FP16);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- /* Note that A9 supports the MP extensions even for
- * A9UP and single-core A9MP (which are both different
- * and valid configurations; we don't model A9UP).
- */
- set_feature(env, ARM_FEATURE_V7MP);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
- memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x80038003;
- env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
- env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
- env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
- env->cp15.c1_sys = 0x00c50078;
- break;
- case ARM_CPUID_CORTEXA15:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP4);
- set_feature(env, ARM_FEATURE_VFP_FP16);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- set_feature(env, ARM_FEATURE_ARM_DIV);
- set_feature(env, ARM_FEATURE_V7MP);
- set_feature(env, ARM_FEATURE_GENERIC_TIMER);
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
- memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x8444c004;
- env->cp15.c0_clid = 0x0a200023;
- env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
- env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
- env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
- env->cp15.c1_sys = 0x00c50078;
- break;
- case ARM_CPUID_CORTEXM3:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_M);
- break;
- case ARM_CPUID_ANY: /* For userspace emulation. */
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP4);
- set_feature(env, ARM_FEATURE_VFP_FP16);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- set_feature(env, ARM_FEATURE_ARM_DIV);
- set_feature(env, ARM_FEATURE_V7MP);
- break;
- case ARM_CPUID_TI915T:
- case ARM_CPUID_TI925T:
- set_feature(env, ARM_FEATURE_V4T);
- set_feature(env, ARM_FEATURE_OMAPCP);
- env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */
- env->cp15.c0_cachetype = 0x5109149;
- env->cp15.c1_sys = 0x00000070;
- env->cp15.c15_i_max = 0x000;
- env->cp15.c15_i_min = 0xff0;
- break;
- case ARM_CPUID_PXA250:
- case ARM_CPUID_PXA255:
- case ARM_CPUID_PXA260:
- case ARM_CPUID_PXA261:
- case ARM_CPUID_PXA262:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_XSCALE);
- /* JTAG_ID is ((id << 28) | 0x09265013) */
- env->cp15.c0_cachetype = 0xd172172;
- env->cp15.c1_sys = 0x00000078;
- break;
- case ARM_CPUID_PXA270_A0:
- case ARM_CPUID_PXA270_A1:
- case ARM_CPUID_PXA270_B0:
- case ARM_CPUID_PXA270_B1:
- case ARM_CPUID_PXA270_C0:
- case ARM_CPUID_PXA270_C5:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_XSCALE);
- /* JTAG_ID is ((id << 28) | 0x09265013) */
- set_feature(env, ARM_FEATURE_IWMMXT);
- env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
- env->cp15.c0_cachetype = 0xd172172;
- env->cp15.c1_sys = 0x00000078;
- break;
- case ARM_CPUID_SA1100:
- case ARM_CPUID_SA1110:
- set_feature(env, ARM_FEATURE_STRONGARM);
- env->cp15.c1_sys = 0x00000070;
- break;
- default:
- cpu_abort(env, "Bad CPU ID: %x\n", id);
- break;
- }
-
- /* Some features automatically imply others: */
- if (arm_feature(env, ARM_FEATURE_V7)) {
- set_feature(env, ARM_FEATURE_VAPA);
- set_feature(env, ARM_FEATURE_THUMB2);
- if (!arm_feature(env, ARM_FEATURE_M)) {
- set_feature(env, ARM_FEATURE_V6K);
- } else {
- set_feature(env, ARM_FEATURE_V6);
- }
- }
- if (arm_feature(env, ARM_FEATURE_V6K)) {
- set_feature(env, ARM_FEATURE_V6);
- set_feature(env, ARM_FEATURE_MVFR);
- }
- if (arm_feature(env, ARM_FEATURE_V6)) {
- set_feature(env, ARM_FEATURE_V5);
- if (!arm_feature(env, ARM_FEATURE_M)) {
- set_feature(env, ARM_FEATURE_AUXCR);
- }
- }
- if (arm_feature(env, ARM_FEATURE_V5)) {
- set_feature(env, ARM_FEATURE_V4T);
- }
- if (arm_feature(env, ARM_FEATURE_M)) {
- set_feature(env, ARM_FEATURE_THUMB_DIV);
- }
- if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
- set_feature(env, ARM_FEATURE_THUMB_DIV);
- }
- if (arm_feature(env, ARM_FEATURE_VFP4)) {
- set_feature(env, ARM_FEATURE_VFP3);
- }
- if (arm_feature(env, ARM_FEATURE_VFP3)) {
- set_feature(env, ARM_FEATURE_VFP);
- }
-}
-
-/* TODO Move contents into arm_cpu_reset() in cpu.c,
- * once cpu_reset_model_id() is eliminated,
- * and then forward to cpu_reset() here.
- */
void cpu_state_reset(CPUARMState *env)
{
- uint32_t id;
- uint32_t tmp = 0;
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- id = env->cp15.c0_cpuid;
- tmp = env->cp15.c15_config_base_address;
- memset(env, 0, offsetof(CPUARMState, breakpoints));
- if (id)
- cpu_reset_model_id(env, id);
- env->cp15.c15_config_base_address = tmp;
-#if defined (CONFIG_USER_ONLY)
- env->uncached_cpsr = ARM_CPU_MODE_USR;
- /* For user mode we must enable access to coprocessors */
- env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
- if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- env->cp15.c15_cpar = 3;
- } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- env->cp15.c15_cpar = 1;
- }
-#else
- /* SVC mode with interrupts disabled. */
- env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
- /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
- clear at reset. Initial SP and PC are loaded from ROM. */
- if (IS_M(env)) {
- uint32_t pc;
- uint8_t *rom;
- env->uncached_cpsr &= ~CPSR_I;
- rom = rom_ptr(0);
- if (rom) {
- /* We should really use ldl_phys here, in case the guest
- modified flash and reset itself. However images
- loaded via -kernel have not been copied yet, so load the
- values directly from there. */
- env->regs[13] = ldl_p(rom);
- pc = ldl_p(rom + 4);
- env->thumb = pc & 1;
- env->regs[15] = pc & ~1;
- }
- }
- env->vfp.xregs[ARM_VFP_FPEXC] = 0;
- env->cp15.c2_base_mask = 0xffffc000u;
- /* v7 performance monitor control register: same implementor
- * field as main ID register, and we implement no event counters.
- */
- env->cp15.c9_pmcr = (id & 0xff000000);
-#endif
- set_flush_to_zero(1, &env->vfp.standard_fp_status);
- set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
- set_default_nan_mode(1, &env->vfp.standard_fp_status);
- set_float_detect_tininess(float_tininess_before_rounding,
- &env->vfp.fp_status);
- set_float_detect_tininess(float_tininess_before_rounding,
- &env->vfp.standard_fp_status);
- tlb_flush(env, 1);
- /* Reset is a state change for some CPUARMState fields which we
- * bake assumptions about into translated code, so we need to
- * tb_flush().
- */
- tb_flush(env);
+ cpu_reset(ENV_GET_CPU(env));
}
static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
@@ -407,22 +65,21 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
{
ARMCPU *cpu;
CPUARMState *env;
- uint32_t id;
static int inited = 0;
- id = cpu_arm_find_by_name(cpu_model);
- if (id == 0)
+ if (!object_class_by_name(cpu_model)) {
return NULL;
- cpu = ARM_CPU(object_new(TYPE_ARM_CPU));
+ }
+ cpu = ARM_CPU(object_new(cpu_model));
env = &cpu->env;
- cpu_exec_init(env);
+ env->cpu_model_str = cpu_model;
+ arm_cpu_realize(cpu);
+
if (tcg_enabled() && !inited) {
inited = 1;
arm_translate_init();
}
- env->cpu_model_str = cpu_model;
- env->cp15.c0_cpuid = id;
cpu_state_reset(env);
if (arm_feature(env, ARM_FEATURE_NEON)) {
gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
@@ -438,66 +95,51 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
return env;
}
-struct arm_cpu_t {
- uint32_t id;
- const char *name;
-};
-
-static const struct arm_cpu_t arm_cpu_names[] = {
- { ARM_CPUID_ARM926, "arm926"},
- { ARM_CPUID_ARM946, "arm946"},
- { ARM_CPUID_ARM1026, "arm1026"},
- { ARM_CPUID_ARM1136, "arm1136"},
- { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
- { ARM_CPUID_ARM1176, "arm1176"},
- { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
- { ARM_CPUID_CORTEXM3, "cortex-m3"},
- { ARM_CPUID_CORTEXA8, "cortex-a8"},
- { ARM_CPUID_CORTEXA9, "cortex-a9"},
- { ARM_CPUID_CORTEXA15, "cortex-a15" },
- { ARM_CPUID_TI925T, "ti925t" },
- { ARM_CPUID_PXA250, "pxa250" },
- { ARM_CPUID_SA1100, "sa1100" },
- { ARM_CPUID_SA1110, "sa1110" },
- { ARM_CPUID_PXA255, "pxa255" },
- { ARM_CPUID_PXA260, "pxa260" },
- { ARM_CPUID_PXA261, "pxa261" },
- { ARM_CPUID_PXA262, "pxa262" },
- { ARM_CPUID_PXA270, "pxa270" },
- { ARM_CPUID_PXA270_A0, "pxa270-a0" },
- { ARM_CPUID_PXA270_A1, "pxa270-a1" },
- { ARM_CPUID_PXA270_B0, "pxa270-b0" },
- { ARM_CPUID_PXA270_B1, "pxa270-b1" },
- { ARM_CPUID_PXA270_C0, "pxa270-c0" },
- { ARM_CPUID_PXA270_C5, "pxa270-c5" },
- { ARM_CPUID_ANY, "any"},
- { 0, NULL}
-};
+typedef struct ARMCPUListState {
+ fprintf_function cpu_fprintf;
+ FILE *file;
+} ARMCPUListState;
-void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+/* Sort alphabetically by type name, except for "any". */
+static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b)
{
- int i;
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+ const char *name_a, *name_b;
- (*cpu_fprintf)(f, "Available CPUs:\n");
- for (i = 0; arm_cpu_names[i].name; i++) {
- (*cpu_fprintf)(f, " %s\n", arm_cpu_names[i].name);
+ name_a = object_class_get_name(class_a);
+ name_b = object_class_get_name(class_b);
+ if (strcmp(name_a, "any") == 0) {
+ return 1;
+ } else if (strcmp(name_b, "any") == 0) {
+ return -1;
+ } else {
+ return strcmp(name_a, name_b);
}
}
-/* return 0 if not found */
-static uint32_t cpu_arm_find_by_name(const char *name)
+static void arm_cpu_list_entry(gpointer data, gpointer user_data)
{
- int i;
- uint32_t id;
+ ObjectClass *oc = data;
+ ARMCPUListState *s = user_data;
- id = 0;
- for (i = 0; arm_cpu_names[i].name; i++) {
- if (strcmp(name, arm_cpu_names[i].name) == 0) {
- id = arm_cpu_names[i].id;
- break;
- }
- }
- return id;
+ (*s->cpu_fprintf)(s->file, " %s\n",
+ object_class_get_name(oc));
+}
+
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ ARMCPUListState s = {
+ .file = f,
+ .cpu_fprintf = cpu_fprintf,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_ARM_CPU, false);
+ list = g_slist_sort(list, arm_cpu_list_compare);
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ g_slist_foreach(list, arm_cpu_list_entry, &s);
+ g_slist_free(list);
}
static int bad_mode_switch(CPUARMState *env, int mode)
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 24f90f1ded..7ac6bdb058 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -119,7 +119,9 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model)
cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU));
env = &cpu->env;
- gen_intermediate_code_init(env);
+ if (tcg_enabled()) {
+ gen_intermediate_code_init(env);
+ }
if (cpu_sparc_register(env, cpu_model) < 0) {
object_delete(OBJECT(cpu));
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 6900123983..521c0e6226 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -2278,7 +2278,7 @@ static void disas_xtensa_insn(DisasContext *dc)
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
- gen_wsr_lend(dc, LEND, tmp);
+ gen_helper_wsr_lend(tmp);
tcg_temp_free(tmp);
if (BRI8_R > 8) {
diff --git a/tci.c b/tci.c
index c43fe7d260..71de66d508 100644
--- a/tci.c
+++ b/tci.c
@@ -58,7 +58,7 @@ CPUArchState *env;
/* Targets which don't use GETPC also don't need tci_tb_ptr
which makes them a little faster. */
#if defined(GETPC)
-void *tci_tb_ptr;
+uintptr_t tci_tb_ptr;
#endif
static tcg_target_ulong tci_reg[TCG_TARGET_NB_REGS];
@@ -450,7 +450,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
for (;;) {
#if defined(GETPC)
- tci_tb_ptr = tb_ptr;
+ tci_tb_ptr = (uintptr_t)tb_ptr;
#endif
TCGOpcode opc = tb_ptr[0];
#if !defined(NDEBUG)
diff --git a/tests/Makefile b/tests/Makefile
index baf1d70ee8..9988681293 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -20,6 +20,8 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
# really in libqtest, not in the testcases themselves.
check-qtest-i386-y = tests/rtc-test
check-qtest-x86_64-y = $(check-qtest-i386-y)
+check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
+check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
@@ -64,6 +66,7 @@ tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
+tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
# QTest rules
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
new file mode 100644
index 0000000000..5179681ca5
--- /dev/null
+++ b/tests/m48t59-test.c
@@ -0,0 +1,259 @@
+/*
+ * QTest testcase for the M48T59 and M48T08 real-time clocks
+ *
+ * Based on MC146818 RTC test:
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define RTC_SECONDS 0x9
+#define RTC_MINUTES 0xa
+#define RTC_HOURS 0xb
+
+#define RTC_DAY_OF_WEEK 0xc
+#define RTC_DAY_OF_MONTH 0xd
+#define RTC_MONTH 0xe
+#define RTC_YEAR 0xf
+
+static uint32_t base;
+static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
+static int base_year;
+static bool use_mmio;
+
+static uint8_t cmos_read_mmio(uint8_t reg)
+{
+ uint8_t data;
+
+ memread(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+ return data;
+}
+
+static void cmos_write_mmio(uint8_t reg, uint8_t val)
+{
+ uint8_t data = val;
+
+ memwrite(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+}
+
+static uint8_t cmos_read_ioio(uint8_t reg)
+{
+ outw(base + 0, reg_base + (uint16_t)reg);
+ return inb(base + 3);
+}
+
+static void cmos_write_ioio(uint8_t reg, uint8_t val)
+{
+ outw(base + 0, reg_base + (uint16_t)reg);
+ outb(base + 3, val);
+}
+
+static uint8_t cmos_read(uint8_t reg)
+{
+ if (use_mmio) {
+ return cmos_read_mmio(reg);
+ } else {
+ return cmos_read_ioio(reg);
+ }
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+ if (use_mmio) {
+ cmos_write_mmio(reg, val);
+ } else {
+ cmos_write_ioio(reg, val);
+ }
+}
+
+static int bcd2dec(int value)
+{
+ return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+ time_t a, b;
+ struct tm d1, d2;
+
+ memcpy(&d1, lhs, sizeof(d1));
+ memcpy(&d2, rhs, sizeof(d2));
+
+ a = mktime(&d1);
+ b = mktime(&d2);
+
+ if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+ printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(struct tm *date)
+{
+ int sec, min, hour, mday, mon, year;
+ time_t ts;
+ struct tm dummy;
+
+ sec = cmos_read(RTC_SECONDS);
+ min = cmos_read(RTC_MINUTES);
+ hour = cmos_read(RTC_HOURS);
+ mday = cmos_read(RTC_DAY_OF_MONTH);
+ mon = cmos_read(RTC_MONTH);
+ year = cmos_read(RTC_YEAR);
+
+ sec = bcd2dec(sec);
+ min = bcd2dec(min);
+ hour = bcd2dec(hour);
+ mday = bcd2dec(mday);
+ mon = bcd2dec(mon);
+ year = bcd2dec(year);
+
+ ts = time(NULL);
+ localtime_r(&ts, &dummy);
+
+ date->tm_isdst = dummy.tm_isdst;
+ date->tm_sec = sec;
+ date->tm_min = min;
+ date->tm_hour = hour;
+ date->tm_mday = mday;
+ date->tm_mon = mon - 1;
+ date->tm_year = base_year + year - 1900;
+ date->tm_gmtoff = 0;
+
+ ts = mktime(date);
+}
+
+static void check_time(int wiggle)
+{
+ struct tm start, date[4], end;
+ struct tm *datep;
+ time_t ts;
+
+ /*
+ * This check assumes a few things. First, we cannot guarantee that we get
+ * a consistent reading from the wall clock because we may hit an edge of
+ * the clock while reading. To work around this, we read four clock readings
+ * such that at least two of them should match. We need to assume that one
+ * reading is corrupt so we need four readings to ensure that we have at
+ * least two consecutive identical readings
+ *
+ * It's also possible that we'll cross an edge reading the host clock so
+ * simply check to make sure that the clock reading is within the period of
+ * when we expect it to be.
+ */
+
+ ts = time(NULL);
+ gmtime_r(&ts, &start);
+
+ cmos_get_date_time(&date[0]);
+ cmos_get_date_time(&date[1]);
+ cmos_get_date_time(&date[2]);
+ cmos_get_date_time(&date[3]);
+
+ ts = time(NULL);
+ gmtime_r(&ts, &end);
+
+ if (tm_cmp(&date[0], &date[1]) == 0) {
+ datep = &date[0];
+ } else if (tm_cmp(&date[1], &date[2]) == 0) {
+ datep = &date[1];
+ } else if (tm_cmp(&date[2], &date[3]) == 0) {
+ datep = &date[2];
+ } else {
+ g_assert_not_reached();
+ }
+
+ if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+ long t, s;
+
+ start.tm_isdst = datep->tm_isdst;
+
+ t = (long)mktime(datep);
+ s = (long)mktime(&start);
+ if (t < s) {
+ g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
+ } else {
+ g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
+ }
+
+ g_assert_cmpint(ABS(t - s), <=, wiggle);
+ }
+}
+
+static int wiggle = 2;
+
+static void bcd_check_time(void)
+{
+ if (strcmp(qtest_get_arch(), "sparc64") == 0) {
+ base = 0x74;
+ base_year = 1900;
+ use_mmio = false;
+ } else if (strcmp(qtest_get_arch(), "sparc") == 0) {
+ base = 0x71200000;
+ base_year = 1968;
+ use_mmio = true;
+ } else { /* PPC: need to map macio in PCI */
+ g_assert_not_reached();
+ }
+ check_time(wiggle);
+}
+
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < 1000; i++) {
+ uint8_t reg, val;
+
+ reg = (uint8_t)g_test_rand_int_range(0, 16);
+ val = (uint8_t)g_test_rand_int_range(0, 256);
+
+ cmos_write(reg, val);
+ cmos_read(reg);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ s = qtest_start("-display none -rtc clock=vm");
+
+ qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
+ qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+
+ return ret;
+}
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 983a980bab..f23ac3a6cf 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -240,6 +240,22 @@ static void alarm_time(void)
g_assert(cmos_read(RTC_REG_C) == 0);
}
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < 1000; i++) {
+ uint8_t reg, val;
+
+ reg = (uint8_t)g_test_rand_int_range(0, 16);
+ val = (uint8_t)g_test_rand_int_range(0, 256);
+
+ cmos_write(reg, val);
+ cmos_read(reg);
+ }
+}
+
int main(int argc, char **argv)
{
QTestState *s = NULL;
@@ -253,6 +269,7 @@ int main(int argc, char **argv)
qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
qtest_add_func("/rtc/dec/check-time", dec_check_time);
qtest_add_func("/rtc/alarm-time", alarm_time);
+ qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
ret = g_test_run();
if (s) {
diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S
index 5cead47a27..1c240e8e9b 100644
--- a/tests/tcg/xtensa/test_loop.S
+++ b/tests/tcg/xtensa/test_loop.S
@@ -124,4 +124,40 @@ test lend_invalidation
assert eqi, a2, 7
test_end
+test loopnez
+ movi a2, 0
+ movi a3, 5
+ loopnez a3, 1f
+ addi a2, a2, 1
+1:
+ assert eqi, a2, 5
+
+ movi a2, 0
+ movi a3, 0
+ loopnez a3, 1f
+ test_fail
+1:
+test_end
+
+test loopgtz
+ movi a2, 0
+ movi a3, 5
+ loopgtz a3, 1f
+ addi a2, a2, 1
+1:
+ assert eqi, a2, 5
+
+ movi a2, 0
+ movi a3, 0
+ loopgtz a3, 1f
+ test_fail
+1:
+
+ movi a2, 0
+ movi a3, 0x80000000
+ loopgtz a3, 1f
+ test_fail
+1:
+test_end
+
test_suite_end