850 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			850 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 *  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"
 | 
						|
 | 
						|
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;
 | 
						|
        if (val != 0)
 | 
						|
            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;
 | 
						|
        if (val != 0)
 | 
						|
            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_imull_T0_T1();
 | 
						|
                        else
 | 
						|
                            gen_op_mull_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 << 24))
 | 
						|
                    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;
 | 
						|
                    }
 | 
						|
                    gen_movl_reg_T0(s, rd);
 | 
						|
                } else {
 | 
						|
                    /* store */
 | 
						|
                    gen_movl_T0_reg(s, rd);
 | 
						|
                    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;
 | 
						|
        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 & CPU_LOG_TB_IN_ASM) {
 | 
						|
        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");
 | 
						|
        if (loglevel & (CPU_LOG_TB_OP)) {
 | 
						|
            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));
 | 
						|
    cpu_single_env = env;
 | 
						|
    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' : '-');
 | 
						|
}
 | 
						|
 | 
						|
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 | 
						|
{
 | 
						|
    return addr;
 | 
						|
}
 |