]>
git.proxmox.com Git - qemu.git/blob - translate-arm.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 /* XXX: move that elsewhere */
38 static uint16_t *gen_opc_ptr
;
39 static uint32_t *gen_opparam_ptr
;
44 #define DEF(s, n, copy_size) INDEX_op_ ## s,
50 #include "gen-op-arm.h"
52 typedef void (GenOpFunc
)(void);
53 typedef void (GenOpFunc1
)(long);
54 typedef void (GenOpFunc2
)(long, long);
55 typedef void (GenOpFunc3
)(long, long, long);
57 static GenOpFunc2
*gen_test_cc
[14] = {
74 const uint8_t table_logic_cc
[16] = {
93 static GenOpFunc1
*gen_shift_T1_im
[4] = {
100 static GenOpFunc1
*gen_shift_T2_im
[4] = {
107 static GenOpFunc1
*gen_shift_T1_im_cc
[4] = {
108 gen_op_shll_T1_im_cc
,
109 gen_op_shrl_T1_im_cc
,
110 gen_op_sarl_T1_im_cc
,
111 gen_op_rorl_T1_im_cc
,
114 static GenOpFunc
*gen_shift_T1_T0
[4] = {
121 static GenOpFunc
*gen_shift_T1_T0_cc
[4] = {
122 gen_op_shll_T1_T0_cc
,
123 gen_op_shrl_T1_T0_cc
,
124 gen_op_sarl_T1_T0_cc
,
125 gen_op_rorl_T1_T0_cc
,
128 static GenOpFunc
*gen_op_movl_TN_reg
[3][16] = {
185 static GenOpFunc
*gen_op_movl_reg_TN
[2][16] = {
224 static GenOpFunc1
*gen_op_movl_TN_im
[3] = {
230 static inline void gen_movl_TN_reg(DisasContext
*s
, int reg
, int t
)
235 /* normaly, since we updated PC, we need only to add 4 */
236 val
= (long)s
->pc
+ 4;
237 gen_op_movl_TN_im
[t
](val
);
239 gen_op_movl_TN_reg
[t
][reg
]();
243 static inline void gen_movl_T0_reg(DisasContext
*s
, int reg
)
245 gen_movl_TN_reg(s
, reg
, 0);
248 static inline void gen_movl_T1_reg(DisasContext
*s
, int reg
)
250 gen_movl_TN_reg(s
, reg
, 1);
253 static inline void gen_movl_T2_reg(DisasContext
*s
, int reg
)
255 gen_movl_TN_reg(s
, reg
, 2);
258 static inline void gen_movl_reg_TN(DisasContext
*s
, int reg
, int t
)
260 gen_op_movl_reg_TN
[t
][reg
]();
262 s
->is_jmp
= DISAS_JUMP
;
266 static inline void gen_movl_reg_T0(DisasContext
*s
, int reg
)
268 gen_movl_reg_TN(s
, reg
, 0);
271 static inline void gen_movl_reg_T1(DisasContext
*s
, int reg
)
273 gen_movl_reg_TN(s
, reg
, 1);
276 static inline void gen_add_data_offset(DisasContext
*s
, unsigned int insn
)
280 if (!(insn
& (1 << 25))) {
283 if (!(insn
& (1 << 23)))
285 gen_op_addl_T1_im(val
);
289 shift
= (insn
>> 7) & 0x1f;
290 gen_movl_T2_reg(s
, rm
);
292 gen_shift_T2_im
[(insn
>> 5) & 3](shift
);
294 if (!(insn
& (1 << 23)))
301 static inline void gen_add_datah_offset(DisasContext
*s
, unsigned int insn
)
305 if (insn
& (1 << 22)) {
307 val
= (insn
& 0xf) | ((insn
>> 4) & 0xf0);
308 if (!(insn
& (1 << 23)))
310 gen_op_addl_T1_im(val
);
314 gen_movl_T2_reg(s
, rm
);
315 if (!(insn
& (1 << 23)))
322 static void disas_arm_insn(DisasContext
*s
)
324 unsigned int cond
, insn
, val
, op1
, i
, shift
, rm
, rs
, rn
, rd
, sh
;
333 /* if not always execute, we generate a conditional jump to
335 gen_test_cc
[cond
^ 1]((long)s
->tb
, (long)s
->pc
);
338 if ((insn
& 0x0c000000) == 0 &&
339 (insn
& 0x00000090) != 0x90) {
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
);
370 rs
= (insn
>> 16) & 0xf;
371 gen_movl_T0_reg(s
, rs
);
373 gen_shift_T1_T0_cc
[shiftop
]();
375 gen_shift_T1_T0
[shiftop
]();
379 if (op1
!= 0x0f && op1
!= 0x0d) {
380 rn
= (insn
>> 16) & 0xf;
381 gen_movl_T0_reg(s
, rn
);
383 rd
= (insn
>> 12) & 0xf;
387 gen_movl_reg_T0(s
, rd
);
391 gen_movl_reg_T0(s
, rd
);
395 gen_op_subl_T0_T1_cc();
398 gen_movl_reg_T0(s
, rd
);
402 gen_op_rsbl_T0_T1_cc();
405 gen_movl_reg_T0(s
, rd
);
409 gen_op_addl_T0_T1_cc();
412 gen_movl_reg_T0(s
, rd
);
416 gen_op_adcl_T0_T1_cc();
419 gen_movl_reg_T0(s
, rd
);
423 gen_op_sbcl_T0_T1_cc();
426 gen_movl_reg_T0(s
, rd
);
430 gen_op_rscl_T0_T1_cc();
433 gen_movl_reg_T0(s
, rd
);
447 gen_op_subl_T0_T1_cc();
452 gen_op_addl_T0_T1_cc();
457 gen_movl_reg_T0(s
, rd
);
460 gen_movl_reg_T1(s
, rd
);
464 gen_movl_reg_T0(s
, rd
);
469 gen_movl_reg_T1(s
, rd
);
475 /* other instructions */
476 op1
= (insn
>> 24) & 0xf;
480 sh
= (insn
>> 5) & 3;
483 rd
= (insn
>> 16) & 0xf;
484 rn
= (insn
>> 12) & 0xf;
485 rs
= (insn
>> 8) & 0xf;
487 if (!(insn
& (1 << 23))) {
489 gen_movl_T0_reg(s
, rs
);
490 gen_movl_T1_reg(s
, rm
);
492 if (insn
& (1 << 21)) {
493 gen_movl_T1_reg(s
, rn
);
496 if (insn
& (1 << 20))
498 gen_movl_reg_T0(s
, rd
);
501 gen_movl_T0_reg(s
, rs
);
502 gen_movl_T1_reg(s
, rm
);
503 if (insn
& (1 << 22))
506 gen_op_imull_T0_T1();
507 if (insn
& (1 << 21))
508 gen_op_addq_T0_T1(rn
, rd
);
509 if (insn
& (1 << 20))
511 gen_movl_reg_T0(s
, rn
);
512 gen_movl_reg_T1(s
, rd
);
515 /* SWP instruction */
516 rn
= (insn
>> 16) & 0xf;
517 rd
= (insn
>> 12) & 0xf;
520 gen_movl_T0_reg(s
, rm
);
521 gen_movl_T1_reg(s
, rn
);
522 if (insn
& (1 << 22)) {
527 gen_movl_reg_T0(s
, rd
);
530 /* load/store half word */
531 rn
= (insn
>> 16) & 0xf;
532 rd
= (insn
>> 12) & 0xf;
533 gen_movl_T1_reg(s
, rn
);
534 if (insn
& (1 << 25))
535 gen_add_datah_offset(s
, insn
);
536 if (insn
& (1 << 20)) {
554 if (!(insn
& (1 << 24)))
555 gen_add_datah_offset(s
, insn
);
556 if (insn
& (1 << 21))
557 gen_movl_reg_T1(s
, rn
);
564 /* load/store byte/word */
565 rn
= (insn
>> 16) & 0xf;
566 rd
= (insn
>> 12) & 0xf;
567 gen_movl_T1_reg(s
, rn
);
568 if (insn
& (1 << 24))
569 gen_add_data_offset(s
, insn
);
570 if (insn
& (1 << 20)) {
572 if (insn
& (1 << 22))
576 gen_movl_reg_T0(s
, rd
);
579 gen_movl_T0_reg(s
, rd
);
580 if (insn
& (1 << 22))
585 if (!(insn
& (1 << 24)))
586 gen_add_data_offset(s
, insn
);
587 if (insn
& (1 << 21))
588 gen_movl_reg_T1(s
, rn
);
592 /* load/store multiple words */
593 if (insn
& (1 << 22))
594 goto illegal_op
; /* only usable in supervisor mode */
595 rn
= (insn
>> 16) & 0xf;
596 gen_movl_T1_reg(s
, rn
);
598 if (!(insn
& (1 << 23)))
601 if (insn
& (1 << i
)) {
602 if (insn
& (1 << 24))
603 gen_op_addl_T1_im(val
);
604 if (insn
& (1 << 20)) {
607 gen_movl_reg_T0(s
, i
);
610 gen_movl_T0_reg(s
, i
);
613 if (!(insn
& (1 << 24)))
614 gen_op_addl_T1_im(val
);
617 if (insn
& (1 << 21))
618 gen_movl_reg_T1(s
, rn
);
625 /* branch (and link) */
627 if (insn
& (1 << 24)) {
628 gen_op_movl_T0_im(val
);
629 gen_op_movl_reg_TN
[0][14]();
631 offset
= (((int)insn
<< 8) >> 8);
632 val
+= (offset
<< 2) + 4;
633 gen_op_jmp((long)s
->tb
, val
);
634 s
->is_jmp
= DISAS_TB_JUMP
;
639 gen_op_movl_T0_im((long)s
->pc
);
640 gen_op_movl_reg_TN
[0][15]();
642 s
->is_jmp
= DISAS_JUMP
;
646 gen_op_movl_T0_im((long)s
->pc
- 4);
647 gen_op_movl_reg_TN
[0][15]();
649 s
->is_jmp
= DISAS_JUMP
;
655 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
656 basic block 'tb'. If search_pc is TRUE, also generate PC
657 information for each intermediate instruction. */
658 int gen_intermediate_code(TranslationBlock
*tb
, int search_pc
)
660 DisasContext dc1
, *dc
= &dc1
;
661 uint16_t *gen_opc_end
;
665 /* generate intermediate code */
666 pc_start
= (uint8_t *)tb
->pc
;
670 gen_opc_ptr
= gen_opc_buf
;
671 gen_opc_end
= gen_opc_buf
+ OPC_MAX_SIZE
;
672 gen_opparam_ptr
= gen_opparam_buf
;
674 dc
->is_jmp
= DISAS_NEXT
;
679 j
= gen_opc_ptr
- gen_opc_buf
;
683 gen_opc_instr_start
[lj
++] = 0;
684 gen_opc_pc
[lj
] = (uint32_t)dc
->pc
;
685 gen_opc_instr_start
[lj
] = 1;
689 } while (!dc
->is_jmp
&& gen_opc_ptr
< gen_opc_end
&&
690 (dc
->pc
- pc_start
) < (TARGET_PAGE_SIZE
- 32));
691 /* we must store the eflags state if it is not already done */
692 if (dc
->is_jmp
!= DISAS_TB_JUMP
&&
693 dc
->is_jmp
!= DISAS_JUMP
) {
694 gen_op_movl_T0_im((long)dc
->pc
- 4);
695 gen_op_movl_reg_TN
[0][15]();
697 if (dc
->is_jmp
!= DISAS_TB_JUMP
) {
698 /* indicate that the hash table must be used to find the next TB */
701 *gen_opc_ptr
= INDEX_op_end
;
705 fprintf(logfile
, "----------------\n");
706 fprintf(logfile
, "IN: %s\n", lookup_symbol(pc_start
));
707 disas(logfile
, pc_start
, dc
->pc
- pc_start
, 0, 0);
708 fprintf(logfile
, "\n");
710 fprintf(logfile
, "OP:\n");
711 dump_ops(gen_opc_buf
, gen_opparam_buf
);
712 fprintf(logfile
, "\n");
716 tb
->size
= dc
->pc
- pc_start
;
720 CPUARMState
*cpu_arm_init(void)
726 env
= malloc(sizeof(CPUARMState
));
729 memset(env
, 0, sizeof(CPUARMState
));
733 void cpu_arm_close(CPUARMState
*env
)
738 void cpu_arm_dump_state(CPUARMState
*env
, FILE *f
, int flags
)
743 fprintf(f
, "R%02d=%08x", i
, env
->regs
[i
]);
749 fprintf(f
, "CPSR=%08x", env
->cpsr
);