 beddab753d
			
		
	
	
		beddab753d
		
	
	
	
	
		
			
			git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@785 c046a42c-6fe2-441c-8c8c-71466251a162
		
			
				
	
	
		
			849 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			849 lines
		
	
	
		
			23 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));
 | |
|     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;
 | |
| }
 |