mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'origin/master' into staging
* origin/master: (27 commits) target-arm: Move reset handling to arm_cpu_reset target-arm: Drop cpu_reset_model_id() target-arm: Move cache ID register setup to cpu specific init fns target-arm: Move OMAP cp15_i_{max,min} reset to cpu_state_reset target-arm: Move feature register setup to per-CPU init fns target-arm: Move iWMMXT wCID reset to cpu_state_reset target-arm: Drop JTAG_ID documentation target-arm: Move SCTLR reset value setup to per cpu init fns target-arm: Move CTR setup to per cpu init fns target-arm: Move MVFR* setup to per cpu init fns target-arm: Move FPSID config to cpu init fns target-arm: Move feature bit settings to CPU init fns target-arm: Add QOM subclasses for each ARM cpu implementation target-arm: remind to keep arm features in sync with linux-user/elfload.c tci: GETPC() macro must return an uintptr_t gdbstub: Synchronize CPU state unconditionally in gdb_set_cpu_pc softfloat: make USE_SOFTFLOAT_STRUCT_TYPES compile target-xtensa: add tests for LOOPNEZ and LOOPGTZ target-xtensa: fix LOOPNEZ/LOOPGTZ translation qtest: add m48t59 tests for Sparc ...
This commit is contained in:
commit
5469963394
|
@ -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
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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;
|
||||
|
|
18
qtest.h
18
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
|
||||
|
|
|
@ -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
|
||||
|
|
625
target-arm/cpu.c
625
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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
typedef struct ARMCPUListState {
|
||||
fprintf_function cpu_fprintf;
|
||||
FILE *file;
|
||||
} ARMCPUListState;
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
4
tci.c
4
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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue