]>
git.proxmox.com Git - mirror_qemu.git/blob - target-arm/translate.c
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2005 CodeSourcery, LLC
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 /* internal defines */
32 typedef struct DisasContext
{
35 struct TranslationBlock
*tb
;
36 int singlestep_enabled
;
39 #define DISAS_JUMP_NEXT 4
41 /* XXX: move that elsewhere */
42 static uint16_t *gen_opc_ptr
;
43 static uint32_t *gen_opparam_ptr
;
48 #define DEF(s, n, copy_size) INDEX_op_ ## s,
56 static GenOpFunc2
*gen_test_cc
[14] = {
73 const uint8_t table_logic_cc
[16] = {
92 static GenOpFunc1
*gen_shift_T1_im
[4] = {
99 static GenOpFunc
*gen_shift_T1_0
[4] = {
106 static GenOpFunc1
*gen_shift_T2_im
[4] = {
113 static GenOpFunc
*gen_shift_T2_0
[4] = {
120 static GenOpFunc1
*gen_shift_T1_im_cc
[4] = {
121 gen_op_shll_T1_im_cc
,
122 gen_op_shrl_T1_im_cc
,
123 gen_op_sarl_T1_im_cc
,
124 gen_op_rorl_T1_im_cc
,
127 static GenOpFunc
*gen_shift_T1_0_cc
[4] = {
134 static GenOpFunc
*gen_shift_T1_T0
[4] = {
141 static GenOpFunc
*gen_shift_T1_T0_cc
[4] = {
142 gen_op_shll_T1_T0_cc
,
143 gen_op_shrl_T1_T0_cc
,
144 gen_op_sarl_T1_T0_cc
,
145 gen_op_rorl_T1_T0_cc
,
148 static GenOpFunc
*gen_op_movl_TN_reg
[3][16] = {
205 static GenOpFunc
*gen_op_movl_reg_TN
[2][16] = {
244 static GenOpFunc1
*gen_op_movl_TN_im
[3] = {
250 static GenOpFunc1
*gen_shift_T0_im_thumb
[3] = {
251 gen_op_shll_T0_im_thumb
,
252 gen_op_shrl_T0_im_thumb
,
253 gen_op_sarl_T0_im_thumb
,
256 static inline void gen_bx(DisasContext
*s
)
258 s
->is_jmp
= DISAS_UPDATE
;
262 static inline void gen_movl_TN_reg(DisasContext
*s
, int reg
, int t
)
267 /* normaly, since we updated PC, we need only to add 4 */
268 val
= (long)s
->pc
+ 4;
269 gen_op_movl_TN_im
[t
](val
);
271 gen_op_movl_TN_reg
[t
][reg
]();
275 static inline void gen_movl_T0_reg(DisasContext
*s
, int reg
)
277 gen_movl_TN_reg(s
, reg
, 0);
280 static inline void gen_movl_T1_reg(DisasContext
*s
, int reg
)
282 gen_movl_TN_reg(s
, reg
, 1);
285 static inline void gen_movl_T2_reg(DisasContext
*s
, int reg
)
287 gen_movl_TN_reg(s
, reg
, 2);
290 static inline void gen_movl_reg_TN(DisasContext
*s
, int reg
, int t
)
292 gen_op_movl_reg_TN
[t
][reg
]();
294 s
->is_jmp
= DISAS_JUMP
;
298 static inline void gen_movl_reg_T0(DisasContext
*s
, int reg
)
300 gen_movl_reg_TN(s
, reg
, 0);
303 static inline void gen_movl_reg_T1(DisasContext
*s
, int reg
)
305 gen_movl_reg_TN(s
, reg
, 1);
308 static inline void gen_add_data_offset(DisasContext
*s
, unsigned int insn
)
310 int val
, rm
, shift
, shiftop
;
312 if (!(insn
& (1 << 25))) {
315 if (!(insn
& (1 << 23)))
318 gen_op_addl_T1_im(val
);
322 shift
= (insn
>> 7) & 0x1f;
323 gen_movl_T2_reg(s
, rm
);
324 shiftop
= (insn
>> 5) & 3;
326 gen_shift_T2_im
[shiftop
](shift
);
327 } else if (shiftop
!= 0) {
328 gen_shift_T2_0
[shiftop
]();
330 if (!(insn
& (1 << 23)))
337 static inline void gen_add_datah_offset(DisasContext
*s
, unsigned int insn
)
341 if (insn
& (1 << 22)) {
343 val
= (insn
& 0xf) | ((insn
>> 4) & 0xf0);
344 if (!(insn
& (1 << 23)))
347 gen_op_addl_T1_im(val
);
351 gen_movl_T2_reg(s
, rm
);
352 if (!(insn
& (1 << 23)))
359 #define VFP_OP(name) \
360 static inline void gen_vfp_##name(int dp) \
363 gen_op_vfp_##name##d(); \
365 gen_op_vfp_##name##s(); \
390 vfp_reg_offset (int dp
, int reg
)
393 return offsetof(CPUARMState
, vfp
.regs
[reg
]);
395 return offsetof(CPUARMState
, vfp
.regs
[reg
>> 1])
396 + offsetof(CPU_DoubleU
, l
.upper
);
398 return offsetof(CPUARMState
, vfp
.regs
[reg
>> 1])
399 + offsetof(CPU_DoubleU
, l
.lower
);
402 static inline void gen_mov_F0_vreg(int dp
, int reg
)
405 gen_op_vfp_getreg_F0d(vfp_reg_offset(dp
, reg
));
407 gen_op_vfp_getreg_F0s(vfp_reg_offset(dp
, reg
));
410 static inline void gen_mov_F1_vreg(int dp
, int reg
)
413 gen_op_vfp_getreg_F1d(vfp_reg_offset(dp
, reg
));
415 gen_op_vfp_getreg_F1s(vfp_reg_offset(dp
, reg
));
418 static inline void gen_mov_vreg_F0(int dp
, int reg
)
421 gen_op_vfp_setreg_F0d(vfp_reg_offset(dp
, reg
));
423 gen_op_vfp_setreg_F0s(vfp_reg_offset(dp
, reg
));
426 /* Disassemble a VFP instruction. Returns nonzero if an error occured
427 (ie. an undefined instruction). */
428 static int disas_vfp_insn(CPUState
* env
, DisasContext
*s
, uint32_t insn
)
430 uint32_t rd
, rn
, rm
, op
, i
, n
, offset
, delta_d
, delta_m
, bank_mask
;
433 dp
= ((insn
& 0xf00) == 0xb00);
434 switch ((insn
>> 24) & 0xf) {
436 if (insn
& (1 << 4)) {
437 /* single register transfer */
438 if ((insn
& 0x6f) != 0x00)
440 rd
= (insn
>> 12) & 0xf;
444 rn
= (insn
>> 16) & 0xf;
445 /* Get the existing value even for arm->vfp moves because
446 we only set half the register. */
447 gen_mov_F0_vreg(1, rn
);
449 if (insn
& (1 << 20)) {
451 if (insn
& (1 << 21))
452 gen_movl_reg_T1(s
, rd
);
454 gen_movl_reg_T0(s
, rd
);
457 if (insn
& (1 << 21))
458 gen_movl_T1_reg(s
, rd
);
460 gen_movl_T0_reg(s
, rd
);
462 gen_mov_vreg_F0(dp
, rn
);
465 rn
= ((insn
>> 15) & 0x1e) | ((insn
>> 7) & 1);
466 if (insn
& (1 << 20)) {
468 if (insn
& (1 << 21)) {
469 /* system register */
476 gen_op_vfp_movl_T0_fpscr_flags();
478 gen_op_vfp_movl_T0_fpscr();
484 gen_mov_F0_vreg(0, rn
);
488 /* This will only set the 4 flag bits */
489 gen_op_movl_psr_T0();
491 gen_movl_reg_T0(s
, rd
);
494 gen_movl_T0_reg(s
, rd
);
495 if (insn
& (1 << 21)) {
496 /* system register */
499 /* Writes are ignored. */
502 gen_op_vfp_movl_fpscr_T0();
503 /* This could change vector settings, so jump to
504 the next instuction. */
505 gen_op_movl_T0_im(s
->pc
);
506 gen_movl_reg_T0(s
, 15);
507 s
->is_jmp
= DISAS_UPDATE
;
514 gen_mov_vreg_F0(0, rn
);
519 /* data processing */
520 /* The opcode is in bits 23, 21, 20 and 6. */
521 op
= ((insn
>> 20) & 8) | ((insn
>> 19) & 6) | ((insn
>> 6) & 1);
525 rn
= ((insn
>> 15) & 0x1e) | ((insn
>> 7) & 1);
527 /* rn is register number */
530 rn
= (insn
>> 16) & 0xf;
533 if (op
== 15 && (rn
== 15 || rn
> 17)) {
534 /* Integer or single precision destination. */
535 rd
= ((insn
>> 11) & 0x1e) | ((insn
>> 22) & 1);
537 if (insn
& (1 << 22))
539 rd
= (insn
>> 12) & 0xf;
542 if (op
== 15 && (rn
== 16 || rn
== 17)) {
543 /* Integer source. */
544 rm
= ((insn
<< 1) & 0x1e) | ((insn
>> 5) & 1);
551 rn
= ((insn
>> 15) & 0x1e) | ((insn
>> 7) & 1);
552 if (op
== 15 && rn
== 15) {
553 /* Double precision destination. */
554 if (insn
& (1 << 22))
556 rd
= (insn
>> 12) & 0xf;
558 rd
= ((insn
>> 11) & 0x1e) | ((insn
>> 22) & 1);
559 rm
= ((insn
<< 1) & 0x1e) | ((insn
>> 5) & 1);
562 veclen
= env
->vfp
.vec_len
;
563 if (op
== 15 && rn
> 3)
566 /* Shut up compiler warnings. */
577 /* Figure out what type of vector operation this is. */
578 if ((rd
& bank_mask
) == 0) {
583 delta_d
= (env
->vfp
.vec_stride
>> 1) + 1;
585 delta_d
= env
->vfp
.vec_stride
+ 1;
587 if ((rm
& bank_mask
) == 0) {
588 /* mixed scalar/vector */
597 /* Load the initial operands. */
603 gen_mov_F0_vreg(0, rm
);
608 gen_mov_F0_vreg(dp
, rd
);
609 gen_mov_F1_vreg(dp
, rm
);
613 /* Compare with zero */
614 gen_mov_F0_vreg(dp
, rd
);
618 /* One source operand. */
619 gen_mov_F0_vreg(dp
, rm
);
622 /* Two source operands. */
623 gen_mov_F0_vreg(dp
, rn
);
624 gen_mov_F1_vreg(dp
, rm
);
628 /* Perform the calculation. */
630 case 0: /* mac: fd + (fn * fm) */
632 gen_mov_F1_vreg(dp
, rd
);
635 case 1: /* nmac: fd - (fn * fm) */
638 gen_mov_F1_vreg(dp
, rd
);
641 case 2: /* msc: -fd + (fn * fm) */
643 gen_mov_F1_vreg(dp
, rd
);
646 case 3: /* nmsc: -fd - (fn * fm) */
648 gen_mov_F1_vreg(dp
, rd
);
652 case 4: /* mul: fn * fm */
655 case 5: /* nmul: -(fn * fm) */
659 case 6: /* add: fn + fm */
662 case 7: /* sub: fn - fm */
665 case 8: /* div: fn / fm */
668 case 15: /* extension space */
695 case 15: /* single<->double conversion */
710 case 25: /* ftouiz */
716 case 27: /* ftosiz */
719 default: /* undefined */
720 printf ("rn:%d\n", rn
);
724 default: /* undefined */
725 printf ("op:%d\n", op
);
729 /* Write back the result. */
730 if (op
== 15 && (rn
>= 8 && rn
<= 11))
731 ; /* Comparison, do nothing. */
732 else if (op
== 15 && rn
> 17)
733 /* Integer result. */
734 gen_mov_vreg_F0(0, rd
);
735 else if (op
== 15 && rn
== 15)
737 gen_mov_vreg_F0(!dp
, rd
);
739 gen_mov_vreg_F0(dp
, rd
);
741 /* break out of the loop if we have finished */
745 if (op
== 15 && delta_m
== 0) {
746 /* single source one-many */
748 rd
= ((rd
+ delta_d
) & (bank_mask
- 1))
750 gen_mov_vreg_F0(dp
, rd
);
754 /* Setup the next operands. */
756 rd
= ((rd
+ delta_d
) & (bank_mask
- 1))
760 /* One source operand. */
761 rm
= ((rm
+ delta_m
) & (bank_mask
- 1))
763 gen_mov_F0_vreg(dp
, rm
);
765 /* Two source operands. */
766 rn
= ((rn
+ delta_d
) & (bank_mask
- 1))
768 gen_mov_F0_vreg(dp
, rn
);
770 rm
= ((rm
+ delta_m
) & (bank_mask
- 1))
772 gen_mov_F1_vreg(dp
, rm
);
780 if (dp
&& (insn
& (1 << 22))) {
781 /* two-register transfer */
782 rn
= (insn
>> 16) & 0xf;
783 rd
= (insn
>> 12) & 0xf;
789 rm
= ((insn
<< 1) & 0x1e) | ((insn
>> 5) & 1);
791 if (insn
& (1 << 20)) {
794 gen_mov_F0_vreg(1, rm
);
796 gen_movl_reg_T0(s
, rd
);
797 gen_movl_reg_T1(s
, rn
);
799 gen_mov_F0_vreg(0, rm
);
801 gen_movl_reg_T0(s
, rn
);
802 gen_mov_F0_vreg(0, rm
+ 1);
804 gen_movl_reg_T0(s
, rd
);
809 gen_movl_T0_reg(s
, rd
);
810 gen_movl_T1_reg(s
, rn
);
812 gen_mov_vreg_F0(1, rm
);
814 gen_movl_T0_reg(s
, rn
);
816 gen_mov_vreg_F0(0, rm
);
817 gen_movl_T0_reg(s
, rd
);
819 gen_mov_vreg_F0(0, rm
+ 1);
824 rn
= (insn
>> 16) & 0xf;
826 rd
= (insn
>> 12) & 0xf;
828 rd
= ((insn
>> 11) & 0x1e) | ((insn
>> 22) & 1);
829 gen_movl_T1_reg(s
, rn
);
830 if ((insn
& 0x01200000) == 0x01000000) {
831 /* Single load/store */
832 offset
= (insn
& 0xff) << 2;
833 if ((insn
& (1 << 23)) == 0)
835 gen_op_addl_T1_im(offset
);
836 if (insn
& (1 << 20)) {
838 gen_mov_vreg_F0(dp
, rd
);
840 gen_mov_F0_vreg(dp
, rd
);
844 /* load/store multiple */
846 n
= (insn
>> 1) & 0x7f;
850 if (insn
& (1 << 24)) /* pre-decrement */
851 gen_op_addl_T1_im(-((insn
& 0xff) << 2));
857 for (i
= 0; i
< n
; i
++) {
858 if (insn
& (1 << 20)) {
861 gen_mov_vreg_F0(dp
, rd
+ i
);
864 gen_mov_F0_vreg(dp
, rd
+ i
);
867 gen_op_addl_T1_im(offset
);
869 if (insn
& (1 << 21)) {
871 if (insn
& (1 << 24))
872 offset
= -offset
* n
;
873 else if (dp
&& (insn
& 1))
879 gen_op_addl_T1_im(offset
);
880 gen_movl_reg_T1(s
, rn
);
886 /* Should never happen. */
892 static inline void gen_jmp (DisasContext
*s
, uint32_t dest
)
894 if (__builtin_expect(s
->singlestep_enabled
, 0)) {
895 /* An indirect jump so that we still trigger the debug exception. */
896 gen_op_movl_T0_im(dest
);
899 gen_op_jmp((long)s
->tb
, dest
);
900 s
->is_jmp
= DISAS_TB_JUMP
;
904 static void disas_arm_insn(CPUState
* env
, DisasContext
*s
)
906 unsigned int cond
, insn
, val
, op1
, i
, shift
, rm
, rs
, rn
, rd
, sh
;
913 /* Unconditional instructions. */
914 if ((insn
& 0x0d70f000) == 0x0550f000)
916 else if ((insn
& 0x0e000000) == 0x0a000000) {
917 /* branch link and change to thumb (blx <offset>) */
920 val
= (uint32_t)s
->pc
;
921 gen_op_movl_T0_im(val
);
922 gen_movl_reg_T0(s
, 14);
923 /* Sign-extend the 24-bit offset */
924 offset
= (((int32_t)insn
) << 8) >> 8;
925 /* offset * 4 + bit24 * 2 + (thumb bit) */
926 val
+= (offset
<< 2) | ((insn
>> 23) & 2) | 1;
927 /* pipeline offset */
929 gen_op_movl_T0_im(val
);
932 } else if ((insn
& 0x0fe00000) == 0x0c400000) {
933 /* Coprocessor double register transfer. */
934 } else if ((insn
& 0x0f000010) == 0x0e000010) {
935 /* Additional coprocessor register transfer. */
940 /* if not always execute, we generate a conditional jump to
942 gen_test_cc
[cond
^ 1]((long)s
->tb
, (long)s
->pc
);
943 s
->is_jmp
= DISAS_JUMP_NEXT
;
945 if ((insn
& 0x0f900000) == 0x03000000) {
946 if ((insn
& 0x0ff0f000) != 0x0360f000)
948 /* CPSR = immediate */
950 shift
= ((insn
>> 8) & 0xf) * 2;
952 val
= (val
>> shift
) | (val
<< (32 - shift
));
953 gen_op_movl_T0_im(val
);
954 if (insn
& (1 << 19))
955 gen_op_movl_psr_T0();
956 } else if ((insn
& 0x0f900000) == 0x01000000
957 && (insn
& 0x00000090) != 0x00000090) {
958 /* miscellaneous instructions */
959 op1
= (insn
>> 21) & 3;
960 sh
= (insn
>> 4) & 0xf;
963 case 0x0: /* move program status register */
965 /* SPSR not accessible in user mode */
970 gen_movl_T0_reg(s
, rm
);
971 if (insn
& (1 << 19))
972 gen_op_movl_psr_T0();
975 rd
= (insn
>> 12) & 0xf;
976 gen_op_movl_T0_psr();
977 gen_movl_reg_T0(s
, rd
);
982 /* branch/exchange thumb (bx). */
983 gen_movl_T0_reg(s
, rm
);
985 } else if (op1
== 3) {
987 rd
= (insn
>> 12) & 0xf;
988 gen_movl_T0_reg(s
, rm
);
990 gen_movl_reg_T0(s
, rd
);
999 /* branch link/exchange thumb (blx) */
1000 val
= (uint32_t)s
->pc
;
1001 gen_op_movl_T0_im(val
);
1002 gen_movl_reg_T0(s
, 14);
1003 gen_movl_T0_reg(s
, rm
);
1006 case 0x5: /* saturating add/subtract */
1007 rd
= (insn
>> 12) & 0xf;
1008 rn
= (insn
>> 16) & 0xf;
1009 gen_movl_T0_reg(s
, rn
);
1011 gen_movl_T1_reg(s
, rn
);
1013 gen_op_subl_T0_T1_saturate();
1015 gen_op_addl_T0_T1_saturate();
1017 gen_movl_T1_reg(s
, rm
);
1019 gen_op_subl_T0_T1_saturate();
1021 gen_op_addl_T0_T1_saturate();
1022 gen_movl_reg_T0(s
, rn
);
1024 case 0x8: /* signed multiply */
1028 rs
= (insn
>> 8) & 0xf;
1029 rn
= (insn
>> 12) & 0xf;
1030 rd
= (insn
>> 16) & 0xf;
1032 /* (32 * 16) >> 16 */
1033 gen_movl_T0_reg(s
, rm
);
1034 gen_movl_T1_reg(s
, rs
);
1036 gen_op_sarl_T1_im(16);
1039 gen_op_imulw_T0_T1();
1040 if ((sh
& 2) == 0) {
1041 gen_movl_T1_reg(s
, rn
);
1042 gen_op_addl_T0_T1_setq();
1044 gen_movl_reg_T0(s
, rd
);
1047 gen_movl_T0_reg(s
, rm
);
1049 gen_op_sarl_T0_im(16);
1052 gen_movl_T1_reg(s
, rs
);
1054 gen_op_sarl_T1_im(16);
1058 gen_op_imull_T0_T1();
1059 gen_op_addq_T0_T1(rn
, rd
);
1060 gen_movl_reg_T0(s
, rn
);
1061 gen_movl_reg_T1(s
, rd
);
1065 gen_movl_T1_reg(s
, rn
);
1066 gen_op_addl_T0_T1_setq();
1068 gen_movl_reg_T0(s
, rd
);
1075 } else if (((insn
& 0x0e000000) == 0 &&
1076 (insn
& 0x00000090) != 0x90) ||
1077 ((insn
& 0x0e000000) == (1 << 25))) {
1078 int set_cc
, logic_cc
, shiftop
;
1080 op1
= (insn
>> 21) & 0xf;
1081 set_cc
= (insn
>> 20) & 1;
1082 logic_cc
= table_logic_cc
[op1
] & set_cc
;
1084 /* data processing instruction */
1085 if (insn
& (1 << 25)) {
1086 /* immediate operand */
1088 shift
= ((insn
>> 8) & 0xf) * 2;
1090 val
= (val
>> shift
) | (val
<< (32 - shift
));
1091 gen_op_movl_T1_im(val
);
1092 if (logic_cc
&& shift
)
1097 gen_movl_T1_reg(s
, rm
);
1098 shiftop
= (insn
>> 5) & 3;
1099 if (!(insn
& (1 << 4))) {
1100 shift
= (insn
>> 7) & 0x1f;
1103 gen_shift_T1_im_cc
[shiftop
](shift
);
1105 gen_shift_T1_im
[shiftop
](shift
);
1107 } else if (shiftop
!= 0) {
1109 gen_shift_T1_0_cc
[shiftop
]();
1111 gen_shift_T1_0
[shiftop
]();
1115 rs
= (insn
>> 8) & 0xf;
1116 gen_movl_T0_reg(s
, rs
);
1118 gen_shift_T1_T0_cc
[shiftop
]();
1120 gen_shift_T1_T0
[shiftop
]();
1124 if (op1
!= 0x0f && op1
!= 0x0d) {
1125 rn
= (insn
>> 16) & 0xf;
1126 gen_movl_T0_reg(s
, rn
);
1128 rd
= (insn
>> 12) & 0xf;
1131 gen_op_andl_T0_T1();
1132 gen_movl_reg_T0(s
, rd
);
1134 gen_op_logic_T0_cc();
1137 gen_op_xorl_T0_T1();
1138 gen_movl_reg_T0(s
, rd
);
1140 gen_op_logic_T0_cc();
1144 gen_op_subl_T0_T1_cc();
1146 gen_op_subl_T0_T1();
1147 gen_movl_reg_T0(s
, rd
);
1151 gen_op_rsbl_T0_T1_cc();
1153 gen_op_rsbl_T0_T1();
1154 gen_movl_reg_T0(s
, rd
);
1158 gen_op_addl_T0_T1_cc();
1160 gen_op_addl_T0_T1();
1161 gen_movl_reg_T0(s
, rd
);
1165 gen_op_adcl_T0_T1_cc();
1167 gen_op_adcl_T0_T1();
1168 gen_movl_reg_T0(s
, rd
);
1172 gen_op_sbcl_T0_T1_cc();
1174 gen_op_sbcl_T0_T1();
1175 gen_movl_reg_T0(s
, rd
);
1179 gen_op_rscl_T0_T1_cc();
1181 gen_op_rscl_T0_T1();
1182 gen_movl_reg_T0(s
, rd
);
1186 gen_op_andl_T0_T1();
1187 gen_op_logic_T0_cc();
1192 gen_op_xorl_T0_T1();
1193 gen_op_logic_T0_cc();
1198 gen_op_subl_T0_T1_cc();
1203 gen_op_addl_T0_T1_cc();
1208 gen_movl_reg_T0(s
, rd
);
1210 gen_op_logic_T0_cc();
1213 gen_movl_reg_T1(s
, rd
);
1215 gen_op_logic_T1_cc();
1218 gen_op_bicl_T0_T1();
1219 gen_movl_reg_T0(s
, rd
);
1221 gen_op_logic_T0_cc();
1226 gen_movl_reg_T1(s
, rd
);
1228 gen_op_logic_T1_cc();
1232 /* other instructions */
1233 op1
= (insn
>> 24) & 0xf;
1237 /* multiplies, extra load/stores */
1238 sh
= (insn
>> 5) & 3;
1241 rd
= (insn
>> 16) & 0xf;
1242 rn
= (insn
>> 12) & 0xf;
1243 rs
= (insn
>> 8) & 0xf;
1245 if (((insn
>> 22) & 3) == 0) {
1247 gen_movl_T0_reg(s
, rs
);
1248 gen_movl_T1_reg(s
, rm
);
1250 if (insn
& (1 << 21)) {
1251 gen_movl_T1_reg(s
, rn
);
1252 gen_op_addl_T0_T1();
1254 if (insn
& (1 << 20))
1255 gen_op_logic_T0_cc();
1256 gen_movl_reg_T0(s
, rd
);
1259 gen_movl_T0_reg(s
, rs
);
1260 gen_movl_T1_reg(s
, rm
);
1261 if (insn
& (1 << 22))
1262 gen_op_imull_T0_T1();
1264 gen_op_mull_T0_T1();
1265 if (insn
& (1 << 21)) /* mult accumulate */
1266 gen_op_addq_T0_T1(rn
, rd
);
1267 if (!(insn
& (1 << 23))) { /* double accumulate */
1268 gen_op_addq_lo_T0_T1(rn
);
1269 gen_op_addq_lo_T0_T1(rd
);
1271 if (insn
& (1 << 20))
1273 gen_movl_reg_T0(s
, rn
);
1274 gen_movl_reg_T1(s
, rd
);
1277 rn
= (insn
>> 16) & 0xf;
1278 rd
= (insn
>> 12) & 0xf;
1279 if (insn
& (1 << 23)) {
1280 /* load/store exclusive */
1283 /* SWP instruction */
1286 gen_movl_T0_reg(s
, rm
);
1287 gen_movl_T1_reg(s
, rn
);
1288 if (insn
& (1 << 22)) {
1289 gen_op_swpb_T0_T1();
1291 gen_op_swpl_T0_T1();
1293 gen_movl_reg_T0(s
, rd
);
1297 /* Misc load/store */
1298 rn
= (insn
>> 16) & 0xf;
1299 rd
= (insn
>> 12) & 0xf;
1300 gen_movl_T1_reg(s
, rn
);
1301 if (insn
& (1 << 24))
1302 gen_add_datah_offset(s
, insn
);
1303 if (insn
& (1 << 20)) {
1307 gen_op_lduw_T0_T1();
1310 gen_op_ldsb_T0_T1();
1314 gen_op_ldsw_T0_T1();
1317 gen_movl_reg_T0(s
, rd
);
1318 } else if (sh
& 2) {
1322 gen_movl_T0_reg(s
, rd
);
1324 gen_op_addl_T1_im(4);
1325 gen_movl_T0_reg(s
, rd
+ 1);
1327 if ((insn
& (1 << 24)) || (insn
& (1 << 20)))
1328 gen_op_addl_T1_im(-4);
1332 gen_movl_reg_T0(s
, rd
);
1333 gen_op_addl_T1_im(4);
1335 gen_movl_reg_T0(s
, rd
+ 1);
1336 if ((insn
& (1 << 24)) || (insn
& (1 << 20)))
1337 gen_op_addl_T1_im(-4);
1341 gen_movl_T0_reg(s
, rd
);
1344 if (!(insn
& (1 << 24))) {
1345 gen_add_datah_offset(s
, insn
);
1346 gen_movl_reg_T1(s
, rn
);
1347 } else if (insn
& (1 << 21)) {
1348 gen_movl_reg_T1(s
, rn
);
1356 /* load/store byte/word */
1357 rn
= (insn
>> 16) & 0xf;
1358 rd
= (insn
>> 12) & 0xf;
1359 gen_movl_T1_reg(s
, rn
);
1360 if (insn
& (1 << 24))
1361 gen_add_data_offset(s
, insn
);
1362 if (insn
& (1 << 20)) {
1364 if (insn
& (1 << 22))
1365 gen_op_ldub_T0_T1();
1371 gen_movl_reg_T0(s
, rd
);
1374 gen_movl_T0_reg(s
, rd
);
1375 if (insn
& (1 << 22))
1380 if (!(insn
& (1 << 24))) {
1381 gen_add_data_offset(s
, insn
);
1382 gen_movl_reg_T1(s
, rn
);
1383 } else if (insn
& (1 << 21))
1384 gen_movl_reg_T1(s
, rn
); {
1391 /* load/store multiple words */
1392 /* XXX: store correct base if write back */
1393 if (insn
& (1 << 22))
1394 goto illegal_op
; /* only usable in supervisor mode */
1395 rn
= (insn
>> 16) & 0xf;
1396 gen_movl_T1_reg(s
, rn
);
1398 /* compute total size */
1401 if (insn
& (1 << i
))
1404 /* XXX: test invalid n == 0 case ? */
1405 if (insn
& (1 << 23)) {
1406 if (insn
& (1 << 24)) {
1408 gen_op_addl_T1_im(4);
1410 /* post increment */
1413 if (insn
& (1 << 24)) {
1415 gen_op_addl_T1_im(-(n
* 4));
1417 /* post decrement */
1419 gen_op_addl_T1_im(-((n
- 1) * 4));
1424 if (insn
& (1 << i
)) {
1425 if (insn
& (1 << 20)) {
1431 gen_movl_reg_T0(s
, i
);
1435 /* special case: r15 = PC + 12 */
1436 val
= (long)s
->pc
+ 8;
1437 gen_op_movl_TN_im
[0](val
);
1439 gen_movl_T0_reg(s
, i
);
1444 /* no need to add after the last transfer */
1446 gen_op_addl_T1_im(4);
1449 if (insn
& (1 << 21)) {
1451 if (insn
& (1 << 23)) {
1452 if (insn
& (1 << 24)) {
1455 /* post increment */
1456 gen_op_addl_T1_im(4);
1459 if (insn
& (1 << 24)) {
1462 gen_op_addl_T1_im(-((n
- 1) * 4));
1464 /* post decrement */
1465 gen_op_addl_T1_im(-(n
* 4));
1468 gen_movl_reg_T1(s
, rn
);
1477 /* branch (and link) */
1478 val
= (int32_t)s
->pc
;
1479 if (insn
& (1 << 24)) {
1480 gen_op_movl_T0_im(val
);
1481 gen_op_movl_reg_TN
[0][14]();
1483 offset
= (((int32_t)insn
<< 8) >> 8);
1484 val
+= (offset
<< 2) + 4;
1492 op1
= (insn
>> 8) & 0xf;
1496 if (disas_vfp_insn (env
, s
, insn
))
1500 /* unknown coprocessor. */
1506 gen_op_movl_T0_im((long)s
->pc
);
1507 gen_op_movl_reg_TN
[0][15]();
1509 s
->is_jmp
= DISAS_JUMP
;
1513 gen_op_movl_T0_im((long)s
->pc
- 4);
1514 gen_op_movl_reg_TN
[0][15]();
1515 gen_op_undef_insn();
1516 s
->is_jmp
= DISAS_JUMP
;
1522 static void disas_thumb_insn(DisasContext
*s
)
1524 uint32_t val
, insn
, op
, rm
, rn
, rd
, shift
, cond
;
1531 switch (insn
>> 12) {
1534 op
= (insn
>> 11) & 3;
1537 rn
= (insn
>> 3) & 7;
1538 gen_movl_T0_reg(s
, rn
);
1539 if (insn
& (1 << 10)) {
1541 gen_op_movl_T1_im((insn
>> 6) & 7);
1544 rm
= (insn
>> 6) & 7;
1545 gen_movl_T1_reg(s
, rm
);
1547 if (insn
& (1 << 9))
1548 gen_op_addl_T0_T1_cc();
1550 gen_op_addl_T0_T1_cc();
1551 gen_movl_reg_T0(s
, rd
);
1553 /* shift immediate */
1554 rm
= (insn
>> 3) & 7;
1555 shift
= (insn
>> 6) & 0x1f;
1556 gen_movl_T0_reg(s
, rm
);
1557 gen_shift_T0_im_thumb
[op
](shift
);
1558 gen_movl_reg_T0(s
, rd
);
1562 /* arithmetic large immediate */
1563 op
= (insn
>> 11) & 3;
1564 rd
= (insn
>> 8) & 0x7;
1566 gen_op_movl_T0_im(insn
& 0xff);
1568 gen_movl_T0_reg(s
, rd
);
1569 gen_op_movl_T1_im(insn
& 0xff);
1573 gen_op_logic_T0_cc();
1576 gen_op_subl_T0_T1_cc();
1579 gen_op_addl_T0_T1_cc();
1582 gen_op_subl_T0_T1_cc();
1586 gen_movl_reg_T0(s
, rd
);
1589 if (insn
& (1 << 11)) {
1590 rd
= (insn
>> 8) & 7;
1591 /* load pc-relative */
1592 val
= (insn
& 0xff) * 4;
1593 gen_op_movl_T1_im(val
);
1594 gen_movl_T2_reg(s
, 15);
1595 gen_op_addl_T1_T2();
1597 gen_movl_reg_T0(s
, rd
);
1600 if (insn
& (1 << 10)) {
1601 /* data processing extended or blx */
1602 rd
= (insn
& 7) | ((insn
>> 4) & 8);
1603 rm
= (insn
>> 3) & 0xf;
1604 op
= (insn
>> 8) & 3;
1607 gen_movl_T0_reg(s
, rd
);
1608 gen_movl_T1_reg(s
, rm
);
1609 gen_op_addl_T0_T1();
1610 gen_movl_reg_T0(s
, rd
);
1613 gen_movl_T0_reg(s
, rd
);
1614 gen_movl_T1_reg(s
, rm
);
1615 gen_op_subl_T0_T1_cc();
1617 case 2: /* mov/cpy */
1618 gen_movl_T0_reg(s
, rm
);
1619 gen_movl_reg_T0(s
, rd
);
1621 case 3:/* branch [and link] exchange thumb register */
1622 if (insn
& (1 << 7)) {
1623 val
= (uint32_t)s
->pc
| 1;
1624 gen_op_movl_T1_im(val
);
1625 gen_movl_reg_T1(s
, 14);
1627 gen_movl_T0_reg(s
, rm
);
1634 /* data processing register */
1636 rm
= (insn
>> 3) & 7;
1637 op
= (insn
>> 6) & 0xf;
1638 if (op
== 2 || op
== 3 || op
== 4 || op
== 7) {
1639 /* the shift/rotate ops want the operands backwards */
1648 if (op
== 9) /* neg */
1649 gen_op_movl_T0_im(0);
1650 else if (op
!= 0xf) /* mvn doesn't read its first operand */
1651 gen_movl_T0_reg(s
, rd
);
1653 gen_movl_T1_reg(s
, rm
);
1654 switch (insn
>> 6) {
1656 gen_op_andl_T0_T1();
1657 gen_op_logic_T0_cc();
1660 gen_op_xorl_T0_T1();
1661 gen_op_logic_T0_cc();
1664 gen_op_shll_T1_T0_cc();
1667 gen_op_shrl_T1_T0_cc();
1670 gen_op_sarl_T1_T0_cc();
1673 gen_op_adcl_T0_T1_cc();
1676 gen_op_sbcl_T0_T1_cc();
1679 gen_op_rorl_T1_T0_cc();
1682 gen_op_andl_T0_T1();
1683 gen_op_logic_T0_cc();
1686 gen_op_rsbl_T0_T1_cc();
1689 gen_op_subl_T0_T1_cc();
1693 gen_op_addl_T0_T1_cc();
1698 gen_op_logic_T0_cc();
1701 gen_op_mull_T0_T1();
1702 gen_op_logic_T0_cc();
1705 gen_op_bicl_T0_T1();
1706 gen_op_logic_T0_cc();
1710 gen_op_logic_T1_cc();
1716 gen_movl_reg_T1(s
, rd
);
1718 gen_movl_reg_T0(s
, rd
);
1723 /* load/store register offset. */
1725 rn
= (insn
>> 3) & 7;
1726 rm
= (insn
>> 6) & 7;
1727 op
= (insn
>> 9) & 7;
1728 gen_movl_T1_reg(s
, rn
);
1729 gen_movl_T2_reg(s
, rm
);
1730 gen_op_addl_T1_T2();
1732 if (op
< 3) /* store */
1733 gen_movl_T0_reg(s
, rd
);
1746 gen_op_ldsb_T0_T1();
1752 gen_op_ldsw_T0_T1();
1755 gen_op_ldub_T0_T1();
1758 gen_op_ldsw_T0_T1();
1761 if (op
>= 3) /* load */
1762 gen_movl_reg_T0(s
, rd
);
1766 /* load/store word immediate offset */
1768 rn
= (insn
>> 3) & 7;
1769 gen_movl_T1_reg(s
, rn
);
1770 val
= (insn
>> 4) & 0x7c;
1771 gen_op_movl_T2_im(val
);
1772 gen_op_addl_T1_T2();
1774 if (insn
& (1 << 11)) {
1777 gen_movl_reg_T0(s
, rd
);
1780 gen_movl_T0_reg(s
, rd
);
1786 /* load/store byte immediate offset */
1788 rn
= (insn
>> 3) & 7;
1789 gen_movl_T1_reg(s
, rn
);
1790 val
= (insn
>> 6) & 0x1f;
1791 gen_op_movl_T2_im(val
);
1792 gen_op_addl_T1_T2();
1794 if (insn
& (1 << 11)) {
1796 gen_op_ldub_T0_T1();
1797 gen_movl_reg_T0(s
, rd
);
1800 gen_movl_T0_reg(s
, rd
);
1806 /* load/store halfword immediate offset */
1808 rn
= (insn
>> 3) & 7;
1809 gen_movl_T1_reg(s
, rn
);
1810 val
= (insn
>> 5) & 0x3e;
1811 gen_op_movl_T2_im(val
);
1812 gen_op_addl_T1_T2();
1814 if (insn
& (1 << 11)) {
1816 gen_op_lduw_T0_T1();
1817 gen_movl_reg_T0(s
, rd
);
1820 gen_movl_T0_reg(s
, rd
);
1826 /* load/store from stack */
1827 rd
= (insn
>> 8) & 7;
1828 gen_movl_T1_reg(s
, 13);
1829 val
= (insn
& 0xff) * 4;
1830 gen_op_movl_T2_im(val
);
1831 gen_op_addl_T1_T2();
1833 if (insn
& (1 << 11)) {
1836 gen_movl_reg_T0(s
, rd
);
1839 gen_movl_T0_reg(s
, rd
);
1845 /* add to high reg */
1846 rd
= (insn
>> 8) & 7;
1847 if (insn
& (1 << 11))
1851 gen_movl_T0_reg(s
, rm
);
1852 val
= (insn
& 0xff) * 4;
1853 gen_op_movl_T1_im(val
);
1854 gen_op_addl_T0_T1();
1855 gen_movl_reg_T0(s
, rd
);
1860 op
= (insn
>> 8) & 0xf;
1863 /* adjust stack pointer */
1864 gen_movl_T1_reg(s
, 13);
1865 val
= (insn
& 0x7f) * 4;
1866 if (insn
& (1 << 7))
1867 val
= -(int32_t)val
;
1868 gen_op_movl_T2_im(val
);
1869 gen_op_addl_T1_T2();
1870 gen_movl_reg_T1(s
, 13);
1873 case 4: case 5: case 0xc: case 0xd:
1875 gen_movl_T1_reg(s
, 13);
1876 if (insn
& (1 << 11))
1880 gen_op_movl_T2_im(val
);
1881 for (i
= 0; i
< 8; i
++) {
1882 if (insn
& (1 << i
)) {
1883 if (insn
& (1 << 11)) {
1886 gen_movl_reg_T0(s
, i
);
1889 gen_movl_T0_reg(s
, i
);
1892 /* move to the next address */
1893 gen_op_addl_T1_T2();
1896 if (insn
& (1 << 8)) {
1897 if (insn
& (1 << 11)) {
1900 /* don't set the pc until the rest of the instruction
1904 gen_movl_T0_reg(s
, 14);
1907 gen_op_addl_T1_T2();
1910 /* write back the new stack pointer */
1911 gen_movl_reg_T1(s
, 13);
1912 /* set the new PC value */
1913 if ((insn
& 0x0900) == 0x0900)
1923 /* load/store multiple */
1924 rn
= (insn
>> 8) & 0x7;
1925 gen_movl_T1_reg(s
, rn
);
1926 gen_op_movl_T2_im(4);
1928 for (i
= 0; i
< 8; i
++) {
1929 if (insn
& (1 << i
)) {
1930 /* advance to the next address */
1932 gen_op_addl_T1_T2();
1935 if (insn
& (1 << 11)) {
1938 gen_movl_reg_T0(s
, i
);
1941 gen_movl_T0_reg(s
, i
);
1949 /* conditional branch or swi */
1950 cond
= (insn
>> 8) & 0xf;
1956 gen_op_movl_T0_im((long)s
->pc
| 1);
1957 /* Don't set r15. */
1958 gen_op_movl_reg_TN
[0][15]();
1960 s
->is_jmp
= DISAS_JUMP
;
1963 /* generate a conditional jump to next instruction */
1964 gen_test_cc
[cond
^ 1]((long)s
->tb
, (long)s
->pc
);
1965 s
->is_jmp
= DISAS_JUMP_NEXT
;
1966 gen_movl_T1_reg(s
, 15);
1968 /* jump to the offset */
1969 val
= (uint32_t)s
->pc
;
1970 offset
= ((int32_t)insn
<< 24) >> 24;
1971 val
+= (offset
<< 1) + 2;
1976 /* unconditional branch */
1977 if (insn
& (1 << 11))
1978 goto undef
; /* Second half of a blx */
1979 val
= (uint32_t)s
->pc
;
1980 offset
= ((int32_t)insn
<< 21) >> 21;
1981 val
+= (offset
<< 1) + 2;
1986 /* branch and link [and switch to arm] */
1987 offset
= ((int32_t)insn
<< 21) >> 10;
1989 offset
|= insn
& 0x7ff;
1991 val
= (uint32_t)s
->pc
+ 2;
1992 gen_op_movl_T1_im(val
| 1);
1993 gen_movl_reg_T1(s
, 14);
1996 if (insn
& (1 << 11)) {
2001 gen_op_movl_T0_im(val
);
2007 gen_op_movl_T0_im((long)s
->pc
- 4);
2008 gen_op_movl_reg_TN
[0][15]();
2009 gen_op_undef_insn();
2010 s
->is_jmp
= DISAS_JUMP
;
2013 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
2014 basic block 'tb'. If search_pc is TRUE, also generate PC
2015 information for each intermediate instruction. */
2016 static inline int gen_intermediate_code_internal(CPUState
*env
,
2017 TranslationBlock
*tb
,
2020 DisasContext dc1
, *dc
= &dc1
;
2021 uint16_t *gen_opc_end
;
2023 target_ulong pc_start
;
2025 /* generate intermediate code */
2030 gen_opc_ptr
= gen_opc_buf
;
2031 gen_opc_end
= gen_opc_buf
+ OPC_MAX_SIZE
;
2032 gen_opparam_ptr
= gen_opparam_buf
;
2034 dc
->is_jmp
= DISAS_NEXT
;
2036 dc
->singlestep_enabled
= env
->singlestep_enabled
;
2039 if (env
->nb_breakpoints
> 0) {
2040 for(j
= 0; j
< env
->nb_breakpoints
; j
++) {
2041 if (env
->breakpoints
[j
] == dc
->pc
) {
2042 gen_op_movl_T0_im((long)dc
->pc
);
2043 gen_op_movl_reg_TN
[0][15]();
2045 dc
->is_jmp
= DISAS_JUMP
;
2051 j
= gen_opc_ptr
- gen_opc_buf
;
2055 gen_opc_instr_start
[lj
++] = 0;
2057 gen_opc_pc
[lj
] = dc
->pc
;
2058 gen_opc_instr_start
[lj
] = 1;
2061 disas_thumb_insn(dc
);
2063 disas_arm_insn(env
, dc
);
2064 } while (!dc
->is_jmp
&& gen_opc_ptr
< gen_opc_end
&&
2065 !env
->singlestep_enabled
&&
2066 (dc
->pc
- pc_start
) < (TARGET_PAGE_SIZE
- 32));
2067 if (__builtin_expect(env
->singlestep_enabled
, 0)) {
2068 /* Make sure the pc is updated, and raise a debug exception. */
2069 if (dc
->is_jmp
== DISAS_NEXT
|| dc
->is_jmp
== DISAS_JUMP_NEXT
) {
2070 gen_op_movl_T0_im((long)dc
->pc
);
2071 gen_op_movl_reg_TN
[0][15]();
2075 switch(dc
->is_jmp
) {
2076 case DISAS_JUMP_NEXT
:
2078 gen_op_jmp((long)dc
->tb
, (long)dc
->pc
);
2083 /* indicate that the hash table must be used to find the next TB */
2088 /* nothing more to generate */
2092 *gen_opc_ptr
= INDEX_op_end
;
2095 if (loglevel
& CPU_LOG_TB_IN_ASM
) {
2096 fprintf(logfile
, "----------------\n");
2097 fprintf(logfile
, "IN: %s\n", lookup_symbol(pc_start
));
2098 target_disas(logfile
, pc_start
, dc
->pc
- pc_start
, 0);
2099 fprintf(logfile
, "\n");
2100 if (loglevel
& (CPU_LOG_TB_OP
)) {
2101 fprintf(logfile
, "OP:\n");
2102 dump_ops(gen_opc_buf
, gen_opparam_buf
);
2103 fprintf(logfile
, "\n");
2108 tb
->size
= dc
->pc
- pc_start
;
2112 int gen_intermediate_code(CPUState
*env
, TranslationBlock
*tb
)
2114 return gen_intermediate_code_internal(env
, tb
, 0);
2117 int gen_intermediate_code_pc(CPUState
*env
, TranslationBlock
*tb
)
2119 return gen_intermediate_code_internal(env
, tb
, 1);
2122 CPUARMState
*cpu_arm_init(void)
2128 env
= malloc(sizeof(CPUARMState
));
2131 memset(env
, 0, sizeof(CPUARMState
));
2132 cpu_single_env
= env
;
2136 void cpu_arm_close(CPUARMState
*env
)
2141 void cpu_dump_state(CPUState
*env
, FILE *f
,
2142 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...),
2153 cpu_fprintf(f
, "R%02d=%08x", i
, env
->regs
[i
]);
2155 cpu_fprintf(f
, "\n");
2157 cpu_fprintf(f
, " ");
2159 cpu_fprintf(f
, "PSR=%08x %c%c%c%c\n",
2161 env
->cpsr
& (1 << 31) ? 'N' : '-',
2162 env
->cpsr
& (1 << 30) ? 'Z' : '-',
2163 env
->cpsr
& (1 << 29) ? 'C' : '-',
2164 env
->cpsr
& (1 << 28) ? 'V' : '-');
2166 for (i
= 0; i
< 16; i
++) {
2167 d
.d
= env
->vfp
.regs
[i
];
2170 cpu_fprintf(f
, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n",
2171 i
* 2, (int)s0
.i
, s0
.s
,
2172 i
* 2 + 1, (int)s0
.i
, s0
.s
,
2173 i
, (int)(uint32_t)d
.l
.upper
, (int)(uint32_t)d
.l
.lower
,
2176 cpu_fprintf(f
, "FPSCR: %08x\n", (int)env
->vfp
.fpscr
);
2179 target_ulong
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)
2184 #if defined(CONFIG_USER_ONLY)
2186 int cpu_arm_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
2187 int is_user
, int is_softmmu
)
2189 env
->cp15_6
= address
;
2191 env
->exception_index
= EXCP_PREFETCH_ABORT
;
2193 env
->exception_index
= EXCP_DATA_ABORT
;
2200 #error not implemented