aboutsummaryrefslogtreecommitdiffstats
path: root/target-arm
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2008-03-31 03:44:26 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2008-03-31 03:44:26 +0000
commitb26eefb68e7942eeb689c81fd20e67e57ad95cd2 (patch)
tree3eb9eaf50ba68bae2729a0ce1974bea027dfb3ef /target-arm
parent2a39bc41cb81e1fbd989e0dc648251a1f745c4db (diff)
ARM TCG conversion 1/16.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4138 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/cpu.h3
-rw-r--r--target-arm/helper.c26
-rw-r--r--target-arm/helpers.h6
-rw-r--r--target-arm/op.c330
-rw-r--r--target-arm/op_template.h53
-rw-r--r--target-arm/translate.c689
6 files changed, 434 insertions, 673 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index b284a2169..275733e9c 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -89,7 +89,7 @@ typedef struct CPUARMState {
uint32_t NZF; /* N is bit 31. Z is computed from NZF */
uint32_t QF; /* 0 or 1 */
uint32_t GE; /* cpsr[19:16] */
- int thumb; /* cprs[5]. 0 = arm mode, 1 = thumb mode. */
+ uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */
/* System control coprocessor (cp15) */
@@ -207,6 +207,7 @@ typedef struct CPUARMState {
} CPUARMState;
CPUARMState *cpu_arm_init(const char *cpu_model);
+void arm_translate_init(void);
int cpu_arm_exec(CPUARMState *s);
void cpu_arm_close(CPUARMState *s);
void do_interrupt(CPUARMState *);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 86470dbee..df09778ea 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5,6 +5,7 @@
#include "cpu.h"
#include "exec-all.h"
#include "gdbstub.h"
+#include "helpers.h"
static uint32_t cortexa8_cp15_c0_c1[8] =
{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 };
@@ -174,6 +175,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
{
CPUARMState *env;
uint32_t id;
+ static int inited = 0;
id = cpu_arm_find_by_name(cpu_model);
if (id == 0)
@@ -182,6 +184,11 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
if (!env)
return NULL;
cpu_exec_init(env);
+ if (!inited) {
+ inited = 1;
+ arm_translate_init();
+ }
+
env->cpu_model_str = cpu_model;
env->cp15.c0_cpuid = id;
cpu_reset(env);
@@ -315,6 +322,24 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask);
}
+#define HELPER(x) helper_##x
+/* Sign/zero extend */
+uint32_t HELPER(sxtb16)(uint32_t x)
+{
+ uint32_t res;
+ res = (uint16_t)(int8_t)x;
+ res |= (uint32_t)(int8_t)(x >> 16) << 16;
+ return res;
+}
+
+uint32_t HELPER(uxtb16)(uint32_t x)
+{
+ uint32_t res;
+ res = (uint16_t)(uint8_t)x;
+ res |= (uint32_t)(uint8_t)(x >> 16) << 16;
+ return res;
+}
+
#if defined(CONFIG_USER_ONLY)
void do_interrupt (CPUState *env)
@@ -1861,3 +1886,4 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
}
#endif
+
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
new file mode 100644
index 000000000..577f5ee40
--- /dev/null
+++ b/target-arm/helpers.h
@@ -0,0 +1,6 @@
+#ifndef DEF_HELPER
+#define DEF_HELPER(name, ret, args) ret helper_##name args;
+#endif
+
+DEF_HELPER(sxtb16, uint32_t, (uint32_t))
+DEF_HELPER(uxtb16, uint32_t, (uint32_t))
diff --git a/target-arm/op.c b/target-arm/op.c
index c2d33ca32..9a0167527 100644
--- a/target-arm/op.c
+++ b/target-arm/op.c
@@ -20,122 +20,6 @@
*/
#include "exec.h"
-#define REGNAME r0
-#define REG (env->regs[0])
-#include "op_template.h"
-
-#define REGNAME r1
-#define REG (env->regs[1])
-#include "op_template.h"
-
-#define REGNAME r2
-#define REG (env->regs[2])
-#include "op_template.h"
-
-#define REGNAME r3
-#define REG (env->regs[3])
-#include "op_template.h"
-
-#define REGNAME r4
-#define REG (env->regs[4])
-#include "op_template.h"
-
-#define REGNAME r5
-#define REG (env->regs[5])
-#include "op_template.h"
-
-#define REGNAME r6
-#define REG (env->regs[6])
-#include "op_template.h"
-
-#define REGNAME r7
-#define REG (env->regs[7])
-#include "op_template.h"
-
-#define REGNAME r8
-#define REG (env->regs[8])
-#include "op_template.h"
-
-#define REGNAME r9
-#define REG (env->regs[9])
-#include "op_template.h"
-
-#define REGNAME r10
-#define REG (env->regs[10])
-#include "op_template.h"
-
-#define REGNAME r11
-#define REG (env->regs[11])
-#include "op_template.h"
-
-#define REGNAME r12
-#define REG (env->regs[12])
-#include "op_template.h"
-
-#define REGNAME r13
-#define REG (env->regs[13])
-#include "op_template.h"
-
-#define REGNAME r14
-#define REG (env->regs[14])
-#include "op_template.h"
-
-#define REGNAME r15
-#define REG (env->regs[15])
-#define SET_REG(x) REG = x & ~(uint32_t)1
-#include "op_template.h"
-
-void OPPROTO op_bx_T0(void)
-{
- env->regs[15] = T0 & ~(uint32_t)1;
- env->thumb = (T0 & 1) != 0;
-}
-
-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_mov_CF_T1(void)
-{
- env->CF = ((uint32_t)T1) >> 31;
-}
-
-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;
@@ -146,11 +30,6 @@ void OPPROTO op_addl_T0_T1_cc(void)
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;
@@ -169,11 +48,6 @@ void OPPROTO op_adcl_T0_T1_cc(void)
#define OPSUB(sub, sbc, res, T0, T1) \
\
-void OPPROTO op_ ## sub ## l_T0_T1(void) \
-{ \
- res = T0 - T1; \
-} \
- \
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
{ \
unsigned int src1; \
@@ -211,46 +85,6 @@ OPSUB(sub, sbc, T0, T0, T1)
OPSUB(rsb, rsc, T0, 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_T0(void)
-{
- T0 = ~T0;
-}
-
-void OPPROTO op_notl_T1(void)
-{
- T1 = ~T1;
-}
-
-void OPPROTO op_logic_T0_cc(void)
-{
- env->NZF = T0;
-}
-
-void OPPROTO op_logic_T1_cc(void)
-{
- env->NZF = T1;
-}
-
#define EIP (env->regs[15])
void OPPROTO op_test_eq(void)
@@ -485,51 +319,6 @@ void OPPROTO op_clrex(void)
/* shifts */
-/* Used by NEON. */
-void OPPROTO op_shll_T0_im(void)
-{
- T1 = T1 << PARAM1;
-}
-
-/* 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_shrl_T1_0(void)
-{
- T1 = 0;
-}
-
-void OPPROTO op_sarl_T1_im(void)
-{
- T1 = (int32_t)T1 >> PARAM1;
-}
-
-void OPPROTO op_sarl_T1_0(void)
-{
- T1 = (int32_t)T1 >> 31;
-}
-
-void OPPROTO op_rorl_T1_im(void)
-{
- int shift;
- shift = PARAM1;
- T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
-}
-
-void OPPROTO op_rrxl_T1(void)
-{
- T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31);
-}
-
/* T1 based, set C flag */
void OPPROTO op_shll_T1_im_cc(void)
{
@@ -577,44 +366,6 @@ void OPPROTO op_rrxl_T1_cc(void)
env->CF = c;
}
-/* 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_shrl_T2_0(void)
-{
- T2 = 0;
-}
-
-void OPPROTO op_sarl_T2_im(void)
-{
- T2 = (int32_t)T2 >> PARAM1;
-}
-
-void OPPROTO op_sarl_T2_0(void)
-{
- T2 = (int32_t)T2 >> 31;
-}
-
-void OPPROTO op_rorl_T2_im(void)
-{
- int shift;
- shift = PARAM1;
- T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift));
-}
-
-void OPPROTO op_rrxl_T2(void)
-{
- T2 = ((uint32_t)T2 >> 1) | ((uint32_t)env->CF << 31);
-}
-
/* T1 based, use T0 as shift count */
void OPPROTO op_shll_T1_T0(void)
@@ -733,53 +484,6 @@ void OPPROTO op_clz_T0(void)
FORCE_RET();
}
-void OPPROTO op_sarl_T0_im(void)
-{
- T0 = (int32_t)T0 >> PARAM1;
-}
-
-/* Sign/zero extend */
-void OPPROTO op_sxth_T0(void)
-{
- T0 = (int16_t)T0;
-}
-
-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)
@@ -1369,31 +1073,6 @@ void OPPROTO op_movl_user_T0(void)
FORCE_RET();
}
-void OPPROTO op_movl_T0_T1(void)
-{
- T0 = T1;
-}
-
-void OPPROTO op_movl_T0_T2(void)
-{
- T0 = T2;
-}
-
-void OPPROTO op_movl_T1_T0(void)
-{
- T1 = T0;
-}
-
-void OPPROTO op_movl_T1_T2(void)
-{
- T1 = T2;
-}
-
-void OPPROTO op_movl_T2_T0(void)
-{
- T2 = T0;
-}
-
/* ARMv6 Media instructions. */
/* Note that signed overflow is undefined in C. The following routines are
@@ -1769,15 +1448,6 @@ void OPPROTO op_usat16_T1(void)
}
/* Dual 16-bit add. */
-void OPPROTO op_add16_T1_T2(void)
-{
- uint32_t mask;
- mask = (T0 & T1) & 0x8000;
- T0 ^= ~0x8000;
- T1 ^= ~0x8000;
- T0 = (T0 + T1) ^ mask;
-}
-
static inline uint8_t do_usad(uint8_t a, uint8_t b)
{
if (a > b)
diff --git a/target-arm/op_template.h b/target-arm/op_template.h
deleted file mode 100644
index 33d53c05a..000000000
--- a/target-arm/op_template.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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
- */
-
-#ifndef SET_REG
-#define SET_REG(x) REG = x
-#endif
-
-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)
-{
- SET_REG (T0);
-}
-
-void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
-{
- SET_REG (T1);
-}
-
-#undef REG
-#undef REGNAME
-#undef SET_REG
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 6de78f8ca..ef529eb16 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -29,6 +29,7 @@
#include "exec-all.h"
#include "disas.h"
#include "tcg-op.h"
+#include "helpers.h"
#define ENABLE_ARCH_5J 0
#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
@@ -73,6 +74,240 @@ typedef struct DisasContext {
extern FILE *logfile;
extern int loglevel;
+static TCGv cpu_env;
+/* FIXME: These should be removed. */
+static TCGv cpu_T[3];
+
+/* initialize TCG globals. */
+void arm_translate_init(void)
+{
+ cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
+
+ cpu_T[0] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG1, "T0");
+ cpu_T[1] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG2, "T1");
+ cpu_T[2] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG3, "T2");
+}
+
+/* The code generator doesn't like lots of temporaries, so maintain our own
+ cache for reuse within a function. */
+#define MAX_TEMPS 8
+static int num_temps;
+static TCGv temps[MAX_TEMPS];
+
+/* Allocate a temporary variable. */
+static TCGv new_tmp(void)
+{
+ TCGv tmp;
+ if (num_temps == MAX_TEMPS)
+ abort();
+
+ if (GET_TCGV(temps[num_temps]))
+ return temps[num_temps++];
+
+ tmp = tcg_temp_new(TCG_TYPE_I32);
+ temps[num_temps++] = tmp;
+ return tmp;
+}
+
+/* Release a temporary variable. */
+static void dead_tmp(TCGv tmp)
+{
+ int i;
+ num_temps--;
+ i = num_temps;
+ if (GET_TCGV(temps[i]) == GET_TCGV(tmp))
+ return;
+
+ /* Shuffle this temp to the last slot. */
+ while (GET_TCGV(temps[i]) != GET_TCGV(tmp))
+ i--;
+ while (i < num_temps) {
+ temps[i] = temps[i + 1];
+ i++;
+ }
+ temps[i] = tmp;
+}
+
+/* Set a variable to the value of a CPU register. */
+static void load_reg_var(DisasContext *s, TCGv var, int reg)
+{
+ if (reg == 15) {
+ uint32_t addr;
+ /* normaly, since we updated PC, we need only to add one insn */
+ if (s->thumb)
+ addr = (long)s->pc + 2;
+ else
+ addr = (long)s->pc + 4;
+ tcg_gen_movi_i32(var, addr);
+ } else {
+ tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
+ }
+}
+
+/* Create a new temporary and set it to the value of a CPU register. */
+static inline TCGv load_reg(DisasContext *s, int reg)
+{
+ TCGv tmp = new_tmp();
+ load_reg_var(s, tmp, reg);
+ return tmp;
+}
+
+/* Set a CPU register. The source must be a temporary and will be
+ marked as dead. */
+static void store_reg(DisasContext *s, int reg, TCGv var)
+{
+ if (reg == 15) {
+ tcg_gen_andi_i32(var, var, ~1);
+ s->is_jmp = DISAS_JUMP;
+ }
+ tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
+ dead_tmp(var);
+}
+
+
+/* Basic operations. */
+#define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
+#define gen_op_movl_T0_T2() tcg_gen_mov_i32(cpu_T[0], cpu_T[2])
+#define gen_op_movl_T1_T0() tcg_gen_mov_i32(cpu_T[1], cpu_T[0])
+#define gen_op_movl_T1_T2() tcg_gen_mov_i32(cpu_T[1], cpu_T[2])
+#define gen_op_movl_T2_T0() tcg_gen_mov_i32(cpu_T[2], cpu_T[0])
+#define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im)
+#define gen_op_movl_T1_im(im) tcg_gen_movi_i32(cpu_T[1], im)
+#define gen_op_movl_T2_im(im) tcg_gen_movi_i32(cpu_T[2], im)
+
+#define gen_op_addl_T1_im(im) tcg_gen_addi_i32(cpu_T[1], cpu_T[1], im)
+#define gen_op_addl_T0_T1() tcg_gen_add_i32(cpu_T[0], cpu_T[0], cpu_T[1])
+#define gen_op_subl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[0], cpu_T[1])
+#define gen_op_rsbl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[1], cpu_T[0])
+
+#define gen_op_andl_T0_T1() tcg_gen_and_i32(cpu_T[0], cpu_T[0], cpu_T[1])
+#define gen_op_xorl_T0_T1() tcg_gen_xor_i32(cpu_T[0], cpu_T[0], cpu_T[1])
+#define gen_op_orl_T0_T1() tcg_gen_or_i32(cpu_T[0], cpu_T[0], cpu_T[1])
+#define gen_op_notl_T0() tcg_gen_not_i32(cpu_T[0], cpu_T[0])
+#define gen_op_notl_T1() tcg_gen_not_i32(cpu_T[1], cpu_T[1])
+#define gen_op_logic_T0_cc() gen_logic_CC(cpu_T[0]);
+#define gen_op_logic_T1_cc() gen_logic_CC(cpu_T[1]);
+
+#define gen_op_shll_T0_im(im) tcg_gen_shli_i32(cpu_T[0], cpu_T[0], im)
+#define gen_op_shll_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im)
+#define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im)
+#define gen_op_sarl_T1_im(im) tcg_gen_sari_i32(cpu_T[1], cpu_T[1], im)
+#define gen_op_rorl_T1_im(im) tcg_gen_rori_i32(cpu_T[1], cpu_T[1], im)
+
+/* Value extensions. */
+#define gen_uxtb(var) tcg_gen_andi_i32(var, var, 0xff)
+#define gen_uxth(var) tcg_gen_andi_i32(var, var, 0xffff)
+#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
+#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
+
+#define HELPER_ADDR(x) helper_##x
+
+#define gen_sxtb16(var) tcg_gen_helper_1_1(HELPER_ADDR(sxtb16), var, var)
+#define gen_uxtb16(var) tcg_gen_helper_1_1(HELPER_ADDR(uxtb16), var, var)
+
+/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
+ tmp = (t0 ^ t1) & 0x8000;
+ t0 &= ~0x8000;
+ t1 &= ~0x8000;
+ t0 = (t0 + t1) ^ tmp;
+ */
+
+static void gen_add16(TCGv t0, TCGv t1)
+{
+ TCGv tmp = new_tmp();
+ tcg_gen_xor_i32(tmp, t0, t1);
+ tcg_gen_andi_i32(tmp, tmp, 0x8000);
+ tcg_gen_andi_i32(t0, t0, ~0x8000);
+ tcg_gen_andi_i32(t1, t1, ~0x8000);
+ tcg_gen_add_i32(t0, t0, t1);
+ tcg_gen_xor_i32(t0, t0, tmp);
+ dead_tmp(tmp);
+ dead_tmp(t1);
+}
+
+/* Set CF to the top bit of var. */
+static void gen_set_CF_bit31(TCGv var)
+{
+ TCGv tmp = new_tmp();
+ tcg_gen_shri_i32(tmp, var, 31);
+ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, CF));
+ dead_tmp(tmp);
+}
+
+/* Set N and Z flags from var. */
+static inline void gen_logic_CC(TCGv var)
+{
+ tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NZF));
+}
+
+/* T0 += T1 + CF. */
+static void gen_adc_T0_T1(void)
+{
+ TCGv tmp = new_tmp();
+ gen_op_addl_T0_T1();
+ tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, CF));
+ tcg_gen_add_i32(cpu_T[0], cpu_T[0], tmp);
+ dead_tmp(tmp);
+}
+
+/* FIXME: Implement this natively. */
+static inline void tcg_gen_not_i32(TCGv t0, TCGv t1)
+{
+ tcg_gen_xori_i32(t0, t1, ~0);
+}
+
+/* T0 &= ~T1. Clobbers T1. */
+/* FIXME: Implement bic natively. */
+static inline void gen_op_bicl_T0_T1(void)
+{
+ gen_op_notl_T1();
+ gen_op_andl_T0_T1();
+}
+
+/* FIXME: Implement this natively. */
+static void tcg_gen_rori_i32(TCGv t0, TCGv t1, int i)
+{
+ TCGv tmp;
+
+ if (i == 0)
+ return;
+
+ tmp = new_tmp();
+ tcg_gen_shri_i32(tmp, t1, i);
+ tcg_gen_shli_i32(t1, t1, 32 - i);
+ tcg_gen_or_i32(t0, t1, tmp);
+ dead_tmp(tmp);
+}
+
+/* Shift by immediate. Includes special handling for shift == 0. */
+static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift)
+{
+ if (shift != 0) {
+ switch (shiftop) {
+ case 0: tcg_gen_shli_i32(var, var, shift); break;
+ case 1: tcg_gen_shri_i32(var, var, shift); break;
+ case 2: tcg_gen_sari_i32(var, var, shift); break;
+ case 3: tcg_gen_rori_i32(var, var, shift); break;
+ }
+ } else {
+ TCGv tmp;
+
+ switch (shiftop) {
+ case 0: break;
+ case 1: tcg_gen_movi_i32(var, 0); break;
+ case 2: tcg_gen_sari_i32(var, var, 31); break;
+ case 3: /* rrx */
+ tcg_gen_shri_i32(var, var, 1);
+ tmp = new_tmp();
+ tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, CF));
+ tcg_gen_shli_i32(tmp, tmp, 31);
+ tcg_gen_or_i32(var, var, tmp);
+ dead_tmp(tmp);
+ break;
+ }
+ }
+};
+
#define PAS_OP(pfx) { \
gen_op_ ## pfx ## add16_T0_T1, \
gen_op_ ## pfx ## addsubx_T0_T1, \
@@ -154,34 +389,6 @@ const uint8_t table_logic_cc[16] = {
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 GenOpFunc *gen_shift_T1_0[4] = {
- NULL,
- gen_op_shrl_T1_0,
- gen_op_sarl_T1_0,
- gen_op_rrxl_T1,
-};
-
-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 GenOpFunc *gen_shift_T2_0[4] = {
- NULL,
- gen_op_shrl_T2_0,
- gen_op_sarl_T2_0,
- gen_op_rrxl_T2,
-};
-
static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
gen_op_shll_T1_im_cc,
gen_op_shrl_T1_im_cc,
@@ -210,108 +417,6 @@ static GenOpFunc *gen_shift_T1_T0_cc[4] = {
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 GenOpFunc1 *gen_shift_T0_im_thumb_cc[3] = {
gen_op_shll_T0_im_thumb_cc,
gen_op_shrl_T0_im_thumb_cc,
@@ -324,12 +429,19 @@ static GenOpFunc1 *gen_shift_T0_im_thumb[3] = {
gen_op_sarl_T0_im_thumb,
};
+/* Set PC and thumb state from T0. Clobbers T0. */
static inline void gen_bx(DisasContext *s)
{
- s->is_jmp = DISAS_UPDATE;
- gen_op_bx_T0();
-}
+ TCGv tmp;
+ s->is_jmp = DISAS_UPDATE;
+ tmp = new_tmp();
+ tcg_gen_andi_i32(tmp, cpu_T[0], 1);
+ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
+ dead_tmp(tmp);
+ tcg_gen_andi_i32(cpu_T[0], cpu_T[0], ~1);
+ tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, regs[15]));
+}
#if defined(CONFIG_USER_ONLY)
#define gen_ldst(name, s) gen_op_##name##_raw()
@@ -343,41 +455,38 @@ static inline void gen_bx(DisasContext *s)
} while (0)
#endif
-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 one insn */
- if (s->thumb)
- val = (long)s->pc + 2;
- else
- 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);
+ load_reg_var(s, cpu_T[0], reg);
}
static inline void gen_movl_T1_reg(DisasContext *s, int reg)
{
- gen_movl_TN_reg(s, reg, 1);
+ load_reg_var(s, cpu_T[1], reg);
}
static inline void gen_movl_T2_reg(DisasContext *s, int reg)
{
- gen_movl_TN_reg(s, reg, 2);
+ load_reg_var(s, cpu_T[2], reg);
+}
+
+static inline void gen_set_pc_T0(void)
+{
+ tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, regs[15]));
}
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
{
- gen_op_movl_reg_TN[t][reg]();
+ TCGv tmp;
+ if (reg == 15) {
+ tmp = new_tmp();
+ tcg_gen_andi_i32(tmp, cpu_T[t], ~1);
+ } else {
+ tmp = cpu_T[t];
+ }
+ tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[reg]));
if (reg == 15) {
+ dead_tmp(tmp);
s->is_jmp = DISAS_JUMP;
}
}
@@ -403,6 +512,7 @@ static inline void gen_lookup_tb(DisasContext *s)
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
{
int val, rm, shift, shiftop;
+ TCGv offset;
if (!(insn & (1 << 25))) {
/* immediate */
@@ -415,17 +525,14 @@ static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
/* shift/register */
rm = (insn) & 0xf;
shift = (insn >> 7) & 0x1f;
- gen_movl_T2_reg(s, rm);
shiftop = (insn >> 5) & 3;
- if (shift != 0) {
- gen_shift_T2_im[shiftop](shift);
- } else if (shiftop != 0) {
- gen_shift_T2_0[shiftop]();
- }
+ offset = load_reg(s, rm);
+ gen_arm_shift_im(offset, shiftop, shift);
if (!(insn & (1 << 23)))
- gen_op_subl_T1_T2();
+ tcg_gen_sub_i32(cpu_T[1], cpu_T[1], offset);
else
- gen_op_addl_T1_T2();
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], offset);
+ dead_tmp(offset);
}
}
@@ -433,6 +540,7 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
int extra)
{
int val, rm;
+ TCGv offset;
if (insn & (1 << 22)) {
/* immediate */
@@ -447,11 +555,12 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
if (extra)
gen_op_addl_T1_im(extra);
rm = (insn) & 0xf;
- gen_movl_T2_reg(s, rm);
+ offset = load_reg(s, rm);
if (!(insn & (1 << 23)))
- gen_op_subl_T1_T2();
+ tcg_gen_sub_i32(cpu_T[1], cpu_T[1], offset);
else
- gen_op_addl_T1_T2();
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], offset);
+ dead_tmp(offset);
}
}
@@ -979,7 +1088,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
case 3:
return 1;
}
- gen_op_movl_reg_TN[0][rd]();
+ gen_movl_reg_T0(s, rd);
break;
case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
if ((insn & 0x000ff008) != 0x0003f000)
@@ -1531,21 +1640,21 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_M0_wRn(wrd);
switch ((insn >> 16) & 0xf) {
case 0x0: /* TMIA */
- gen_op_movl_TN_reg[0][rd0]();
- gen_op_movl_TN_reg[1][rd1]();
+ gen_movl_T0_reg(s, rd0);
+ gen_movl_T1_reg(s, rd1);
gen_op_iwmmxt_muladdsl_M0_T0_T1();
break;
case 0x8: /* TMIAPH */
- gen_op_movl_TN_reg[0][rd0]();
- gen_op_movl_TN_reg[1][rd1]();
+ gen_movl_T0_reg(s, rd0);
+ gen_movl_T1_reg(s, rd1);
gen_op_iwmmxt_muladdsw_M0_T0_T1();
break;
case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
- gen_op_movl_TN_reg[1][rd0]();
+ gen_movl_T1_reg(s, rd0);
if (insn & (1 << 16))
gen_op_shrl_T1_im(16);
gen_op_movl_T0_T1();
- gen_op_movl_TN_reg[1][rd1]();
+ gen_movl_T1_reg(s, rd1);
if (insn & (1 << 17))
gen_op_shrl_T1_im(16);
gen_op_iwmmxt_muladdswl_M0_T0_T1();
@@ -1580,24 +1689,24 @@ static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
switch ((insn >> 16) & 0xf) {
case 0x0: /* MIA */
- gen_op_movl_TN_reg[0][rd0]();
- gen_op_movl_TN_reg[1][rd1]();
+ gen_movl_T0_reg(s, rd0);
+ gen_movl_T1_reg(s, rd1);
gen_op_iwmmxt_muladdsl_M0_T0_T1();
break;
case 0x8: /* MIAPH */
- gen_op_movl_TN_reg[0][rd0]();
- gen_op_movl_TN_reg[1][rd1]();
+ gen_movl_T0_reg(s, rd0);
+ gen_movl_T1_reg(s, rd1);
gen_op_iwmmxt_muladdsw_M0_T0_T1();
break;
case 0xc: /* MIABB */
case 0xd: /* MIABT */
case 0xe: /* MIATB */
case 0xf: /* MIATT */
- gen_op_movl_TN_reg[1][rd0]();
+ gen_movl_T1_reg(s, rd0);
if (insn & (1 << 16))
gen_op_shrl_T1_im(16);
gen_op_movl_T0_T1();
- gen_op_movl_TN_reg[1][rd1]();
+ gen_movl_T1_reg(s, rd1);
if (insn & (1 << 17))
gen_op_shrl_T1_im(16);
gen_op_iwmmxt_muladdswl_M0_T0_T1();
@@ -1621,13 +1730,13 @@ static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
if (insn & ARM_CP_RW_BIT) { /* MRA */
gen_op_iwmmxt_movl_T0_T1_wRn(acc);
- gen_op_movl_reg_TN[0][rdlo]();
+ gen_movl_reg_T0(s, rdlo);
gen_op_movl_T0_im((1 << (40 - 32)) - 1);
gen_op_andl_T0_T1();
- gen_op_movl_reg_TN[0][rdhi]();
+ gen_movl_reg_T0(s, rdhi);
} else { /* MAR */
- gen_op_movl_TN_reg[0][rdlo]();
- gen_op_movl_TN_reg[1][rdhi]();
+ gen_movl_T0_reg(s, rdlo);
+ gen_movl_T1_reg(s, rdhi);
gen_op_iwmmxt_movl_wRn_T0_T1(acc);
}
return 0;
@@ -1650,14 +1759,14 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
if (!env->cp[cp].cp_read)
return 1;
gen_op_movl_T0_im((uint32_t) s->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_movl_T0_cp(insn);
gen_movl_reg_T0(s, rd);
} else {
if (!env->cp[cp].cp_write)
return 1;
gen_op_movl_T0_im((uint32_t) s->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_movl_T0_reg(s, rd);
gen_op_movl_cp_T0(insn);
}
@@ -1713,7 +1822,7 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
|| (insn & 0x0fff0fff) == 0x0e070f58) {
/* Wait for interrupt. */
gen_op_movl_T0_im((long)s->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
s->is_jmp = DISAS_WFI;
return 0;
}
@@ -1817,9 +1926,9 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (offset)
gen_op_shrl_T1_im(offset);
if (insn & (1 << 23))
- gen_op_uxtb_T1();
+ gen_uxtb(cpu_T[1]);
else
- gen_op_sxtb_T1();
+ gen_sxtb(cpu_T[1]);
break;
case 1:
NEON_GET_REG(T1, rn, pass);
@@ -1827,13 +1936,13 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (offset) {
gen_op_shrl_T1_im(16);
} else {
- gen_op_uxth_T1();
+ gen_uxth(cpu_T[1]);
}
} else {
if (offset) {
gen_op_sarl_T1_im(16);
} else {
- gen_op_sxth_T1();
+ gen_sxth(cpu_T[1]);
}
}
break;
@@ -2418,11 +2527,11 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
tcg_gen_goto_tb(n);
gen_op_movl_T0_im(dest);
- gen_op_movl_r15_T0();
+ gen_set_pc_T0();
tcg_gen_exit_tb((long)tb + n);
} else {
gen_op_movl_T0_im(dest);
- gen_op_movl_r15_T0();
+ gen_set_pc_T0();
tcg_gen_exit_tb(0);
}
}
@@ -2444,13 +2553,13 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
static inline void gen_mulxy(int x, int y)
{
if (x)
- gen_op_sarl_T0_im(16);
+ tcg_gen_sari_i32(cpu_T[0], cpu_T[0], 16);
else
- gen_op_sxth_T0();
+ gen_sxth(cpu_T[0]);
if (y)
gen_op_sarl_T1_im(16);
else
- gen_op_sxth_T1();
+ gen_sxth(cpu_T[1]);
gen_op_mul_T0_T1();
}
@@ -2501,7 +2610,7 @@ static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
/* Generate an old-style exception return. */
static void gen_exception_return(DisasContext *s)
{
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_movl_T0_spsr();
gen_op_movl_cpsr_T0(0xffffffff);
s->is_jmp = DISAS_UPDATE;
@@ -2512,7 +2621,7 @@ static void gen_rfe(DisasContext *s)
{
gen_op_movl_cpsr_T0(0xffffffff);
gen_op_movl_T0_T2();
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
s->is_jmp = DISAS_UPDATE;
}
@@ -2529,7 +2638,7 @@ static void gen_nop_hint(DisasContext *s, int val)
switch (val) {
case 3: /* wfi */
gen_op_movl_T0_im((long)s->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
s->is_jmp = DISAS_WFI;
break;
case 2: /* wfe */
@@ -3011,14 +3120,18 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
}
if (rm != 15) {
- gen_movl_T1_reg(s, rn);
+ TCGv base;
+
+ base = load_reg(s, rn);
if (rm == 13) {
- gen_op_addl_T1_im(stride);
+ tcg_gen_addi_i32(base, base, stride);
} else {
- gen_movl_T2_reg(s, rm);
- gen_op_addl_T1_T2();
+ TCGv index;
+ index = load_reg(s, rm);
+ tcg_gen_add_i32(base, base, index);
+ dead_tmp(index);
}
- gen_movl_reg_T1(s, rn);
+ store_reg(s, rn, base);
}
return 0;
}
@@ -4626,6 +4739,7 @@ static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
static void disas_arm_insn(CPUState * env, DisasContext *s)
{
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
+ TCGv tmp;
insn = ldl_code(s->pc);
s->pc += 4;
@@ -4936,7 +5050,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 7: /* bkpt */
gen_set_condexec(s);
gen_op_movl_T0_im((long)s->pc - 4);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_bkpt();
s->is_jmp = DISAS_JUMP;
break;
@@ -4954,7 +5068,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
if (sh & 4)
gen_op_sarl_T1_im(16);
else
- gen_op_sxth_T1();
+ gen_sxth(cpu_T[1]);
gen_op_imulw_T0_T1();
if ((sh & 2) == 0) {
gen_movl_T1_reg(s, rn);
@@ -5001,7 +5115,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
val = (val >> shift) | (val << (32 - shift));
gen_op_movl_T1_im(val);
if (logic_cc && shift)
- gen_op_mov_CF_T1();
+ gen_set_CF_bit31(cpu_T[1]);
} else {
/* register */
rm = (insn) & 0xf;
@@ -5009,18 +5123,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
shiftop = (insn >> 5) & 3;
if (!(insn & (1 << 4))) {
shift = (insn >> 7) & 0x1f;
- if (shift != 0) {
- if (logic_cc) {
+ if (logic_cc) {
+ if (shift != 0) {
gen_shift_T1_im_cc[shiftop](shift);
- } else {
- gen_shift_T1_im[shiftop](shift);
- }
- } else if (shiftop != 0) {
- if (logic_cc) {
+ } else if (shiftop != 0) {
gen_shift_T1_0_cc[shiftop]();
- } else {
- gen_shift_T1_0[shiftop]();
}
+ } else {
+ gen_arm_shift_im(cpu_T[1], shiftop, shift);
}
} else {
rs = (insn >> 8) & 0xf;
@@ -5083,7 +5193,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
if (set_cc)
gen_op_adcl_T0_T1_cc();
else
- gen_op_adcl_T0_T1();
+ gen_adc_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x06:
@@ -5389,20 +5499,21 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
gen_op_rorl_T1_im(shift * 8);
op1 = (insn >> 20) & 7;
switch (op1) {
- case 0: gen_op_sxtb16_T1(); break;
- case 2: gen_op_sxtb_T1(); break;
- case 3: gen_op_sxth_T1(); break;
- case 4: gen_op_uxtb16_T1(); break;
- case 6: gen_op_uxtb_T1(); break;
- case 7: gen_op_uxth_T1(); break;
+ case 0: gen_sxtb16(cpu_T[1]); break;
+ case 2: gen_sxtb(cpu_T[1]); break;
+ case 3: gen_sxth(cpu_T[1]); break;
+ case 4: gen_uxtb16(cpu_T[1]); break;
+ case 6: gen_uxtb(cpu_T[1]); break;
+ case 7: gen_uxth(cpu_T[1]); break;
default: goto illegal_op;
}
if (rn != 15) {
- gen_movl_T2_reg(s, rn);
+ tmp = load_reg(s, rn);
if ((op1 & 3) == 0) {
- gen_op_add16_T1_T2();
+ gen_add16(cpu_T[1], tmp);
} else {
- gen_op_addl_T1_T2();
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
+ dead_tmp(tmp);
}
}
gen_movl_reg_T1(s, rd);
@@ -5667,7 +5778,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
if (i == 15) {
/* special case: r15 = PC + 8 */
val = (long)s->pc + 4;
- gen_op_movl_TN_im[0](val);
+ gen_op_movl_T0_im(val);
} else if (user) {
gen_op_movl_T0_user(i);
} else {
@@ -5723,7 +5834,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
val = (int32_t)s->pc;
if (insn & (1 << 24)) {
gen_op_movl_T0_im(val);
- gen_op_movl_reg_TN[0][14]();
+ gen_movl_reg_T0(s, 14);
}
offset = (((int32_t)insn << 8) >> 8);
val += (offset << 2) + 4;
@@ -5740,14 +5851,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0xf:
/* swi */
gen_op_movl_T0_im((long)s->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
s->is_jmp = DISAS_SWI;
break;
default:
illegal_op:
gen_set_condexec(s);
gen_op_movl_T0_im((long)s->pc - 4);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_undef_insn();
s->is_jmp = DISAS_JUMP;
break;
@@ -5806,7 +5917,7 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out)
if (conds)
gen_op_adcl_T0_T1_cc();
else
- gen_op_adcl_T0_T1();
+ gen_adc_T0_T1();
break;
case 11: /* sbc */
if (conds)
@@ -5832,7 +5943,7 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out)
if (logic_cc) {
gen_op_logic_T0_cc();
if (shifter_out)
- gen_op_mov_CF_T1();
+ gen_set_CF_bit31(cpu_T[1]);
}
return 0;
}
@@ -5843,6 +5954,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
{
uint32_t insn, imm, shift, offset, addr;
uint32_t rd, rn, rm, rs;
+ TCGv tmp;
int op;
int shiftop;
int conds;
@@ -5966,13 +6078,15 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
} else {
gen_movl_T1_reg(s, rn);
}
- gen_movl_T2_reg(s, rm);
- gen_op_addl_T1_T2();
+ tmp = load_reg(s, rm);
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
if (insn & (1 << 4)) {
/* tbh */
- gen_op_addl_T1_T2();
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
+ dead_tmp(tmp);
gen_ldst(lduw, s);
} else { /* tbb */
+ dead_tmp(tmp);
gen_ldst(ldub, s);
}
gen_op_jmp_T0_im(s->pc);
@@ -6126,18 +6240,14 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
conds = (insn & (1 << 20)) != 0;
logic_cc = (conds && thumb2_logic_op(op));
- if (shift != 0) {
- if (logic_cc) {
+ if (logic_cc) {
+ if (shift != 0) {
gen_shift_T1_im_cc[shiftop](shift);
- } else {
- gen_shift_T1_im[shiftop](shift);
- }
- } else if (shiftop != 0) {
- if (logic_cc) {
+ } else if (shiftop != 0) {
gen_shift_T1_0_cc[shiftop]();
- } else {
- gen_shift_T1_0[shiftop]();
}
+ } else {
+ gen_arm_shift_im(cpu_T[1], shiftop, shift);
}
if (gen_thumb2_data_op(s, op, conds, 0))
goto illegal_op;
@@ -6172,20 +6282,21 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
gen_op_rorl_T1_im(shift * 8);
op = (insn >> 20) & 7;
switch (op) {
- case 0: gen_op_sxth_T1(); break;
- case 1: gen_op_uxth_T1(); break;
- case 2: gen_op_sxtb16_T1(); break;
- case 3: gen_op_uxtb16_T1(); break;
- case 4: gen_op_sxtb_T1(); break;
- case 5: gen_op_uxtb_T1(); break;
+ case 0: gen_sxth(cpu_T[1]); break;
+ case 1: gen_uxth(cpu_T[1]); break;
+ case 2: gen_sxtb16(cpu_T[1]); break;
+ case 3: gen_uxtb16(cpu_T[1]); break;
+ case 4: gen_sxtb(cpu_T[1]); break;
+ case 5: gen_uxtb(cpu_T[1]); break;
default: goto illegal_op;
}
if (rn != 15) {
- gen_movl_T2_reg(s, rn);
+ tmp = load_reg(s, rn);
if ((op >> 1) == 1) {
- gen_op_add16_T1_T2();
+ gen_add16(cpu_T[1], tmp);
} else {
- gen_op_addl_T1_T2();
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
+ dead_tmp(tmp);
}
}
gen_movl_reg_T1(s, rd);
@@ -6286,7 +6397,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
if (op)
gen_op_sarl_T1_im(16);
else
- gen_op_sxth_T1();
+ gen_sxth(cpu_T[1]);
gen_op_imulw_T0_T1();
if (rs != 15)
{
@@ -6718,10 +6829,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
shift = (insn >> 4) & 0xf;
if (shift > 3)
goto illegal_op;
- gen_movl_T2_reg(s, rm);
+ tmp = load_reg(s, rm);
if (shift)
- gen_op_shll_T2_im(shift);
- gen_op_addl_T1_T2();
+ tcg_gen_shli_i32(tmp, tmp, shift);
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
+ dead_tmp(tmp);
break;
case 4: /* Negative offset. */
gen_op_addl_T1_im(-imm);
@@ -6733,7 +6845,6 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
imm = -imm;
/* Fall through. */
case 3: /* Post-increment. */
- gen_op_movl_T2_im(imm);
postinc = 1;
writeback = 1;
break;
@@ -6802,6 +6913,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
uint32_t val, insn, op, rm, rn, rd, shift, cond;
int32_t offset;
int i;
+ TCGv tmp;
if (s->condexec_mask) {
cond = s->condexec_cond;
@@ -6989,7 +7101,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
break;
case 0x5: /* adc */
if (s->condexec_mask)
- gen_op_adcl_T0_T1();
+ gen_adc_T0_T1();
else
gen_op_adcl_T0_T1_cc();
break;
@@ -7064,8 +7176,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
rm = (insn >> 6) & 7;
op = (insn >> 9) & 7;
gen_movl_T1_reg(s, rn);
- gen_movl_T2_reg(s, rm);
- gen_op_addl_T1_T2();
+ tmp = load_reg(s, rm);
+ tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
+ dead_tmp(tmp);
if (op < 3) /* store */
gen_movl_T0_reg(s, rd);
@@ -7106,8 +7219,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
rn = (insn >> 3) & 7;
gen_movl_T1_reg(s, rn);
val = (insn >> 4) & 0x7c;
- gen_op_movl_T2_im(val);
- gen_op_addl_T1_T2();
+ tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
if (insn & (1 << 11)) {
/* load */
@@ -7126,8 +7238,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
rn = (insn >> 3) & 7;
gen_movl_T1_reg(s, rn);
val = (insn >> 6) & 0x1f;
- gen_op_movl_T2_im(val);
- gen_op_addl_T1_T2();
+ tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
if (insn & (1 << 11)) {
/* load */
@@ -7146,8 +7257,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
rn = (insn >> 3) & 7;
gen_movl_T1_reg(s, rn);
val = (insn >> 5) & 0x3e;
- gen_op_movl_T2_im(val);
- gen_op_addl_T1_T2();
+ tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
if (insn & (1 << 11)) {
/* load */
@@ -7165,8 +7275,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
rd = (insn >> 8) & 7;
gen_movl_T1_reg(s, 13);
val = (insn & 0xff) * 4;
- gen_op_movl_T2_im(val);
- gen_op_addl_T1_T2();
+ tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
if (insn & (1 << 11)) {
/* load */
@@ -7201,13 +7310,12 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
switch (op) {
case 0:
/* adjust stack pointer */
- gen_movl_T1_reg(s, 13);
+ tmp = load_reg(s, 13);
val = (insn & 0x7f) * 4;
if (insn & (1 << 7))
val = -(int32_t)val;
- gen_op_movl_T2_im(val);
- gen_op_addl_T1_T2();
- gen_movl_reg_T1(s, 13);
+ tcg_gen_addi_i32(tmp, tmp, val);
+ store_reg(s, 13, tmp);
break;
case 2: /* sign/zero extend. */
@@ -7216,10 +7324,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
rm = (insn >> 3) & 7;
gen_movl_T1_reg(s, rm);
switch ((insn >> 6) & 3) {
- case 0: gen_op_sxth_T1(); break;
- case 1: gen_op_sxtb_T1(); break;
- case 2: gen_op_uxth_T1(); break;
- case 3: gen_op_uxtb_T1(); break;
+ case 0: gen_sxth(cpu_T[1]); break;
+ case 1: gen_sxtb(cpu_T[1]); break;
+ case 2: gen_uxth(cpu_T[1]); break;
+ case 3: gen_uxtb(cpu_T[1]); break;
}
gen_movl_reg_T1(s, rd);
break;
@@ -7235,10 +7343,8 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
offset += 4;
}
if ((insn & (1 << 11)) == 0) {
- gen_op_movl_T2_im(-offset);
- gen_op_addl_T1_T2();
+ gen_op_addl_T1_im(-offset);
}
- gen_op_movl_T2_im(4);
for (i = 0; i < 8; i++) {
if (insn & (1 << i)) {
if (insn & (1 << 11)) {
@@ -7251,7 +7357,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
gen_ldst(stl, s);
}
/* advance to the next address. */
- gen_op_addl_T1_T2();
+ gen_op_addl_T1_im(4);
}
}
if (insn & (1 << 8)) {
@@ -7265,11 +7371,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
gen_movl_T0_reg(s, 14);
gen_ldst(stl, s);
}
- gen_op_addl_T1_T2();
+ gen_op_addl_T1_im(4);
}
if ((insn & (1 << 11)) == 0) {
- gen_op_movl_T2_im(-offset);
- gen_op_addl_T1_T2();
+ gen_op_addl_T1_im(-offset);
}
/* write back the new stack pointer */
gen_movl_reg_T1(s, 13);
@@ -7308,7 +7413,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
case 0xe: /* bkpt */
gen_set_condexec(s);
gen_op_movl_T0_im((long)s->pc - 2);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_bkpt();
s->is_jmp = DISAS_JUMP;
break;
@@ -7363,7 +7468,6 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
/* load/store multiple */
rn = (insn >> 8) & 0x7;
gen_movl_T1_reg(s, rn);
- gen_op_movl_T2_im(4);
for (i = 0; i < 8; i++) {
if (insn & (1 << i)) {
if (insn & (1 << 11)) {
@@ -7376,7 +7480,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
gen_ldst(stl, s);
}
/* advance to the next address */
- gen_op_addl_T1_T2();
+ gen_op_addl_T1_im(4);
}
}
/* Base register writeback. */
@@ -7395,7 +7499,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
gen_set_condexec(s);
gen_op_movl_T0_im((long)s->pc | 1);
/* Don't set r15. */
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
s->is_jmp = DISAS_SWI;
break;
}
@@ -7434,7 +7538,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
undef32:
gen_set_condexec(s);
gen_op_movl_T0_im((long)s->pc - 4);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_undef_insn();
s->is_jmp = DISAS_JUMP;
return;
@@ -7442,7 +7546,7 @@ illegal_op:
undef:
gen_set_condexec(s);
gen_op_movl_T0_im((long)s->pc - 2);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_undef_insn();
s->is_jmp = DISAS_JUMP;
}
@@ -7461,6 +7565,9 @@ static inline int gen_intermediate_code_internal(CPUState *env,
uint32_t next_page_start;
/* generate intermediate code */
+ num_temps = 0;
+ memset(temps, 0, sizeof(temps));
+
pc_start = tb->pc;
dc->tb = tb;
@@ -7502,7 +7609,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
if (env->breakpoints[j] == dc->pc) {
gen_set_condexec(dc);
gen_op_movl_T0_im((long)dc->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
gen_op_debug();
dc->is_jmp = DISAS_JUMP;
/* Advance PC so that clearing the breakpoint will
@@ -7537,6 +7644,10 @@ static inline int gen_intermediate_code_internal(CPUState *env,
} else {
disas_arm_insn(env, dc);
}
+ if (num_temps) {
+ fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
+ num_temps = 0;
+ }
if (dc->condjmp && !dc->is_jmp) {
gen_set_label(dc->condlabel);
@@ -7572,7 +7683,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
}
if (dc->condjmp || !dc->is_jmp) {
gen_op_movl_T0_im((long)dc->pc);
- gen_op_movl_reg_TN[0][15]();
+ gen_set_pc_T0();
dc->condjmp = 0;
}
gen_set_condexec(dc);