]>
git.proxmox.com Git - mirror_qemu.git/blob - target-arm/translate.c
4 * Copyright (c) 2003 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 /* internal defines */
31 typedef struct DisasContext
{
34 struct TranslationBlock
*tb
;
37 #define DISAS_JUMP_NEXT 4
39 /* XXX: move that elsewhere */
40 static uint16_t *gen_opc_ptr
;
41 static uint32_t *gen_opparam_ptr
;
46 #define DEF(s, n, copy_size) INDEX_op_ ## s,
54 static GenOpFunc2
*gen_test_cc
[14] = {
71 const uint8_t table_logic_cc
[16] = {
90 static GenOpFunc1
*gen_shift_T1_im
[4] = {
97 static GenOpFunc1
*gen_shift_T2_im
[4] = {
104 static GenOpFunc1
*gen_shift_T1_im_cc
[4] = {
105 gen_op_shll_T1_im_cc
,
106 gen_op_shrl_T1_im_cc
,
107 gen_op_sarl_T1_im_cc
,
108 gen_op_rorl_T1_im_cc
,
111 static GenOpFunc
*gen_shift_T1_T0
[4] = {
118 static GenOpFunc
*gen_shift_T1_T0_cc
[4] = {
119 gen_op_shll_T1_T0_cc
,
120 gen_op_shrl_T1_T0_cc
,
121 gen_op_sarl_T1_T0_cc
,
122 gen_op_rorl_T1_T0_cc
,
125 static GenOpFunc
*gen_op_movl_TN_reg
[3][16] = {
182 static GenOpFunc
*gen_op_movl_reg_TN
[2][16] = {
221 static GenOpFunc1
*gen_op_movl_TN_im
[3] = {
227 static inline void gen_movl_TN_reg(DisasContext
*s
, int reg
, int t
)
232 /* normaly, since we updated PC, we need only to add 4 */
233 val
= (long)s
->pc
+ 4;
234 gen_op_movl_TN_im
[t
](val
);
236 gen_op_movl_TN_reg
[t
][reg
]();
240 static inline void gen_movl_T0_reg(DisasContext
*s
, int reg
)
242 gen_movl_TN_reg(s
, reg
, 0);
245 static inline void gen_movl_T1_reg(DisasContext
*s
, int reg
)
247 gen_movl_TN_reg(s
, reg
, 1);
250 static inline void gen_movl_T2_reg(DisasContext
*s
, int reg
)
252 gen_movl_TN_reg(s
, reg
, 2);
255 static inline void gen_movl_reg_TN(DisasContext
*s
, int reg
, int t
)
257 gen_op_movl_reg_TN
[t
][reg
]();
259 s
->is_jmp
= DISAS_JUMP
;
263 static inline void gen_movl_reg_T0(DisasContext
*s
, int reg
)
265 gen_movl_reg_TN(s
, reg
, 0);
268 static inline void gen_movl_reg_T1(DisasContext
*s
, int reg
)
270 gen_movl_reg_TN(s
, reg
, 1);
273 static inline void gen_add_data_offset(DisasContext
*s
, unsigned int insn
)
277 if (!(insn
& (1 << 25))) {
280 if (!(insn
& (1 << 23)))
283 gen_op_addl_T1_im(val
);
287 shift
= (insn
>> 7) & 0x1f;
288 gen_movl_T2_reg(s
, rm
);
290 gen_shift_T2_im
[(insn
>> 5) & 3](shift
);
292 if (!(insn
& (1 << 23)))
299 static inline void gen_add_datah_offset(DisasContext
*s
, unsigned int insn
)
303 if (insn
& (1 << 22)) {
305 val
= (insn
& 0xf) | ((insn
>> 4) & 0xf0);
306 if (!(insn
& (1 << 23)))
309 gen_op_addl_T1_im(val
);
313 gen_movl_T2_reg(s
, rm
);
314 if (!(insn
& (1 << 23)))
321 static void disas_arm_insn(DisasContext
*s
)
323 unsigned int cond
, insn
, val
, op1
, i
, shift
, rm
, rs
, rn
, rd
, sh
;
332 /* if not always execute, we generate a conditional jump to
334 gen_test_cc
[cond
^ 1]((long)s
->tb
, (long)s
->pc
);
335 s
->is_jmp
= DISAS_JUMP_NEXT
;
337 if (((insn
& 0x0e000000) == 0 &&
338 (insn
& 0x00000090) != 0x90) ||
339 ((insn
& 0x0e000000) == (1 << 25))) {
340 int set_cc
, logic_cc
, shiftop
;
342 op1
= (insn
>> 21) & 0xf;
343 set_cc
= (insn
>> 20) & 1;
344 logic_cc
= table_logic_cc
[op1
] & set_cc
;
346 /* data processing instruction */
347 if (insn
& (1 << 25)) {
348 /* immediate operand */
350 shift
= ((insn
>> 8) & 0xf) * 2;
352 val
= (val
>> shift
) | (val
<< (32 - shift
));
353 gen_op_movl_T1_im(val
);
354 /* XXX: is CF modified ? */
358 gen_movl_T1_reg(s
, rm
);
359 shiftop
= (insn
>> 5) & 3;
360 if (!(insn
& (1 << 4))) {
361 shift
= (insn
>> 7) & 0x1f;
364 gen_shift_T1_im_cc
[shiftop
](shift
);
366 gen_shift_T1_im
[shiftop
](shift
);
368 } else if (shiftop
== 3) {
375 rs
= (insn
>> 8) & 0xf;
376 gen_movl_T0_reg(s
, rs
);
378 gen_shift_T1_T0_cc
[shiftop
]();
380 gen_shift_T1_T0
[shiftop
]();
384 if (op1
!= 0x0f && op1
!= 0x0d) {
385 rn
= (insn
>> 16) & 0xf;
386 gen_movl_T0_reg(s
, rn
);
388 rd
= (insn
>> 12) & 0xf;
392 gen_movl_reg_T0(s
, rd
);
394 gen_op_logic_T0_cc();
398 gen_movl_reg_T0(s
, rd
);
400 gen_op_logic_T0_cc();
404 gen_op_subl_T0_T1_cc();
407 gen_movl_reg_T0(s
, rd
);
411 gen_op_rsbl_T0_T1_cc();
414 gen_movl_reg_T0(s
, rd
);
418 gen_op_addl_T0_T1_cc();
421 gen_movl_reg_T0(s
, rd
);
425 gen_op_adcl_T0_T1_cc();
428 gen_movl_reg_T0(s
, rd
);
432 gen_op_sbcl_T0_T1_cc();
435 gen_movl_reg_T0(s
, rd
);
439 gen_op_rscl_T0_T1_cc();
442 gen_movl_reg_T0(s
, rd
);
447 gen_op_logic_T0_cc();
453 gen_op_logic_T0_cc();
458 gen_op_subl_T0_T1_cc();
463 gen_op_addl_T0_T1_cc();
468 gen_movl_reg_T0(s
, rd
);
470 gen_op_logic_T0_cc();
473 gen_movl_reg_T1(s
, rd
);
475 gen_op_logic_T1_cc();
479 gen_movl_reg_T0(s
, rd
);
481 gen_op_logic_T0_cc();
486 gen_movl_reg_T1(s
, rd
);
488 gen_op_logic_T1_cc();
492 /* other instructions */
493 op1
= (insn
>> 24) & 0xf;
497 sh
= (insn
>> 5) & 3;
500 rd
= (insn
>> 16) & 0xf;
501 rn
= (insn
>> 12) & 0xf;
502 rs
= (insn
>> 8) & 0xf;
504 if (!(insn
& (1 << 23))) {
506 gen_movl_T0_reg(s
, rs
);
507 gen_movl_T1_reg(s
, rm
);
509 if (insn
& (1 << 21)) {
510 gen_movl_T1_reg(s
, rn
);
513 if (insn
& (1 << 20))
514 gen_op_logic_T0_cc();
515 gen_movl_reg_T0(s
, rd
);
518 gen_movl_T0_reg(s
, rs
);
519 gen_movl_T1_reg(s
, rm
);
520 if (insn
& (1 << 22))
521 gen_op_imull_T0_T1();
524 if (insn
& (1 << 21))
525 gen_op_addq_T0_T1(rn
, rd
);
526 if (insn
& (1 << 20))
528 gen_movl_reg_T0(s
, rn
);
529 gen_movl_reg_T1(s
, rd
);
532 /* SWP instruction */
533 rn
= (insn
>> 16) & 0xf;
534 rd
= (insn
>> 12) & 0xf;
537 gen_movl_T0_reg(s
, rm
);
538 gen_movl_T1_reg(s
, rn
);
539 if (insn
& (1 << 22)) {
544 gen_movl_reg_T0(s
, rd
);
547 /* load/store half word */
548 rn
= (insn
>> 16) & 0xf;
549 rd
= (insn
>> 12) & 0xf;
550 gen_movl_T1_reg(s
, rn
);
551 if (insn
& (1 << 24))
552 gen_add_datah_offset(s
, insn
);
553 if (insn
& (1 << 20)) {
567 gen_movl_reg_T0(s
, rd
);
570 gen_movl_T0_reg(s
, rd
);
573 if (!(insn
& (1 << 24))) {
574 gen_add_datah_offset(s
, insn
);
575 gen_movl_reg_T1(s
, rn
);
576 } else if (insn
& (1 << 21)) {
577 gen_movl_reg_T1(s
, rn
);
585 /* load/store byte/word */
586 rn
= (insn
>> 16) & 0xf;
587 rd
= (insn
>> 12) & 0xf;
588 gen_movl_T1_reg(s
, rn
);
589 if (insn
& (1 << 24))
590 gen_add_data_offset(s
, insn
);
591 if (insn
& (1 << 20)) {
593 if (insn
& (1 << 22))
597 gen_movl_reg_T0(s
, rd
);
600 gen_movl_T0_reg(s
, rd
);
601 if (insn
& (1 << 22))
606 if (!(insn
& (1 << 24))) {
607 gen_add_data_offset(s
, insn
);
608 gen_movl_reg_T1(s
, rn
);
609 } else if (insn
& (1 << 21))
610 gen_movl_reg_T1(s
, rn
); {
617 /* load/store multiple words */
618 /* XXX: store correct base if write back */
619 if (insn
& (1 << 22))
620 goto illegal_op
; /* only usable in supervisor mode */
621 rn
= (insn
>> 16) & 0xf;
622 gen_movl_T1_reg(s
, rn
);
624 /* compute total size */
630 /* XXX: test invalid n == 0 case ? */
631 if (insn
& (1 << 23)) {
632 if (insn
& (1 << 24)) {
634 gen_op_addl_T1_im(4);
639 if (insn
& (1 << 24)) {
641 gen_op_addl_T1_im(-(n
* 4));
645 gen_op_addl_T1_im(-((n
- 1) * 4));
650 if (insn
& (1 << i
)) {
651 if (insn
& (1 << 20)) {
654 gen_movl_reg_T0(s
, i
);
658 /* special case: r15 = PC + 12 */
659 val
= (long)s
->pc
+ 8;
660 gen_op_movl_TN_im
[0](val
);
662 gen_movl_T0_reg(s
, i
);
667 /* no need to add after the last transfer */
669 gen_op_addl_T1_im(4);
672 if (insn
& (1 << 21)) {
674 if (insn
& (1 << 23)) {
675 if (insn
& (1 << 24)) {
679 gen_op_addl_T1_im(4);
682 if (insn
& (1 << 24)) {
685 gen_op_addl_T1_im(-((n
- 1) * 4));
688 gen_op_addl_T1_im(-(n
* 4));
691 gen_movl_reg_T1(s
, rn
);
700 /* branch (and link) */
702 if (insn
& (1 << 24)) {
703 gen_op_movl_T0_im(val
);
704 gen_op_movl_reg_TN
[0][14]();
706 offset
= (((int)insn
<< 8) >> 8);
707 val
+= (offset
<< 2) + 4;
708 gen_op_jmp((long)s
->tb
, val
);
709 s
->is_jmp
= DISAS_TB_JUMP
;
714 gen_op_movl_T0_im((long)s
->pc
);
715 gen_op_movl_reg_TN
[0][15]();
717 s
->is_jmp
= DISAS_JUMP
;
721 gen_op_movl_T0_im((long)s
->pc
- 4);
722 gen_op_movl_reg_TN
[0][15]();
724 s
->is_jmp
= DISAS_JUMP
;
730 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
731 basic block 'tb'. If search_pc is TRUE, also generate PC
732 information for each intermediate instruction. */
733 static inline int gen_intermediate_code_internal(CPUState
*env
,
734 TranslationBlock
*tb
,
737 DisasContext dc1
, *dc
= &dc1
;
738 uint16_t *gen_opc_end
;
742 /* generate intermediate code */
743 pc_start
= (uint8_t *)tb
->pc
;
747 gen_opc_ptr
= gen_opc_buf
;
748 gen_opc_end
= gen_opc_buf
+ OPC_MAX_SIZE
;
749 gen_opparam_ptr
= gen_opparam_buf
;
751 dc
->is_jmp
= DISAS_NEXT
;
756 j
= gen_opc_ptr
- gen_opc_buf
;
760 gen_opc_instr_start
[lj
++] = 0;
762 gen_opc_pc
[lj
] = (uint32_t)dc
->pc
;
763 gen_opc_instr_start
[lj
] = 1;
766 } while (!dc
->is_jmp
&& gen_opc_ptr
< gen_opc_end
&&
767 (dc
->pc
- pc_start
) < (TARGET_PAGE_SIZE
- 32));
769 case DISAS_JUMP_NEXT
:
771 gen_op_jmp((long)dc
->tb
, (long)dc
->pc
);
775 /* indicate that the hash table must be used to find the next TB */
780 /* nothing more to generate */
783 *gen_opc_ptr
= INDEX_op_end
;
786 if (loglevel
& CPU_LOG_TB_IN_ASM
) {
787 fprintf(logfile
, "----------------\n");
788 fprintf(logfile
, "IN: %s\n", lookup_symbol(pc_start
));
789 disas(logfile
, pc_start
, dc
->pc
- pc_start
, 0, 0);
790 fprintf(logfile
, "\n");
791 if (loglevel
& (CPU_LOG_TB_OP
)) {
792 fprintf(logfile
, "OP:\n");
793 dump_ops(gen_opc_buf
, gen_opparam_buf
);
794 fprintf(logfile
, "\n");
799 tb
->size
= dc
->pc
- pc_start
;
803 int gen_intermediate_code(CPUState
*env
, TranslationBlock
*tb
)
805 return gen_intermediate_code_internal(env
, tb
, 0);
808 int gen_intermediate_code_pc(CPUState
*env
, TranslationBlock
*tb
)
810 return gen_intermediate_code_internal(env
, tb
, 1);
813 CPUARMState
*cpu_arm_init(void)
819 env
= malloc(sizeof(CPUARMState
));
822 memset(env
, 0, sizeof(CPUARMState
));
823 cpu_single_env
= env
;
827 void cpu_arm_close(CPUARMState
*env
)
832 void cpu_dump_state(CPUState
*env
, FILE *f
,
833 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...),
839 cpu_fprintf(f
, "R%02d=%08x", i
, env
->regs
[i
]);
841 cpu_fprintf(f
, "\n");
845 cpu_fprintf(f
, "PSR=%08x %c%c%c%c\n",
847 env
->cpsr
& (1 << 31) ? 'N' : '-',
848 env
->cpsr
& (1 << 30) ? 'Z' : '-',
849 env
->cpsr
& (1 << 29) ? 'C' : '-',
850 env
->cpsr
& (1 << 28) ? 'V' : '-');
853 target_ulong
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)