mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
ARM system emulation (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1661 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
version 0.7.3:
|
||||
|
||||
- ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
|
||||
cpu (Paul Brook)
|
||||
- SMP support
|
||||
- Mac OS X cocoa improvements (Mike Kronenberg)
|
||||
- Mac OS X CoreAudio driver (Mike Kronenberg)
|
||||
- DirectSound driver (malc)
|
||||
@@ -10,7 +13,6 @@ version 0.7.3:
|
||||
- Linux host serial port access
|
||||
- Linux host low level parallel port access
|
||||
- New network emulation code supporting VLANs.
|
||||
- SMP support
|
||||
|
||||
version 0.7.2:
|
||||
|
||||
|
||||
+4
-1
@@ -211,7 +211,7 @@ LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), arm)
|
||||
LIBOBJS+= op_helper.o
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
# NOTE: the disassembler code is only needed for debugging
|
||||
@@ -324,6 +324,9 @@ VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o magic-load.o slavio_intctl.o
|
||||
VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), arm)
|
||||
VL_OBJS+= integratorcp.o ps2.o
|
||||
endif
|
||||
ifdef CONFIG_GDBSTUB
|
||||
VL_OBJS+=gdbstub.o
|
||||
endif
|
||||
|
||||
@@ -227,7 +227,7 @@ fi
|
||||
|
||||
if test -z "$target_list" ; then
|
||||
# these targets are portable
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu arm-softmmu"
|
||||
# the following are Linux specific
|
||||
if [ "$linux" = "yes" ] ; then
|
||||
target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list"
|
||||
|
||||
+18
-15
@@ -172,7 +172,9 @@ static inline TranslationBlock *tb_find_fast(void)
|
||||
pc = cs_base + env->eip;
|
||||
#elif defined(TARGET_ARM)
|
||||
flags = env->thumb | (env->vfp.vec_len << 1)
|
||||
| (env->vfp.vec_stride << 4);
|
||||
| (env->vfp.vec_stride << 4);
|
||||
if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
|
||||
flags |= (1 << 6);
|
||||
cs_base = 0;
|
||||
pc = env->regs[15];
|
||||
#elif defined(TARGET_SPARC)
|
||||
@@ -322,15 +324,6 @@ int cpu_exec(CPUState *env1)
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
unsigned int psr;
|
||||
psr = env->cpsr;
|
||||
env->CF = (psr >> 29) & 1;
|
||||
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
env->QF = (psr >> 27) & 1;
|
||||
env->cpsr = psr & ~CACHED_CPSR_BITS;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
saved_regwptr = REGWPTR;
|
||||
@@ -379,6 +372,8 @@ int cpu_exec(CPUState *env1)
|
||||
do_interrupt(env);
|
||||
#elif defined(TARGET_SPARC)
|
||||
do_interrupt(env->exception_index);
|
||||
#elif defined(TARGET_ARM)
|
||||
do_interrupt(env);
|
||||
#endif
|
||||
}
|
||||
env->exception_index = -1;
|
||||
@@ -508,8 +503,19 @@ int cpu_exec(CPUState *env1)
|
||||
//do_interrupt(0, 0, 0, 0, 0);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
if (interrupt_request & CPU_INTERRUPT_FIQ
|
||||
&& !(env->uncached_cpsr & CPSR_F)) {
|
||||
env->exception_index = EXCP_FIQ;
|
||||
do_interrupt(env);
|
||||
}
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||
&& !(env->uncached_cpsr & CPSR_I)) {
|
||||
env->exception_index = EXCP_IRQ;
|
||||
do_interrupt(env);
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||
if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
@@ -526,7 +532,7 @@ int cpu_exec(CPUState *env1)
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if ((loglevel & CPU_LOG_EXEC)) {
|
||||
if ((loglevel & CPU_LOG_TB_CPU)) {
|
||||
#if defined(TARGET_I386)
|
||||
/* restore flags in standard format */
|
||||
#ifdef reg_EAX
|
||||
@@ -557,9 +563,7 @@ int cpu_exec(CPUState *env1)
|
||||
cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
env->cpsr = compute_cpsr();
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
env->cpsr &= ~CACHED_CPSR_BITS;
|
||||
#elif defined(TARGET_SPARC)
|
||||
REGWPTR = env->regbase + (env->cwp * 16);
|
||||
env->regwptr = REGWPTR;
|
||||
@@ -760,7 +764,6 @@ int cpu_exec(CPUState *env1)
|
||||
EDI = saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
env->cpsr = compute_cpsr();
|
||||
/* XXX: Save/restore host fpu exception state?. */
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
|
||||
+3
-1
@@ -549,8 +549,10 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
|
||||
#elif defined (TARGET_SPARC)
|
||||
is_user = (env->psrs == 0);
|
||||
#elif defined (TARGET_ARM)
|
||||
is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
|
||||
#else
|
||||
#error "Unimplemented !"
|
||||
#error unimplemented CPU
|
||||
#endif
|
||||
if (__builtin_expect(env->tlb_read[is_user][index].address !=
|
||||
(addr & TARGET_PAGE_MASK), 0)) {
|
||||
|
||||
@@ -1868,14 +1868,14 @@ int cpu_register_io_memory(int io_index,
|
||||
int i;
|
||||
|
||||
if (io_index <= 0) {
|
||||
if (io_index >= IO_MEM_NB_ENTRIES)
|
||||
if (io_mem_nb >= IO_MEM_NB_ENTRIES)
|
||||
return -1;
|
||||
io_index = io_mem_nb++;
|
||||
} else {
|
||||
if (io_index >= IO_MEM_NB_ENTRIES)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
for(i = 0;i < 3; i++) {
|
||||
io_mem_read[io_index][i] = mem_read[i];
|
||||
io_mem_write[io_index][i] = mem_write[i];
|
||||
|
||||
@@ -399,7 +399,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
memset (ptr, 0, 8 * 12 + 4);
|
||||
ptr += 8 * 12 + 4;
|
||||
/* CPSR (4 bytes). */
|
||||
*(uint32_t *)ptr = tswapl (env->cpsr);
|
||||
*(uint32_t *)ptr = tswapl (cpsr_read(env));
|
||||
ptr += 4;
|
||||
|
||||
return ptr - mem_buf;
|
||||
@@ -419,7 +419,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
}
|
||||
/* Ignore FPA regs and scr. */
|
||||
ptr += 8 * 12 + 4;
|
||||
env->cpsr = tswapl(*(uint32_t *)ptr);
|
||||
cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff);
|
||||
}
|
||||
#else
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
@@ -463,6 +463,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
|
||||
#elif defined (TARGET_SPARC)
|
||||
env->pc = addr;
|
||||
env->npc = addr + 4;
|
||||
#elif defined (TARGET_ARM)
|
||||
env->regs[15] = addr;
|
||||
#endif
|
||||
}
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
@@ -481,6 +483,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
|
||||
#elif defined (TARGET_SPARC)
|
||||
env->pc = addr;
|
||||
env->npc = addr + 4;
|
||||
#elif defined (TARGET_ARM)
|
||||
env->regs[15] = addr;
|
||||
#endif
|
||||
}
|
||||
cpu_single_step(env, 1);
|
||||
|
||||
+1232
File diff suppressed because it is too large
Load Diff
+8
-2
@@ -331,6 +331,7 @@ void cpu_loop(CPUARMState *env)
|
||||
int trapnr;
|
||||
unsigned int n, insn;
|
||||
target_siginfo_t info;
|
||||
uint32_t addr;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_arm_exec(env);
|
||||
@@ -397,13 +398,18 @@ void cpu_loop(CPUARMState *env)
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
addr = env->cp15.c6_data;
|
||||
goto do_segv;
|
||||
case EXCP_DATA_ABORT:
|
||||
addr = env->cp15.c6_insn;
|
||||
goto do_segv;
|
||||
do_segv:
|
||||
{
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->cp15_6;
|
||||
info._sifields._sigfault._addr = addr;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
@@ -1190,10 +1196,10 @@ int main(int argc, char **argv)
|
||||
#elif defined(TARGET_ARM)
|
||||
{
|
||||
int i;
|
||||
cpsr_write(env, regs->uregs[16], 0xffffffff);
|
||||
for(i = 0; i < 16; i++) {
|
||||
env->regs[i] = regs->uregs[i];
|
||||
}
|
||||
env->cpsr = regs->uregs[16];
|
||||
ts->stack_base = info->start_stack;
|
||||
ts->heap_base = info->brk;
|
||||
/* This will be filled in on the first SYS_HEAPINFO call. */
|
||||
|
||||
+7
-3
@@ -1003,7 +1003,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
|
||||
__put_user_error(env->regs[14], &sc->arm_lr, err);
|
||||
__put_user_error(env->regs[15], &sc->arm_pc, err);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__put_user_error(env->cpsr, &sc->arm_cpsr, err);
|
||||
__put_user_error(cpsr_read(env), &sc->arm_cpsr, err);
|
||||
#endif
|
||||
|
||||
__put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
|
||||
@@ -1040,9 +1040,9 @@ setup_return(CPUState *env, struct emulated_sigaction *ka,
|
||||
target_ulong retcode;
|
||||
int thumb = 0;
|
||||
#if defined(TARGET_CONFIG_CPU_32)
|
||||
#if 0
|
||||
target_ulong cpsr = env->cpsr;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
|
||||
*/
|
||||
@@ -1088,8 +1088,10 @@ setup_return(CPUState *env, struct emulated_sigaction *ka,
|
||||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
|
||||
#if 0
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
env->cpsr = cpsr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -1157,6 +1159,7 @@ static int
|
||||
restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t cpsr;
|
||||
|
||||
__get_user_error(env->regs[0], &sc->arm_r0, err);
|
||||
__get_user_error(env->regs[1], &sc->arm_r1, err);
|
||||
@@ -1175,7 +1178,8 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
|
||||
__get_user_error(env->regs[14], &sc->arm_lr, err);
|
||||
__get_user_error(env->regs[15], &sc->arm_pc, err);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__get_user_error(env->cpsr, &sc->arm_cpsr, err);
|
||||
__get_user_error(cpsr, &sc->arm_cpsr, err);
|
||||
cpsr_write(env, cpsr, 0xffffffff);
|
||||
#endif
|
||||
|
||||
err |= !valid_user_regs(env);
|
||||
|
||||
@@ -59,6 +59,10 @@
|
||||
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
|
||||
#elif defined (TARGET_SPARC)
|
||||
#define CPU_MEM_INDEX ((env->psrs) == 0)
|
||||
#elif defined (TARGET_ARM)
|
||||
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
@@ -72,6 +76,10 @@
|
||||
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
|
||||
#elif defined (TARGET_SPARC)
|
||||
#define CPU_MEM_INDEX ((env->psrs) == 0)
|
||||
#elif defined (TARGET_ARM)
|
||||
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
#define MMUSUFFIX _cmmu
|
||||
|
||||
|
||||
+97
-3
@@ -32,6 +32,8 @@
|
||||
#define EXCP_SWI 2 /* software interrupt */
|
||||
#define EXCP_PREFETCH_ABORT 3
|
||||
#define EXCP_DATA_ABORT 4
|
||||
#define EXCP_IRQ 5
|
||||
#define EXCP_FIQ 6
|
||||
|
||||
/* We currently assume float and double are IEEE single and double
|
||||
precision respectively.
|
||||
@@ -42,8 +44,22 @@
|
||||
*/
|
||||
|
||||
typedef struct CPUARMState {
|
||||
/* Regs for current mode. */
|
||||
uint32_t regs[16];
|
||||
uint32_t cpsr;
|
||||
/* Frequently accessed CPSR bits are stored separately for efficiently.
|
||||
This contains all the other bits. Use cpsr_{read,write} to accless
|
||||
the whole CPSR. */
|
||||
uint32_t uncached_cpsr;
|
||||
uint32_t spsr;
|
||||
|
||||
/* Banked registers. */
|
||||
uint32_t banked_spsr[6];
|
||||
uint32_t banked_r13[6];
|
||||
uint32_t banked_r14[6];
|
||||
|
||||
/* These hold r8-r12. */
|
||||
uint32_t usr_regs[5];
|
||||
uint32_t fiq_regs[5];
|
||||
|
||||
/* cpsr flag cache for faster execution */
|
||||
uint32_t CF; /* 0 or 1 */
|
||||
@@ -53,8 +69,21 @@ typedef struct CPUARMState {
|
||||
|
||||
int thumb; /* 0 = arm mode, 1 = thumb mode */
|
||||
|
||||
/* coprocessor 15 (MMU) status */
|
||||
uint32_t cp15_6;
|
||||
/* System control coprocessor (cp15) */
|
||||
struct {
|
||||
uint32_t c1_sys; /* System control register. */
|
||||
uint32_t c1_coproc; /* Coprocessor access register. */
|
||||
uint32_t c2; /* MMU translation table base. */
|
||||
uint32_t c3; /* MMU domain access control register. */
|
||||
uint32_t c5_insn; /* Fault status registers. */
|
||||
uint32_t c5_data;
|
||||
uint32_t c6_insn; /* Fault address registers. */
|
||||
uint32_t c6_data;
|
||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||
uint32_t c9_data;
|
||||
uint32_t c13_fcse; /* FCSE PID. */
|
||||
uint32_t c13_context; /* Context ID. */
|
||||
} cp15;
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
@@ -87,6 +116,9 @@ typedef struct CPUARMState {
|
||||
CPUARMState *cpu_arm_init(void);
|
||||
int cpu_arm_exec(CPUARMState *s);
|
||||
void cpu_arm_close(CPUARMState *s);
|
||||
void do_interrupt(CPUARMState *);
|
||||
void switch_mode(CPUARMState *, int);
|
||||
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
@@ -94,7 +126,69 @@ struct siginfo;
|
||||
int cpu_arm_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc);
|
||||
|
||||
#define CPSR_M (0x1f)
|
||||
#define CPSR_T (1 << 5)
|
||||
#define CPSR_F (1 << 6)
|
||||
#define CPSR_I (1 << 7)
|
||||
#define CPSR_A (1 << 8)
|
||||
#define CPSR_E (1 << 9)
|
||||
#define CPSR_IT_2_7 (0xfc00)
|
||||
/* Bits 20-23 reserved. */
|
||||
#define CPSR_J (1 << 24)
|
||||
#define CPSR_IT_0_1 (3 << 25)
|
||||
#define CPSR_Q (1 << 27)
|
||||
#define CPSR_NZCV (0xf << 28)
|
||||
|
||||
#define CACHED_CPSR_BITS (CPSR_T | CPSR_Q | CPSR_NZCV)
|
||||
/* Return the current CPSR value. */
|
||||
static inline uint32_t cpsr_read(CPUARMState *env)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
|
||||
| (env->thumb << 5);
|
||||
}
|
||||
|
||||
/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */
|
||||
static inline void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||
{
|
||||
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
|
||||
if (mask & CPSR_NZCV) {
|
||||
env->NZF = (val & 0xc0000000) ^ 0x40000000;
|
||||
env->CF = (val >> 29) & 1;
|
||||
env->VF = (val << 3) & 0x80000000;
|
||||
}
|
||||
if (mask & CPSR_Q)
|
||||
env->QF = ((val & CPSR_Q) != 0);
|
||||
if (mask & CPSR_T)
|
||||
env->thumb = ((val & CPSR_T) != 0);
|
||||
|
||||
if ((env->uncached_cpsr ^ val) & mask & CPSR_M) {
|
||||
switch_mode(env, val & CPSR_M);
|
||||
}
|
||||
mask &= ~CACHED_CPSR_BITS;
|
||||
env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask);
|
||||
}
|
||||
|
||||
enum arm_cpu_mode {
|
||||
ARM_CPU_MODE_USR = 0x10,
|
||||
ARM_CPU_MODE_FIQ = 0x11,
|
||||
ARM_CPU_MODE_IRQ = 0x12,
|
||||
ARM_CPU_MODE_SVC = 0x13,
|
||||
ARM_CPU_MODE_ABT = 0x17,
|
||||
ARM_CPU_MODE_UND = 0x1b,
|
||||
ARM_CPU_MODE_SYS = 0x1f
|
||||
};
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#else
|
||||
/* The ARM MMU allows 1k pages. */
|
||||
/* ??? Linux doesn't actually use these, and they're deprecated in recent
|
||||
architecture revisions. Maybe an a configure option to disable them. */
|
||||
#define TARGET_PAGE_BITS 10
|
||||
#endif
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif
|
||||
|
||||
+7
-10
@@ -34,16 +34,6 @@ register uint32_t T2 asm(AREG3);
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
/* Implemented CPSR bits. */
|
||||
#define CACHED_CPSR_BITS 0xf8000000
|
||||
static inline int compute_cpsr(void)
|
||||
{
|
||||
int ZF;
|
||||
ZF = (env->NZF == 0);
|
||||
return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
|
||||
(env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27);
|
||||
}
|
||||
|
||||
static inline void env_to_regs(void)
|
||||
{
|
||||
}
|
||||
@@ -55,10 +45,17 @@ static inline void regs_to_env(void)
|
||||
int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "softmmu_exec.h"
|
||||
#endif
|
||||
|
||||
/* In op_helper.c */
|
||||
|
||||
void cpu_lock(void);
|
||||
void cpu_unlock(void);
|
||||
void helper_set_cp15(CPUState *, uint32_t, uint32_t);
|
||||
uint32_t helper_get_cp15(CPUState *, uint32_t);
|
||||
|
||||
void cpu_loop_exit(void);
|
||||
|
||||
void raise_exception(int);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+102
-82
@@ -101,6 +101,11 @@ void OPPROTO op_movl_T0_im(void)
|
||||
T0 = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_T1(void)
|
||||
{
|
||||
T0 = T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T1_im(void)
|
||||
{
|
||||
T1 = PARAM1;
|
||||
@@ -361,20 +366,27 @@ void OPPROTO op_exit_tb(void)
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_psr(void)
|
||||
void OPPROTO op_movl_T0_cpsr(void)
|
||||
{
|
||||
T0 = compute_cpsr();
|
||||
T0 = cpsr_read(env);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
|
||||
void OPPROTO op_movl_psr_T0(void)
|
||||
void OPPROTO op_movl_T0_spsr(void)
|
||||
{
|
||||
unsigned int psr;
|
||||
psr = T0;
|
||||
env->CF = (psr >> 29) & 1;
|
||||
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
|
||||
env->VF = (psr << 3) & 0x80000000;
|
||||
/* for user mode we do not update other state info */
|
||||
T0 = env->spsr;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_spsr_T0(void)
|
||||
{
|
||||
uint32_t mask = PARAM1;
|
||||
env->spsr = (env->spsr & ~mask) | (T0 & mask);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_cpsr_T0(void)
|
||||
{
|
||||
cpsr_write(env, T0, PARAM1);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_mul_T0_T1(void)
|
||||
@@ -433,67 +445,15 @@ void OPPROTO op_logicq_cc(void)
|
||||
|
||||
/* memory access */
|
||||
|
||||
void OPPROTO op_ldub_T0_T1(void)
|
||||
{
|
||||
T0 = ldub((void *)T1);
|
||||
}
|
||||
#define MEMSUFFIX _raw
|
||||
#include "op_mem.h"
|
||||
|
||||
void OPPROTO op_ldsb_T0_T1(void)
|
||||
{
|
||||
T0 = ldsb((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_lduw_T0_T1(void)
|
||||
{
|
||||
T0 = lduw((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldsw_T0_T1(void)
|
||||
{
|
||||
T0 = ldsw((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_ldl_T0_T1(void)
|
||||
{
|
||||
T0 = ldl((void *)T1);
|
||||
}
|
||||
|
||||
void OPPROTO op_stb_T0_T1(void)
|
||||
{
|
||||
stb((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stw_T0_T1(void)
|
||||
{
|
||||
stw((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_stl_T0_T1(void)
|
||||
{
|
||||
stl((void *)T1, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_swpb_T0_T1(void)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
cpu_lock();
|
||||
tmp = ldub((void *)T1);
|
||||
stb((void *)T1, T0);
|
||||
T0 = tmp;
|
||||
cpu_unlock();
|
||||
}
|
||||
|
||||
void OPPROTO op_swpl_T0_T1(void)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
cpu_lock();
|
||||
tmp = ldl((void *)T1);
|
||||
stl((void *)T1, T0);
|
||||
T0 = tmp;
|
||||
cpu_unlock();
|
||||
}
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMSUFFIX _user
|
||||
#include "op_mem.h"
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "op_mem.h"
|
||||
#endif
|
||||
|
||||
/* shifts */
|
||||
|
||||
@@ -744,17 +704,48 @@ void OPPROTO op_sarl_T0_im(void)
|
||||
T0 = (int32_t)T0 >> PARAM1;
|
||||
}
|
||||
|
||||
/* 16->32 Sign extend */
|
||||
void OPPROTO op_sxl_T0(void)
|
||||
/* Sign/zero extend */
|
||||
void OPPROTO op_sxth_T0(void)
|
||||
{
|
||||
T0 = (int16_t)T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_sxl_T1(void)
|
||||
void OPPROTO op_sxth_T1(void)
|
||||
{
|
||||
T1 = (int16_t)T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sxtb_T1(void)
|
||||
{
|
||||
T1 = (int8_t)T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_uxtb_T1(void)
|
||||
{
|
||||
T1 = (uint8_t)T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_uxth_T1(void)
|
||||
{
|
||||
T1 = (uint16_t)T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_sxtb16_T1(void)
|
||||
{
|
||||
uint32_t res;
|
||||
res = (uint16_t)(int8_t)T1;
|
||||
res |= (uint32_t)(int8_t)(T1 >> 16) << 16;
|
||||
T1 = res;
|
||||
}
|
||||
|
||||
void OPPROTO op_uxtb16_T1(void)
|
||||
{
|
||||
uint32_t res;
|
||||
res = (uint16_t)(uint8_t)T1;
|
||||
res |= (uint32_t)(uint8_t)(T1 >> 16) << 16;
|
||||
T1 = res;
|
||||
}
|
||||
|
||||
#define SIGNBIT (uint32_t)0x80000000
|
||||
/* saturating arithmetic */
|
||||
void OPPROTO op_addl_T0_T1_setq(void)
|
||||
@@ -1128,23 +1119,52 @@ void OPPROTO op_vfp_mdrr(void)
|
||||
FT0d = u.d;
|
||||
}
|
||||
|
||||
/* Floating point load/store. Address is in T1 */
|
||||
void OPPROTO op_vfp_lds(void)
|
||||
/* Copy the most significant bit to T0 to all bits of T1. */
|
||||
void OPPROTO op_signbit_T1_T0(void)
|
||||
{
|
||||
FT0s = ldfl((void *)T1);
|
||||
T1 = (int32_t)T0 >> 31;
|
||||
}
|
||||
|
||||
void OPPROTO op_vfp_ldd(void)
|
||||
void OPPROTO op_movl_cp15_T0(void)
|
||||
{
|
||||
FT0d = ldfq((void *)T1);
|
||||
helper_set_cp15(env, PARAM1, T0);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_vfp_sts(void)
|
||||
void OPPROTO op_movl_T0_cp15(void)
|
||||
{
|
||||
stfl((void *)T1, FT0s);
|
||||
T0 = helper_get_cp15(env, PARAM1);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_vfp_std(void)
|
||||
/* Access to user mode registers from privileged modes. */
|
||||
void OPPROTO op_movl_T0_user(void)
|
||||
{
|
||||
stfq((void *)T1, FT0d);
|
||||
int regno = PARAM1;
|
||||
if (regno == 13) {
|
||||
T0 = env->banked_r13[0];
|
||||
} else if (regno == 14) {
|
||||
T0 = env->banked_r14[0];
|
||||
} else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
|
||||
T0 = env->usr_regs[regno - 8];
|
||||
} else {
|
||||
T0 = env->regs[regno];
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO op_movl_user_T0(void)
|
||||
{
|
||||
int regno = PARAM1;
|
||||
if (regno == 13) {
|
||||
env->banked_r13[0] = T0;
|
||||
} else if (regno == 14) {
|
||||
env->banked_r14[0] = T0;
|
||||
} else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
|
||||
env->usr_regs[regno - 8] = T0;
|
||||
} else {
|
||||
env->regs[regno] = T0;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@@ -172,3 +172,54 @@ void do_vfp_get_fpscr(void)
|
||||
i = get_float_exception_flags(&env->vfp.fp_status);
|
||||
T0 |= vfp_exceptbits_from_host(i);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
CPUState *saved_env;
|
||||
target_phys_addr_t pc;
|
||||
int ret;
|
||||
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
ret = cpu_arm_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (__builtin_expect(ret, 0)) {
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (target_phys_addr_t)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, NULL);
|
||||
}
|
||||
}
|
||||
raise_exception(env->exception_index);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/* ARM memory operations. */
|
||||
|
||||
/* Load from address T1 into T0. */
|
||||
#define MEM_LD_OP(name) \
|
||||
void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \
|
||||
{ \
|
||||
T0 = glue(ld##name,MEMSUFFIX)(T1); \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
MEM_LD_OP(ub)
|
||||
MEM_LD_OP(sb)
|
||||
MEM_LD_OP(uw)
|
||||
MEM_LD_OP(sw)
|
||||
MEM_LD_OP(l)
|
||||
|
||||
#undef MEM_LD_OP
|
||||
|
||||
/* Store T0 to address T1. */
|
||||
#define MEM_ST_OP(name) \
|
||||
void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \
|
||||
{ \
|
||||
glue(st##name,MEMSUFFIX)(T1, T0); \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
MEM_ST_OP(b)
|
||||
MEM_ST_OP(w)
|
||||
MEM_ST_OP(l)
|
||||
|
||||
#undef MEM_ST_OP
|
||||
|
||||
/* Swap T0 with memory at address T1. */
|
||||
/* ??? Is this exception safe? */
|
||||
#define MEM_SWP_OP(name, lname) \
|
||||
void OPPROTO glue(op_swp##name,MEMSUFFIX)(void) \
|
||||
{ \
|
||||
uint32_t tmp; \
|
||||
cpu_lock(); \
|
||||
tmp = glue(ld##lname,MEMSUFFIX)(T1); \
|
||||
glue(st##name,MEMSUFFIX)(T1, T0); \
|
||||
T0 = tmp; \
|
||||
cpu_unlock(); \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
MEM_SWP_OP(b, ub)
|
||||
MEM_SWP_OP(l, l)
|
||||
|
||||
#undef MEM_SWP_OP
|
||||
|
||||
/* Floating point load/store. Address is in T1 */
|
||||
#define VFP_MEM_OP(p, w) \
|
||||
void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \
|
||||
{ \
|
||||
FT0##p = glue(ldf##w,MEMSUFFIX)(T1); \
|
||||
FORCE_RET(); \
|
||||
} \
|
||||
void OPPROTO glue(op_vfp_st##p,MEMSUFFIX)(void) \
|
||||
{ \
|
||||
glue(stf##w,MEMSUFFIX)(T1, FT0##p); \
|
||||
FORCE_RET(); \
|
||||
}
|
||||
|
||||
VFP_MEM_OP(s,l)
|
||||
VFP_MEM_OP(d,q)
|
||||
|
||||
#undef VFP_MEM_OP
|
||||
|
||||
#undef MEMSUFFIX
|
||||
+345
-125
File diff suppressed because it is too large
Load Diff
@@ -3359,6 +3359,19 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||
tlb_flush(env, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_ARM)
|
||||
|
||||
/* ??? Need to implement these. */
|
||||
void cpu_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#warning No CPU save/restore functions
|
||||
@@ -4054,6 +4067,10 @@ void register_machines(void)
|
||||
#else
|
||||
qemu_register_machine(&sun4m_machine);
|
||||
#endif
|
||||
#elif defined(TARGET_ARM)
|
||||
qemu_register_machine(&integratorcp_machine);
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -928,6 +928,9 @@ void do_usb_add(const char *devname);
|
||||
void do_usb_del(const char *devname);
|
||||
void usb_info(void);
|
||||
|
||||
/* integratorcp.c */
|
||||
extern QEMUMachine integratorcp_machine;
|
||||
|
||||
/* ps2.c */
|
||||
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
|
||||
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
|
||||
|
||||
Reference in New Issue
Block a user