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);
370 rs = (insn >> 8) & 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);
389 gen_op_logic_T0_cc();
393 gen_movl_reg_T0(s, rd);
395 gen_op_logic_T0_cc();
399 gen_op_subl_T0_T1_cc();
402 gen_movl_reg_T0(s, rd);
406 gen_op_rsbl_T0_T1_cc();
409 gen_movl_reg_T0(s, rd);
413 gen_op_addl_T0_T1_cc();
416 gen_movl_reg_T0(s, rd);
420 gen_op_adcl_T0_T1_cc();
423 gen_movl_reg_T0(s, rd);
427 gen_op_sbcl_T0_T1_cc();
430 gen_movl_reg_T0(s, rd);
434 gen_op_rscl_T0_T1_cc();
437 gen_movl_reg_T0(s, rd);
442 gen_op_logic_T0_cc();
448 gen_op_logic_T0_cc();
453 gen_op_subl_T0_T1_cc();
458 gen_op_addl_T0_T1_cc();
463 gen_movl_reg_T0(s, rd);
465 gen_op_logic_T0_cc();
468 gen_movl_reg_T1(s, rd);
470 gen_op_logic_T1_cc();
474 gen_movl_reg_T0(s, rd);
476 gen_op_logic_T0_cc();
481 gen_movl_reg_T1(s, rd);
483 gen_op_logic_T1_cc();
487 /* other instructions */
488 op1 = (insn >> 24) & 0xf;
492 sh = (insn >> 5) & 3;
495 rd = (insn >> 16) & 0xf;
496 rn = (insn >> 12) & 0xf;
497 rs = (insn >> 8) & 0xf;
499 if (!(insn & (1 << 23))) {
501 gen_movl_T0_reg(s, rs);
502 gen_movl_T1_reg(s, rm);
504 if (insn & (1 << 21)) {
505 gen_movl_T1_reg(s, rn);
508 if (insn & (1 << 20))
509 gen_op_logic_T0_cc();
510 gen_movl_reg_T0(s, rd);
513 gen_movl_T0_reg(s, rs);
514 gen_movl_T1_reg(s, rm);
515 if (insn & (1 << 22))
516 gen_op_imull_T0_T1();
519 if (insn & (1 << 21))
520 gen_op_addq_T0_T1(rn, rd);
521 if (insn & (1 << 20))
523 gen_movl_reg_T0(s, rn);
524 gen_movl_reg_T1(s, rd);
527 /* SWP instruction */
528 rn = (insn >> 16) & 0xf;
529 rd = (insn >> 12) & 0xf;
532 gen_movl_T0_reg(s, rm);
533 gen_movl_T1_reg(s, rn);
534 if (insn & (1 << 22)) {
539 gen_movl_reg_T0(s, rd);
542 /* load/store half word */
543 rn = (insn >> 16) & 0xf;
544 rd = (insn >> 12) & 0xf;
545 gen_movl_T1_reg(s, rn);
546 gen_add_datah_offset(s, insn);
547 if (insn & (1 << 20)) {
561 gen_movl_reg_T0(s, rd);
564 gen_movl_T0_reg(s, rd);
567 if (!(insn & (1 << 24))) {
568 gen_add_datah_offset(s, insn);
569 gen_movl_reg_T1(s, rn);
570 } else if (insn & (1 << 21)) {
571 gen_movl_reg_T1(s, rn);
579 /* load/store byte/word */
580 rn = (insn >> 16) & 0xf;
581 rd = (insn >> 12) & 0xf;
582 gen_movl_T1_reg(s, rn);
583 if (insn & (1 << 24))
584 gen_add_data_offset(s, insn);
585 if (insn & (1 << 20)) {
587 if (insn & (1 << 22))
591 gen_movl_reg_T0(s, rd);
594 gen_movl_T0_reg(s, rd);
595 if (insn & (1 << 22))
600 if (!(insn & (1 << 24))) {
601 gen_add_data_offset(s, insn);
602 gen_movl_reg_T1(s, rn);
603 } else if (insn & (1 << 21))
604 gen_movl_reg_T1(s, rn); {
611 /* load/store multiple words */
612 /* XXX: store correct base if write back */
613 if (insn & (1 << 22))
614 goto illegal_op; /* only usable in supervisor mode */
615 rn = (insn >> 16) & 0xf;
616 gen_movl_T1_reg(s, rn);
618 /* compute total size */
624 /* XXX: test invalid n == 0 case ? */
625 if (insn & (1 << 23)) {
626 if (insn & (1 << 24)) {
628 gen_op_addl_T1_im(4);
633 if (insn & (1 << 24)) {
635 gen_op_addl_T1_im(-(n * 4));
639 gen_op_addl_T1_im(-((n - 1) * 4));
644 if (insn & (1 << i)) {
645 if (insn & (1 << 20)) {
648 gen_movl_reg_T0(s, i);
652 /* special case: r15 = PC + 12 */
653 val = (long)s->pc + 8;
654 gen_op_movl_TN_im[0](val);
656 gen_movl_T0_reg(s, i);
661 /* no need to add after the last transfer */
663 gen_op_addl_T1_im(4);
666 if (insn & (1 << 21)) {
668 if (insn & (1 << 23)) {
669 if (insn & (1 << 24)) {
673 gen_op_addl_T1_im(4);
676 if (insn & (1 << 24)) {
679 gen_op_addl_T1_im(-((n - 1) * 4));
682 gen_op_addl_T1_im(-(n * 4));
685 gen_movl_reg_T1(s, rn);
694 /* branch (and link) */
696 if (insn & (1 << 24)) {
697 gen_op_movl_T0_im(val);
698 gen_op_movl_reg_TN[0][14]();
700 offset = (((int)insn << 8) >> 8);
701 val += (offset << 2) + 4;
702 gen_op_jmp((long)s->tb, val);
703 s->is_jmp = DISAS_TB_JUMP;
708 gen_op_movl_T0_im((long)s->pc);
709 gen_op_movl_reg_TN[0][15]();
711 s->is_jmp = DISAS_JUMP;
715 gen_op_movl_T0_im((long)s->pc - 4);
716 gen_op_movl_reg_TN[0][15]();
718 s->is_jmp = DISAS_JUMP;
724 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
725 basic block 'tb'. If search_pc is TRUE, also generate PC
726 information for each intermediate instruction. */
727 static inline int gen_intermediate_code_internal(CPUState *env,
728 TranslationBlock *tb,
731 DisasContext dc1, *dc = &dc1;
732 uint16_t *gen_opc_end;
736 /* generate intermediate code */
737 pc_start = (uint8_t *)tb->pc;
741 gen_opc_ptr = gen_opc_buf;
742 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
743 gen_opparam_ptr = gen_opparam_buf;
745 dc->is_jmp = DISAS_NEXT;
750 j = gen_opc_ptr - gen_opc_buf;
754 gen_opc_instr_start[lj++] = 0;
756 gen_opc_pc[lj] = (uint32_t)dc->pc;
757 gen_opc_instr_start[lj] = 1;
760 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
761 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
763 case DISAS_JUMP_NEXT:
765 gen_op_jmp((long)dc->tb, (long)dc->pc);
769 /* indicate that the hash table must be used to find the next TB */
774 /* nothing more to generate */
777 *gen_opc_ptr = INDEX_op_end;
780 if (loglevel & CPU_LOG_TB_IN_ASM) {
781 fprintf(logfile, "----------------\n");
782 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
783 disas(logfile, pc_start, dc->pc - pc_start, 0, 0);
784 fprintf(logfile, "\n");
785 if (loglevel & (CPU_LOG_TB_OP)) {
786 fprintf(logfile, "OP:\n");
787 dump_ops(gen_opc_buf, gen_opparam_buf);
788 fprintf(logfile, "\n");
793 tb->size = dc->pc - pc_start;
797 int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
799 return gen_intermediate_code_internal(env, tb, 0);
802 int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
804 return gen_intermediate_code_internal(env, tb, 1);
807 CPUARMState *cpu_arm_init(void)
813 env = malloc(sizeof(CPUARMState));
816 memset(env, 0, sizeof(CPUARMState));
820 void cpu_arm_close(CPUARMState *env)
825 void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
830 fprintf(f, "R%02d=%08x", i, env->regs[i]);
836 fprintf(f, "PSR=%08x %c%c%c%c\n",
838 env->cpsr & (1 << 31) ? 'N' : '-',
839 env->cpsr & (1 << 30) ? 'Z' : '-',
840 env->cpsr & (1 << 29) ? 'C' : '-',
841 env->cpsr & (1 << 28) ? 'V' : '-');
844 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)