]> git.proxmox.com Git - qemu.git/commitdiff
ARM emulation support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 15 Jun 2003 19:42:24 +0000 (19:42 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 15 Jun 2003 19:42:24 +0000 (19:42 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@232 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-arm.h [new file with mode: 0644]
exec-arm.h [new file with mode: 0644]
op-arm-template.h [new file with mode: 0644]
op-arm.c [new file with mode: 0644]
syscall-arm.h [new file with mode: 0644]
translate-arm.c [new file with mode: 0644]

diff --git a/cpu-arm.h b/cpu-arm.h
new file mode 100644 (file)
index 0000000..c3850eb
--- /dev/null
+++ b/cpu-arm.h
@@ -0,0 +1,64 @@
+/*
+ * ARM virtual CPU header
+ * 
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef CPU_ARM_H
+#define CPU_ARM_H
+
+#include "config.h"
+#include <setjmp.h>
+
+#define EXCP_UDEF       1   /* undefined instruction */
+#define EXCP_SWI        2   /* software interrupt */
+#define EXCP_INTERRUPT         256 /* async interruption */
+
+typedef struct CPUARMState {
+    uint32_t regs[16];
+    uint32_t cpsr;
+    
+    /* cpsr flag cache for faster execution */
+    uint32_t CF; /* 0 or 1 */
+    uint32_t VF; /* V is the bit 31. All other bits are undefined */
+    uint32_t NZF; /* N is bit 31. Z is computed from NZF */
+
+    /* exception/interrupt handling */
+    jmp_buf jmp_env;
+    int exception_index;
+    int interrupt_request;
+
+    /* user data */
+    void *opaque;
+} CPUARMState;
+
+CPUARMState *cpu_arm_init(void);
+int cpu_arm_exec(CPUARMState *s);
+void cpu_arm_interrupt(CPUARMState *s);
+void cpu_arm_close(CPUARMState *s);
+/* 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.  */
+struct siginfo;
+int cpu_arm_signal_handler(int host_signum, struct siginfo *info, 
+                           void *puc);
+
+void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags);
+
+#define TARGET_PAGE_BITS 12
+#include "cpu-all.h"
+
+#endif
diff --git a/exec-arm.h b/exec-arm.h
new file mode 100644 (file)
index 0000000..8da2636
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  ARM execution defines
+ * 
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "dyngen-exec.h"
+
+register struct CPUARMState *env asm(AREG0);
+register uint32_t T0 asm(AREG1);
+register uint32_t T1 asm(AREG2);
+register uint32_t T2 asm(AREG3);
+
+#include "cpu-arm.h"
+#include "exec.h"
+
+void cpu_lock(void);
+void cpu_unlock(void);
+void cpu_loop_exit(void);
diff --git a/op-arm-template.h b/op-arm-template.h
new file mode 100644 (file)
index 0000000..00e9d51
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  ARM micro operations (templates for various register related
+ *  operations)
+ * 
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void OPPROTO glue(op_movl_T0_, REGNAME)(void)
+{
+    T0 = REG;
+}
+
+void OPPROTO glue(op_movl_T1_, REGNAME)(void)
+{
+    T1 = REG;
+}
+
+void OPPROTO glue(op_movl_T2_, REGNAME)(void)
+{
+    T2 = REG;
+}
+
+void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
+{
+    REG = T0;
+}
+
+void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
+{
+    REG = T1;
+}
+
+#undef REG
+#undef REGNAME
diff --git a/op-arm.c b/op-arm.c
new file mode 100644 (file)
index 0000000..40cf3cd
--- /dev/null
+++ b/op-arm.c
@@ -0,0 +1,665 @@
+/*
+ *  ARM micro operations
+ * 
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "exec-arm.h"
+
+#define REGNAME r0
+#define REG (env->regs[0])
+#include "op-arm-template.h"
+
+#define REGNAME r1
+#define REG (env->regs[1])
+#include "op-arm-template.h"
+
+#define REGNAME r2
+#define REG (env->regs[2])
+#include "op-arm-template.h"
+
+#define REGNAME r3
+#define REG (env->regs[3])
+#include "op-arm-template.h"
+
+#define REGNAME r4
+#define REG (env->regs[4])
+#include "op-arm-template.h"
+
+#define REGNAME r5
+#define REG (env->regs[5])
+#include "op-arm-template.h"
+
+#define REGNAME r6
+#define REG (env->regs[6])
+#include "op-arm-template.h"
+
+#define REGNAME r7
+#define REG (env->regs[7])
+#include "op-arm-template.h"
+
+#define REGNAME r8
+#define REG (env->regs[8])
+#include "op-arm-template.h"
+
+#define REGNAME r9
+#define REG (env->regs[9])
+#include "op-arm-template.h"
+
+#define REGNAME r10
+#define REG (env->regs[10])
+#include "op-arm-template.h"
+
+#define REGNAME r11
+#define REG (env->regs[11])
+#include "op-arm-template.h"
+
+#define REGNAME r12
+#define REG (env->regs[12])
+#include "op-arm-template.h"
+
+#define REGNAME r13
+#define REG (env->regs[13])
+#include "op-arm-template.h"
+
+#define REGNAME r14
+#define REG (env->regs[14])
+#include "op-arm-template.h"
+
+#define REGNAME r15
+#define REG (env->regs[15])
+#include "op-arm-template.h"
+
+void OPPROTO op_movl_T0_0(void)
+{
+    T0 = 0;
+}
+
+void OPPROTO op_movl_T0_im(void)
+{
+    T0 = PARAM1;
+}
+
+void OPPROTO op_movl_T1_im(void)
+{
+    T1 = PARAM1;
+}
+
+void OPPROTO op_movl_T2_im(void)
+{
+    T2 = PARAM1;
+}
+
+void OPPROTO op_addl_T1_im(void)
+{
+    T1 += PARAM1;
+}
+
+void OPPROTO op_addl_T1_T2(void)
+{
+    T1 += T2;
+}
+
+void OPPROTO op_subl_T1_T2(void)
+{
+    T1 -= T2;
+}
+
+void OPPROTO op_addl_T0_T1(void)
+{
+    T0 += T1;
+}
+
+void OPPROTO op_addl_T0_T1_cc(void)
+{
+    unsigned int src1;
+    src1 = T0;
+    T0 += T1;
+    env->NZF = T0;
+    env->CF = T0 < src1;
+    env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
+}
+
+void OPPROTO op_adcl_T0_T1(void)
+{
+    T0 += T1 + env->CF;
+}
+
+void OPPROTO op_adcl_T0_T1_cc(void)
+{
+    unsigned int src1;
+    src1 = T0;
+    if (!env->CF) {
+        T0 += T1;
+        env->CF = T0 < src1;
+    } else {
+        T0 += T1 + 1;
+        env->CF = T0 <= src1;
+    }
+    env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
+    env->NZF = T0;
+    FORCE_RET();
+}
+
+#define OPSUB(sub, sbc, T0, T1)                 \
+                                                \
+void OPPROTO op_ ## sub ## l_T0_T1(void)        \
+{                                               \
+    T0 -= T1;                                   \
+}                                               \
+                                                \
+void OPPROTO op_ ## sub ## l_T0_T1_cc(void)     \
+{                                               \
+    unsigned int src1;                          \
+    src1 = T0;                                  \
+    T0 -= T1;                                   \
+    env->NZF = T0;                              \
+    env->CF = src1 < T1;                        \
+    env->VF = (src1 ^ T1) & (src1 ^ T0);        \
+}                                               \
+                                                \
+void OPPROTO op_ ## sbc ## l_T0_T1(void)        \
+{                                               \
+    T0 = T0 - T1 + env->CF - 1;                 \
+}                                               \
+                                                \
+void OPPROTO op_ ## sbc ## l_T0_T1_cc(void)     \
+{                                               \
+    unsigned int src1;                          \
+    src1 = T0;                                  \
+    if (!env->CF) {                             \
+        T0 = T0 - T1 - 1;                       \
+        T0 += T1;                               \
+        env->CF = src1 < T1;                    \
+    } else {                                    \
+        T0 = T0 - T1;                           \
+        env->CF = src1 <= T1;                   \
+    }                                           \
+    env->VF = (src1 ^ T1) & (src1 ^ T0);        \
+    env->NZF = T0;                              \
+    FORCE_RET();                                \
+}
+
+OPSUB(sub, sbc, T0, T1)
+
+OPSUB(rsb, rsc, T1, T0)
+
+void OPPROTO op_andl_T0_T1(void)
+{
+    T0 &= T1;
+}
+
+void OPPROTO op_xorl_T0_T1(void)
+{
+    T0 ^= T1;
+}
+
+void OPPROTO op_orl_T0_T1(void)
+{
+    T0 |= T1;
+}
+
+void OPPROTO op_bicl_T0_T1(void)
+{
+    T0 &= ~T1;
+}
+
+void OPPROTO op_notl_T1(void)
+{
+    T1 = ~T1;
+}
+
+void OPPROTO op_logic_cc(void)
+{
+    env->NZF = T0;
+}
+
+#define EIP (env->regs[15])
+
+void OPPROTO op_test_eq(void)
+{
+    if (env->NZF == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_ne(void)
+{
+    if (env->NZF != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_cs(void)
+{
+    if (env->CF != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_cc(void)
+{
+    if (env->CF == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_mi(void)
+{
+    if ((env->NZF & 0x80000000) != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_pl(void)
+{
+    if ((env->NZF & 0x80000000) == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_vs(void)
+{
+    if ((env->VF & 0x80000000) != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_vc(void)
+{
+    if ((env->VF & 0x80000000) == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_hi(void)
+{
+    if (env->CF != 0 && env->NZF != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_ls(void)
+{
+    if (env->CF == 0 || env->NZF == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_ge(void)
+{
+    if (((env->VF ^ env->NZF) & 0x80000000) == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_lt(void)
+{
+    if (((env->VF ^ env->NZF) & 0x80000000) != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_gt(void)
+{
+    if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_test_le(void)
+{
+    if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
+        JUMP_TB(PARAM1, 0, PARAM2);
+    FORCE_RET();
+}
+
+void OPPROTO op_jmp(void)
+{
+    JUMP_TB(PARAM1, 1, PARAM2);
+}
+
+void OPPROTO op_movl_T0_psr(void)
+{
+    int ZF;
+    ZF = (env->NZF == 0);
+    T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | 
+        (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
+}
+
+/* NOTE: N = 1 and Z = 1 cannot be stored currently */
+void OPPROTO op_movl_psr_T0(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 */
+}
+
+void OPPROTO op_mul_T0_T1(void)
+{
+    T0 = T0 * T1;
+}
+
+/* 64 bit unsigned mul */
+void OPPROTO op_mull_T0_T1(void)
+{
+    uint64_t res;
+    res = T0 * T1;
+    T1 = res >> 32;
+    T0 = res;
+}
+
+/* 64 bit signed mul */
+void OPPROTO op_imull_T0_T1(void)
+{
+    uint64_t res;
+    res = (int32_t)T0 * (int32_t)T1;
+    T1 = res >> 32;
+    T0 = res;
+}
+
+void OPPROTO op_addq_T0_T1(void)
+{
+    uint64_t res;
+    res = ((uint64_t)T1 << 32) | T0;
+    res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
+    T1 = res >> 32;
+    T0 = res;
+}
+
+void OPPROTO op_logicq_cc(void)
+{
+    env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
+}
+
+/* memory access */
+
+void OPPROTO op_ldub_T0_T1(void)
+{
+    T0 = ldub((void *)T1);
+}
+
+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();
+}
+
+/* shifts */
+
+/* T1 based */
+void OPPROTO op_shll_T1_im(void)
+{
+    T1 = T1 << PARAM1;
+}
+
+void OPPROTO op_shrl_T1_im(void)
+{
+    T1 = (uint32_t)T1 >> PARAM1;
+}
+
+void OPPROTO op_sarl_T1_im(void)
+{
+    T1 = (int32_t)T1 >> PARAM1;
+}
+
+void OPPROTO op_rorl_T1_im(void)
+{
+    int shift;
+    shift = PARAM1;
+    T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
+}
+
+/* T1 based, set C flag */
+void OPPROTO op_shll_T1_im_cc(void)
+{
+    env->CF = (T1 >> (32 - PARAM1)) & 1;
+    T1 = T1 << PARAM1;
+}
+
+void OPPROTO op_shrl_T1_im_cc(void)
+{
+    env->CF = (T1 >> (PARAM1 - 1)) & 1;
+    T1 = (uint32_t)T1 >> PARAM1;
+}
+
+void OPPROTO op_sarl_T1_im_cc(void)
+{
+    env->CF = (T1 >> (PARAM1 - 1)) & 1;
+    T1 = (int32_t)T1 >> PARAM1;
+}
+
+void OPPROTO op_rorl_T1_im_cc(void)
+{
+    int shift;
+    shift = PARAM1;
+    env->CF = (T1 >> (shift - 1)) & 1;
+    T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
+}
+
+/* T2 based */
+void OPPROTO op_shll_T2_im(void)
+{
+    T2 = T2 << PARAM1;
+}
+
+void OPPROTO op_shrl_T2_im(void)
+{
+    T2 = (uint32_t)T2 >> PARAM1;
+}
+
+void OPPROTO op_sarl_T2_im(void)
+{
+    T2 = (int32_t)T2 >> PARAM1;
+}
+
+void OPPROTO op_rorl_T2_im(void)
+{
+    int shift;
+    shift = PARAM1;
+    T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift));
+}
+
+/* T1 based, use T0 as shift count */
+
+void OPPROTO op_shll_T1_T0(void)
+{
+    int shift;
+    shift = T0 & 0xff;
+    if (shift >= 32)
+        T1 = 0;
+    else
+        T1 = T1 << shift;
+    FORCE_RET();
+}
+
+void OPPROTO op_shrl_T1_T0(void)
+{
+    int shift;
+    shift = T0 & 0xff;
+    if (shift >= 32)
+        T1 = 0;
+    else
+        T1 = (uint32_t)T1 >> shift;
+    FORCE_RET();
+}
+
+void OPPROTO op_sarl_T1_T0(void)
+{
+    int shift;
+    shift = T0 & 0xff;
+    if (shift >= 32)
+        shift = 31;
+    T1 = (int32_t)T1 >> shift;
+}
+
+void OPPROTO op_rorl_T1_T0(void)
+{
+    int shift;
+    shift = T0 & 0x1f;
+    if (shift) {
+        T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
+    }
+    FORCE_RET();
+}
+
+/* T1 based, use T0 as shift count and compute CF */
+
+void OPPROTO op_shll_T1_T0_cc(void)
+{
+    int shift;
+    shift = T0 & 0xff;
+    if (shift >= 32) {
+        if (shift == 32)
+            env->CF = T1 & 1;
+        else
+            env->CF = 0;
+        T1 = 0;
+    } else if (shift != 0) {
+        env->CF = (T1 >> (32 - shift)) & 1;
+        T1 = T1 << shift;
+    }
+    FORCE_RET();
+}
+
+void OPPROTO op_shrl_T1_T0_cc(void)
+{
+    int shift;
+    shift = T0 & 0xff;
+    if (shift >= 32) {
+        if (shift == 32)
+            env->CF = (T1 >> 31) & 1;
+        else
+            env->CF = 0;
+        T1 = 0;
+    } else if (shift != 0) {
+        env->CF = (T1 >> (shift - 1)) & 1;
+        T1 = (uint32_t)T1 >> shift;
+    }
+    FORCE_RET();
+}
+
+void OPPROTO op_sarl_T1_T0_cc(void)
+{
+    int shift;
+    shift = T0 & 0xff;
+    if (shift >= 32) {
+        env->CF = (T1 >> 31) & 1;
+        T1 = (int32_t)T1 >> 31;
+    } else {
+        env->CF = (T1 >> (shift - 1)) & 1;
+        T1 = (int32_t)T1 >> shift;
+    }
+    FORCE_RET();
+}
+
+void OPPROTO op_rorl_T1_T0_cc(void)
+{
+    int shift1, shift;
+    shift1 = T0 & 0xff;
+    shift = shift1 & 0x1f;
+    if (shift == 0) {
+        if (shift1 != 0)
+            env->CF = (T1 >> 31) & 1;
+    } else {
+        env->CF = (T1 >> (shift - 1)) & 1;
+        T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
+    }
+    FORCE_RET();
+}
+
+/* exceptions */
+
+void OPPROTO op_swi(void)
+{
+    env->exception_index = EXCP_SWI;
+    cpu_loop_exit();
+}
+
+void OPPROTO op_undef_insn(void)
+{
+    env->exception_index = EXCP_UDEF;
+    cpu_loop_exit();
+}
+
+/* thread support */
+
+spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+
+void cpu_lock(void)
+{
+    spin_lock(&global_cpu_lock);
+}
+
+void cpu_unlock(void)
+{
+    spin_unlock(&global_cpu_lock);
+}
+
diff --git a/syscall-arm.h b/syscall-arm.h
new file mode 100644 (file)
index 0000000..e597710
--- /dev/null
@@ -0,0 +1,27 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+    target_long uregs[18];
+};
+
+#define ARM_cpsr       uregs[16]
+#define ARM_pc         uregs[15]
+#define ARM_lr         uregs[14]
+#define ARM_sp         uregs[13]
+#define ARM_ip         uregs[12]
+#define ARM_fp         uregs[11]
+#define ARM_r10                uregs[10]
+#define ARM_r9         uregs[9]
+#define ARM_r8         uregs[8]
+#define ARM_r7         uregs[7]
+#define ARM_r6         uregs[6]
+#define ARM_r5         uregs[5]
+#define ARM_r4         uregs[4]
+#define ARM_r3         uregs[3]
+#define ARM_r2         uregs[2]
+#define ARM_r1         uregs[1]
+#define ARM_r0         uregs[0]
+#define ARM_ORIG_r0    uregs[17]
+
diff --git a/translate-arm.c b/translate-arm.c
new file mode 100644 (file)
index 0000000..9b85b68
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ *  ARM translation
+ * 
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu-arm.h"
+#include "exec.h"
+#include "disas.h"
+
+/* internal defines */
+typedef struct DisasContext {
+    uint8_t *pc;
+    int is_jmp;
+    struct TranslationBlock *tb;
+} DisasContext;
+
+/* XXX: move that elsewhere */
+static uint16_t *gen_opc_ptr;
+static uint32_t *gen_opparam_ptr;
+extern FILE *logfile;
+extern int loglevel;
+
+enum {
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#include "opc-arm.h"
+#undef DEF
+    NB_OPS,
+};
+
+#include "gen-op-arm.h"
+
+typedef void (GenOpFunc)(void);
+typedef void (GenOpFunc1)(long);
+typedef void (GenOpFunc2)(long, long);
+typedef void (GenOpFunc3)(long, long, long);
+
+static GenOpFunc2 *gen_test_cc[14] = {
+    gen_op_test_eq,
+    gen_op_test_ne,
+    gen_op_test_cs,
+    gen_op_test_cc,
+    gen_op_test_mi,
+    gen_op_test_pl,
+    gen_op_test_vs,
+    gen_op_test_vc,
+    gen_op_test_hi,
+    gen_op_test_ls,
+    gen_op_test_ge,
+    gen_op_test_lt,
+    gen_op_test_gt,
+    gen_op_test_le,
+};
+
+const uint8_t table_logic_cc[16] = {
+    1, /* and */
+    1, /* xor */
+    0, /* sub */
+    0, /* rsb */
+    0, /* add */
+    0, /* adc */
+    0, /* sbc */
+    0, /* rsc */
+    1, /* andl */
+    1, /* xorl */
+    0, /* cmp */
+    0, /* cmn */
+    1, /* orr */
+    1, /* mov */
+    1, /* bic */
+    1, /* mvn */
+};
+    
+static GenOpFunc1 *gen_shift_T1_im[4] = {
+    gen_op_shll_T1_im,
+    gen_op_shrl_T1_im,
+    gen_op_sarl_T1_im,
+    gen_op_rorl_T1_im,
+};
+
+static GenOpFunc1 *gen_shift_T2_im[4] = {
+    gen_op_shll_T2_im,
+    gen_op_shrl_T2_im,
+    gen_op_sarl_T2_im,
+    gen_op_rorl_T2_im,
+};
+
+static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
+    gen_op_shll_T1_im_cc,
+    gen_op_shrl_T1_im_cc,
+    gen_op_sarl_T1_im_cc,
+    gen_op_rorl_T1_im_cc,
+};
+
+static GenOpFunc *gen_shift_T1_T0[4] = {
+    gen_op_shll_T1_T0,
+    gen_op_shrl_T1_T0,
+    gen_op_sarl_T1_T0,
+    gen_op_rorl_T1_T0,
+};
+
+static GenOpFunc *gen_shift_T1_T0_cc[4] = {
+    gen_op_shll_T1_T0_cc,
+    gen_op_shrl_T1_T0_cc,
+    gen_op_sarl_T1_T0_cc,
+    gen_op_rorl_T1_T0_cc,
+};
+
+static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
+    {
+        gen_op_movl_T0_r0,
+        gen_op_movl_T0_r1,
+        gen_op_movl_T0_r2,
+        gen_op_movl_T0_r3,
+        gen_op_movl_T0_r4,
+        gen_op_movl_T0_r5,
+        gen_op_movl_T0_r6,
+        gen_op_movl_T0_r7,
+        gen_op_movl_T0_r8,
+        gen_op_movl_T0_r9,
+        gen_op_movl_T0_r10,
+        gen_op_movl_T0_r11,
+        gen_op_movl_T0_r12,
+        gen_op_movl_T0_r13,
+        gen_op_movl_T0_r14,
+        gen_op_movl_T0_r15,
+    },
+    {
+        gen_op_movl_T1_r0,
+        gen_op_movl_T1_r1,
+        gen_op_movl_T1_r2,
+        gen_op_movl_T1_r3,
+        gen_op_movl_T1_r4,
+        gen_op_movl_T1_r5,
+        gen_op_movl_T1_r6,
+        gen_op_movl_T1_r7,
+        gen_op_movl_T1_r8,
+        gen_op_movl_T1_r9,
+        gen_op_movl_T1_r10,
+        gen_op_movl_T1_r11,
+        gen_op_movl_T1_r12,
+        gen_op_movl_T1_r13,
+        gen_op_movl_T1_r14,
+        gen_op_movl_T1_r15,
+    },
+    {
+        gen_op_movl_T2_r0,
+        gen_op_movl_T2_r1,
+        gen_op_movl_T2_r2,
+        gen_op_movl_T2_r3,
+        gen_op_movl_T2_r4,
+        gen_op_movl_T2_r5,
+        gen_op_movl_T2_r6,
+        gen_op_movl_T2_r7,
+        gen_op_movl_T2_r8,
+        gen_op_movl_T2_r9,
+        gen_op_movl_T2_r10,
+        gen_op_movl_T2_r11,
+        gen_op_movl_T2_r12,
+        gen_op_movl_T2_r13,
+        gen_op_movl_T2_r14,
+        gen_op_movl_T2_r15,
+    },
+};
+
+static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
+    {
+        gen_op_movl_r0_T0,
+        gen_op_movl_r1_T0,
+        gen_op_movl_r2_T0,
+        gen_op_movl_r3_T0,
+        gen_op_movl_r4_T0,
+        gen_op_movl_r5_T0,
+        gen_op_movl_r6_T0,
+        gen_op_movl_r7_T0,
+        gen_op_movl_r8_T0,
+        gen_op_movl_r9_T0,
+        gen_op_movl_r10_T0,
+        gen_op_movl_r11_T0,
+        gen_op_movl_r12_T0,
+        gen_op_movl_r13_T0,
+        gen_op_movl_r14_T0,
+        gen_op_movl_r15_T0,
+    },
+    {
+        gen_op_movl_r0_T1,
+        gen_op_movl_r1_T1,
+        gen_op_movl_r2_T1,
+        gen_op_movl_r3_T1,
+        gen_op_movl_r4_T1,
+        gen_op_movl_r5_T1,
+        gen_op_movl_r6_T1,
+        gen_op_movl_r7_T1,
+        gen_op_movl_r8_T1,
+        gen_op_movl_r9_T1,
+        gen_op_movl_r10_T1,
+        gen_op_movl_r11_T1,
+        gen_op_movl_r12_T1,
+        gen_op_movl_r13_T1,
+        gen_op_movl_r14_T1,
+        gen_op_movl_r15_T1,
+    },
+};
+
+static GenOpFunc1 *gen_op_movl_TN_im[3] = {
+    gen_op_movl_T0_im,
+    gen_op_movl_T1_im,
+    gen_op_movl_T2_im,
+};
+
+static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
+{
+    int val;
+
+    if (reg == 15) {
+        /* normaly, since we updated PC, we need only to add 4 */
+        val = (long)s->pc + 4;
+        gen_op_movl_TN_im[t](val);
+    } else {
+        gen_op_movl_TN_reg[t][reg]();
+    }
+}
+
+static inline void gen_movl_T0_reg(DisasContext *s, int reg)
+{
+    gen_movl_TN_reg(s, reg, 0);
+}
+
+static inline void gen_movl_T1_reg(DisasContext *s, int reg)
+{
+    gen_movl_TN_reg(s, reg, 1);
+}
+
+static inline void gen_movl_T2_reg(DisasContext *s, int reg)
+{
+    gen_movl_TN_reg(s, reg, 2);
+}
+
+static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
+{
+    gen_op_movl_reg_TN[t][reg]();
+    if (reg == 15) {
+        s->is_jmp = DISAS_JUMP;
+    }
+}
+
+static inline void gen_movl_reg_T0(DisasContext *s, int reg)
+{
+    gen_movl_reg_TN(s, reg, 0);
+}
+
+static inline void gen_movl_reg_T1(DisasContext *s, int reg)
+{
+    gen_movl_reg_TN(s, reg, 1);
+}
+
+static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
+{
+    int val, rm, shift;
+
+    if (!(insn & (1 << 25))) {
+        /* immediate */
+        val = insn & 0xfff;
+        if (!(insn & (1 << 23)))
+            val = -val;
+        gen_op_addl_T1_im(val);
+    } else {
+        /* shift/register */
+        rm = (insn) & 0xf;
+        shift = (insn >> 7) & 0x1f;
+        gen_movl_T2_reg(s, rm);
+        if (shift != 0) {
+            gen_shift_T2_im[(insn >> 5) & 3](shift);
+        }
+        if (!(insn & (1 << 23)))
+            gen_op_subl_T1_T2();
+        else
+            gen_op_addl_T1_T2();
+    }
+}
+
+static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
+{
+    int val, rm;
+    
+    if (insn & (1 << 22)) {
+        /* immediate */
+        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
+        if (!(insn & (1 << 23)))
+            val = -val;
+        gen_op_addl_T1_im(val);
+    } else {
+        /* register */
+        rm = (insn) & 0xf;
+        gen_movl_T2_reg(s, rm);
+        if (!(insn & (1 << 23)))
+            gen_op_subl_T1_T2();
+        else
+            gen_op_addl_T1_T2();
+    }
+}
+
+static void disas_arm_insn(DisasContext *s)
+{
+    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
+    
+    insn = ldl(s->pc);
+    s->pc += 4;
+    
+    cond = insn >> 28;
+    if (cond == 0xf)
+        goto illegal_op;
+    if (cond != 0xe) {
+        /* if not always execute, we generate a conditional jump to
+           next instruction */
+        gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
+        s->is_jmp = 1;
+    }
+    if ((insn & 0x0c000000) == 0 &&
+        (insn & 0x00000090) != 0x90) {
+        int set_cc, logic_cc, shiftop;
+        
+        op1 = (insn >> 21) & 0xf;
+        set_cc = (insn >> 20) & 1;
+        logic_cc = table_logic_cc[op1] & set_cc;
+
+        /* data processing instruction */
+        if (insn & (1 << 25)) {
+            /* immediate operand */
+            val = insn & 0xff;
+            shift = ((insn >> 8) & 0xf) * 2;
+            if (shift)
+                val = (val >> shift) | (val << (32 - shift));
+            gen_op_movl_T1_im(val);
+            /* XXX: is CF modified ? */
+        } else {
+            /* register */
+            rm = (insn) & 0xf;
+            gen_movl_T1_reg(s, rm);
+            shiftop = (insn >> 5) & 3;
+            if (!(insn & (1 << 4))) {
+                shift = (insn >> 7) & 0x1f;
+                if (shift != 0) {
+                    if (logic_cc) {
+                        gen_shift_T1_im_cc[shiftop](shift);
+                    } else {
+                        gen_shift_T1_im[shiftop](shift);
+                    }
+                }
+            } else {
+                rs = (insn >> 16) & 0xf;
+                gen_movl_T0_reg(s, rs);
+                if (logic_cc) {
+                    gen_shift_T1_T0_cc[shiftop]();
+                } else {
+                    gen_shift_T1_T0[shiftop]();
+                }
+            }
+        }
+        if (op1 != 0x0f && op1 != 0x0d) {
+            rn = (insn >> 16) & 0xf;
+            gen_movl_T0_reg(s, rn);
+        }
+        rd = (insn >> 12) & 0xf;
+        switch(op1) {
+        case 0x00:
+            gen_op_andl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x01:
+            gen_op_xorl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x02:
+            if (set_cc)
+                gen_op_subl_T0_T1_cc();
+            else
+                gen_op_subl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x03:
+            if (set_cc)
+                gen_op_rsbl_T0_T1_cc();
+            else
+                gen_op_rsbl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x04:
+            if (set_cc)
+                gen_op_addl_T0_T1_cc();
+            else
+                gen_op_addl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x05:
+            if (set_cc)
+                gen_op_adcl_T0_T1_cc();
+            else
+                gen_op_adcl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x06:
+            if (set_cc)
+                gen_op_sbcl_T0_T1_cc();
+            else
+                gen_op_sbcl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x07:
+            if (set_cc)
+                gen_op_rscl_T0_T1_cc();
+            else
+                gen_op_rscl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x08:
+            if (set_cc) {
+                gen_op_andl_T0_T1();
+            }
+            break;
+        case 0x09:
+            if (set_cc) {
+                gen_op_xorl_T0_T1();
+            }
+            break;
+        case 0x0a:
+            if (set_cc) {
+                gen_op_subl_T0_T1_cc();
+            }
+            break;
+        case 0x0b:
+            if (set_cc) {
+                gen_op_addl_T0_T1_cc();
+            }
+            break;
+        case 0x0c:
+            gen_op_orl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        case 0x0d:
+            gen_movl_reg_T1(s, rd);
+            break;
+        case 0x0e:
+            gen_op_bicl_T0_T1();
+            gen_movl_reg_T0(s, rd);
+            break;
+        default:
+        case 0x0f:
+            gen_op_notl_T1();
+            gen_movl_reg_T1(s, rd);
+            break;
+        }
+        if (logic_cc)
+            gen_op_logic_cc();
+    } else {
+        /* other instructions */
+        op1 = (insn >> 24) & 0xf;
+        switch(op1) {
+        case 0x0:
+        case 0x1:
+            sh = (insn >> 5) & 3;
+            if (sh == 0) {
+                if (op1 == 0x0) {
+                    rd = (insn >> 16) & 0xf;
+                    rn = (insn >> 12) & 0xf;
+                    rs = (insn >> 8) & 0xf;
+                    rm = (insn) & 0xf;
+                    if (!(insn & (1 << 23))) {
+                        /* 32 bit mul */
+                        gen_movl_T0_reg(s, rs);
+                        gen_movl_T1_reg(s, rm);
+                        gen_op_mul_T0_T1();
+                        if (insn & (1 << 21)) {
+                            gen_movl_T1_reg(s, rn);
+                            gen_op_addl_T0_T1();
+                        }
+                        if (insn & (1 << 20)) 
+                            gen_op_logic_cc();
+                        gen_movl_reg_T0(s, rd);
+                    } else {
+                        /* 64 bit mul */
+                        gen_movl_T0_reg(s, rs);
+                        gen_movl_T1_reg(s, rm);
+                        if (insn & (1 << 22)) 
+                            gen_op_mull_T0_T1();
+                        else
+                            gen_op_imull_T0_T1();
+                        if (insn & (1 << 21)) 
+                            gen_op_addq_T0_T1(rn, rd);
+                        if (insn & (1 << 20)) 
+                            gen_op_logicq_cc();
+                        gen_movl_reg_T0(s, rn);
+                        gen_movl_reg_T1(s, rd);
+                    }
+                } else {
+                    /* SWP instruction */
+                    rn = (insn >> 16) & 0xf;
+                    rd = (insn >> 12) & 0xf;
+                    rm = (insn) & 0xf;
+                    
+                    gen_movl_T0_reg(s, rm);
+                    gen_movl_T1_reg(s, rn);
+                    if (insn & (1 << 22)) {
+                        gen_op_swpb_T0_T1();
+                    } else {
+                        gen_op_swpl_T0_T1();
+                    }
+                    gen_movl_reg_T0(s, rd);
+                }
+            } else {
+                /* load/store half word */
+                rn = (insn >> 16) & 0xf;
+                rd = (insn >> 12) & 0xf;
+                gen_movl_T1_reg(s, rn);
+                if (insn & (1 << 25))
+                    gen_add_datah_offset(s, insn);
+                if (insn & (1 << 20)) {
+                    /* load */
+                    switch(sh) {
+                    case 1:
+                        gen_op_lduw_T0_T1();
+                        break;
+                    case 2:
+                        gen_op_ldsb_T0_T1();
+                        break;
+                    default:
+                    case 3:
+                        gen_op_ldsw_T0_T1();
+                        break;
+                    }
+                } else {
+                    /* store */
+                    gen_op_stw_T0_T1();
+                }
+                if (!(insn & (1 << 24)))
+                    gen_add_datah_offset(s, insn);
+                if (insn & (1 << 21))
+                    gen_movl_reg_T1(s, rn);
+            }
+            break;
+        case 0x4:
+        case 0x5:
+        case 0x6:
+        case 0x7:
+            /* load/store byte/word */
+            rn = (insn >> 16) & 0xf;
+            rd = (insn >> 12) & 0xf;
+            gen_movl_T1_reg(s, rn);
+            if (insn & (1 << 24))
+                gen_add_data_offset(s, insn);
+            if (insn & (1 << 20)) {
+                /* load */
+                if (insn & (1 << 22))
+                    gen_op_ldub_T0_T1();
+                else
+                    gen_op_ldl_T0_T1();
+                gen_movl_reg_T0(s, rd);
+            } else {
+                /* store */
+                gen_movl_T0_reg(s, rd);
+                if (insn & (1 << 22))
+                    gen_op_stb_T0_T1();
+                else
+                    gen_op_stl_T0_T1();
+            }
+            if (!(insn & (1 << 24)))
+                gen_add_data_offset(s, insn);
+            if (insn & (1 << 21))
+                gen_movl_reg_T1(s, rn);
+            break;
+        case 0x08:
+        case 0x09:
+            /* load/store multiple words */
+            if (insn & (1 << 22))
+                goto illegal_op; /* only usable in supervisor mode */
+            rn = (insn >> 16) & 0xf;
+            gen_movl_T1_reg(s, rn);
+            val = 4;
+            if (!(insn & (1 << 23)))
+                val = -val;
+            for(i=0;i<16;i++) {
+                if (insn & (1 << i)) {
+                    if (insn & (1 << 24))
+                        gen_op_addl_T1_im(val);
+                    if (insn & (1 << 20)) {
+                        /* load */
+                        gen_op_ldl_T0_T1();
+                        gen_movl_reg_T0(s, i);
+                    } else {
+                        /* store */
+                        gen_movl_T0_reg(s, i);
+                        gen_op_stl_T0_T1();
+                    }
+                    if (!(insn & (1 << 24)))
+                        gen_op_addl_T1_im(val);
+                }
+            }
+            if (insn & (1 << 21))
+                gen_movl_reg_T1(s, rn);
+            break;
+        case 0xa:
+        case 0xb:
+            {
+                int offset;
+                
+                /* branch (and link) */
+                val = (int)s->pc;
+                if (insn & (1 << 24)) {
+                    gen_op_movl_T0_im(val);
+                    gen_op_movl_reg_TN[0][14]();
+                }
+                offset = (((int)insn << 8) >> 8);
+                val += (offset << 2) + 4;
+                gen_op_jmp((long)s->tb, val);
+                s->is_jmp = DISAS_TB_JUMP;
+            }
+            break;
+        case 0xf:
+            /* swi */
+            gen_op_movl_T0_im((long)s->pc);
+            gen_op_movl_reg_TN[0][15]();
+            gen_op_swi();
+            s->is_jmp = DISAS_JUMP;
+            break;
+        default:
+        illegal_op:
+            gen_op_movl_T0_im((long)s->pc - 4);
+            gen_op_movl_reg_TN[0][15]();
+            gen_op_undef_insn();
+            s->is_jmp = DISAS_JUMP;
+            break;
+        }
+    }
+}
+
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
+   basic block 'tb'. If search_pc is TRUE, also generate PC
+   information for each intermediate instruction. */
+int gen_intermediate_code(TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc1, *dc = &dc1;
+    uint16_t *gen_opc_end;
+    int j, lj;
+    uint8_t *pc_start;
+    
+    /* generate intermediate code */
+    pc_start = (uint8_t *)tb->pc;
+       
+    dc->tb = tb;
+
+    gen_opc_ptr = gen_opc_buf;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    gen_opparam_ptr = gen_opparam_buf;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->pc = pc_start;
+    lj = -1;
+    do {
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+                gen_opc_pc[lj] = (uint32_t)dc->pc;
+                gen_opc_instr_start[lj] = 1;
+            }
+        }
+        disas_arm_insn(dc);
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && 
+             (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+    /* we must store the eflags state if it is not already done */
+    if (dc->is_jmp != DISAS_TB_JUMP && 
+        dc->is_jmp != DISAS_JUMP) {
+        gen_op_movl_T0_im((long)dc->pc - 4);
+        gen_op_movl_reg_TN[0][15]();
+    }
+    if (dc->is_jmp != DISAS_TB_JUMP) {
+        /* indicate that the hash table must be used to find the next TB */
+        gen_op_movl_T0_0();
+    }
+    *gen_opc_ptr = INDEX_op_end;
+
+#ifdef DEBUG_DISAS
+    if (loglevel) {
+        fprintf(logfile, "----------------\n");
+        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+       disas(logfile, pc_start, dc->pc - pc_start, 0, 0);
+        fprintf(logfile, "\n");
+
+        fprintf(logfile, "OP:\n");
+        dump_ops(gen_opc_buf, gen_opparam_buf);
+        fprintf(logfile, "\n");
+    }
+#endif
+    if (!search_pc)
+        tb->size = dc->pc - pc_start;
+    return 0;
+}
+
+CPUARMState *cpu_arm_init(void)
+{
+    CPUARMState *env;
+
+    cpu_exec_init();
+
+    env = malloc(sizeof(CPUARMState));
+    if (!env)
+        return NULL;
+    memset(env, 0, sizeof(CPUARMState));
+    return env;
+}
+
+void cpu_arm_close(CPUARMState *env)
+{
+    free(env);
+}
+
+void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
+{
+    int i;
+
+    for(i=0;i<16;i++) {
+        fprintf(f, "R%02d=%08x", i, env->regs[i]);
+        if ((i % 4) == 3)
+            fprintf(f, "\n");
+        else
+            fprintf(f, " ");
+    }
+    fprintf(f, "CPSR=%08x", env->cpsr);
+}