summaryrefslogtreecommitdiff
path: root/target-arm/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r--target-arm/translate.c903
1 files changed, 903 insertions, 0 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
new file mode 100644
index 0000000000..bffeefa4fb
--- /dev/null
+++ b/target-arm/translate.c
@@ -0,0 +1,903 @@
+/*
+ * 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.h"
+#include "exec-all.h"
+#include "disas.h"
+
+/* internal defines */
+typedef struct DisasContext {
+ uint8_t *pc;
+ int is_jmp;
+ struct TranslationBlock *tb;
+} DisasContext;
+
+#define DISAS_JUMP_NEXT 4
+
+/* 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.h"
+#undef DEF
+ NB_OPS,
+};
+
+#include "gen-op.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 = DISAS_JUMP_NEXT;
+ }
+ if (((insn & 0x0e000000) == 0 &&
+ (insn & 0x00000090) != 0x90) ||
+ ((insn & 0x0e000000) == (1 << 25))) {
+ 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 >> 8) & 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);
+ if (logic_cc)
+ gen_op_logic_T0_cc();
+ break;
+ case 0x01:
+ gen_op_xorl_T0_T1();
+ gen_movl_reg_T0(s, rd);
+ if (logic_cc)
+ gen_op_logic_T0_cc();
+ 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();
+ gen_op_logic_T0_cc();
+ }
+ break;
+ case 0x09:
+ if (set_cc) {
+ gen_op_xorl_T0_T1();
+ gen_op_logic_T0_cc();
+ }
+ 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);
+ if (logic_cc)
+ gen_op_logic_T0_cc();
+ break;
+ case 0x0d:
+ gen_movl_reg_T1(s, rd);
+ if (logic_cc)
+ gen_op_logic_T1_cc();
+ break;
+ case 0x0e:
+ gen_op_bicl_T0_T1();
+ gen_movl_reg_T0(s, rd);
+ if (logic_cc)
+ gen_op_logic_T0_cc();
+ break;
+ default:
+ case 0x0f:
+ gen_op_notl_T1();
+ gen_movl_reg_T1(s, rd);
+ if (logic_cc)
+ gen_op_logic_T1_cc();
+ break;
+ }
+ } 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_T0_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);
+ gen_movl_reg_T1(s, rn);
+ } else 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);
+ gen_movl_reg_T1(s, rn);
+ } else if (insn & (1 << 21))
+ gen_movl_reg_T1(s, rn); {
+ }
+ break;
+ case 0x08:
+ case 0x09:
+ {
+ int j, n;
+ /* load/store multiple words */
+ /* XXX: store correct base if write back */
+ if (insn & (1 << 22))
+ goto illegal_op; /* only usable in supervisor mode */
+ rn = (insn >> 16) & 0xf;
+ gen_movl_T1_reg(s, rn);
+
+ /* compute total size */
+ n = 0;
+ for(i=0;i<16;i++) {
+ if (insn & (1 << i))
+ n++;
+ }
+ /* XXX: test invalid n == 0 case ? */
+ if (insn & (1 << 23)) {
+ if (insn & (1 << 24)) {
+ /* pre increment */
+ gen_op_addl_T1_im(4);
+ } else {
+ /* post increment */
+ }
+ } else {
+ if (insn & (1 << 24)) {
+ /* pre decrement */
+ gen_op_addl_T1_im(-(n * 4));
+ } else {
+ /* post decrement */
+ if (n != 1)
+ gen_op_addl_T1_im(-((n - 1) * 4));
+ }
+ }
+ j = 0;
+ for(i=0;i<16;i++) {
+ if (insn & (1 << i)) {
+ if (insn & (1 << 20)) {
+ /* load */
+ gen_op_ldl_T0_T1();
+ gen_movl_reg_T0(s, i);
+ } else {
+ /* store */
+ if (i == 15) {
+ /* special case: r15 = PC + 12 */
+ val = (long)s->pc + 8;
+ gen_op_movl_TN_im[0](val);
+ } else {
+ gen_movl_T0_reg(s, i);
+ }
+ gen_op_stl_T0_T1();
+ }
+ j++;
+ /* no need to add after the last transfer */
+ if (j != n)
+ gen_op_addl_T1_im(4);
+ }
+ }
+ if (insn & (1 << 21)) {
+ /* write back */
+ if (insn & (1 << 23)) {
+ if (insn & (1 << 24)) {
+ /* pre increment */
+ } else {
+ /* post increment */
+ gen_op_addl_T1_im(4);
+ }
+ } else {
+ if (insn & (1 << 24)) {
+ /* pre decrement */
+ if (n != 1)
+ gen_op_addl_T1_im(-((n - 1) * 4));
+ } else {
+ /* post decrement */
+ gen_op_addl_T1_im(-(n * 4));
+ }
+ }
+ 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;
+ case 0xc:
+ case 0xd:
+ rd = (insn >> 12) & 0x7;
+ rn = (insn >> 16) & 0xf;
+ gen_movl_T1_reg(s, rn);
+ val = (insn) & 0xff;
+ if (!(insn & (1 << 23)))
+ val = -val;
+ switch((insn >> 8) & 0xf) {
+ case 0x1:
+ /* load/store */
+ if ((insn & (1 << 24)))
+ gen_op_addl_T1_im(val);
+ /* XXX: do it */
+ if (!(insn & (1 << 24)))
+ gen_op_addl_T1_im(val);
+ if (insn & (1 << 21))
+ gen_movl_reg_T1(s, rn);
+ break;
+ case 0x2:
+ {
+ int n, i;
+ /* load store multiple */
+ if ((insn & (1 << 24)))
+ gen_op_addl_T1_im(val);
+ switch(insn & 0x00408000) {
+ case 0x00008000: n = 1; break;
+ case 0x00400000: n = 2; break;
+ case 0x00408000: n = 3; break;
+ default: n = 4; break;
+ }
+ for(i = 0;i < n; i++) {
+ /* XXX: do it */
+ }
+ if (!(insn & (1 << 24)))
+ gen_op_addl_T1_im(val);
+ if (insn & (1 << 21))
+ gen_movl_reg_T1(s, rn);
+ }
+ break;
+ default:
+ goto illegal_op;
+ }
+ break;
+ case 0x0e:
+ /* float ops */
+ /* XXX: do it */
+ switch((insn >> 20) & 0xf) {
+ case 0x2: /* wfs */
+ break;
+ case 0x3: /* rfs */
+ break;
+ case 0x4: /* wfc */
+ break;
+ case 0x5: /* rfc */
+ break;
+ default:
+ goto illegal_op;
+ }
+ 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. */
+static inline int gen_intermediate_code_internal(CPUState *env,
+ 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));
+ switch(dc->is_jmp) {
+ case DISAS_JUMP_NEXT:
+ case DISAS_NEXT:
+ gen_op_jmp((long)dc->tb, (long)dc->pc);
+ break;
+ default:
+ case DISAS_JUMP:
+ /* indicate that the hash table must be used to find the next TB */
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ break;
+ case DISAS_TB_JUMP:
+ /* nothing more to generate */
+ break;
+ }
+ *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;
+}
+
+int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 0);
+}
+
+int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 1);
+}
+
+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, "PSR=%08x %c%c%c%c\n",
+ env->cpsr,
+ env->cpsr & (1 << 31) ? 'N' : '-',
+ env->cpsr & (1 << 30) ? 'Z' : '-',
+ env->cpsr & (1 << 29) ? 'C' : '-',
+ env->cpsr & (1 << 28) ? 'V' : '-');
+}