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 GenOpFunc *gen_shift_T1_0[4] = {
104 static GenOpFunc1 *gen_shift_T2_im[4] = {
111 static GenOpFunc *gen_shift_T2_0[4] = {
118 static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
119 gen_op_shll_T1_im_cc,
120 gen_op_shrl_T1_im_cc,
121 gen_op_sarl_T1_im_cc,
122 gen_op_rorl_T1_im_cc,
125 static GenOpFunc *gen_shift_T1_0_cc[4] = {
132 static GenOpFunc *gen_shift_T1_T0[4] = {
139 static GenOpFunc *gen_shift_T1_T0_cc[4] = {
140 gen_op_shll_T1_T0_cc,
141 gen_op_shrl_T1_T0_cc,
142 gen_op_sarl_T1_T0_cc,
143 gen_op_rorl_T1_T0_cc,
146 static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
203 static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
242 static GenOpFunc1 *gen_op_movl_TN_im[3] = {
248 static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
253 /* normaly, since we updated PC, we need only to add 4 */
254 val = (long)s->pc + 4;
255 gen_op_movl_TN_im[t](val);
257 gen_op_movl_TN_reg[t][reg]();
261 static inline void gen_movl_T0_reg(DisasContext *s, int reg)
263 gen_movl_TN_reg(s, reg, 0);
266 static inline void gen_movl_T1_reg(DisasContext *s, int reg)
268 gen_movl_TN_reg(s, reg, 1);
271 static inline void gen_movl_T2_reg(DisasContext *s, int reg)
273 gen_movl_TN_reg(s, reg, 2);
276 static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
278 gen_op_movl_reg_TN[t][reg]();
280 s->is_jmp = DISAS_JUMP;
284 static inline void gen_movl_reg_T0(DisasContext *s, int reg)
286 gen_movl_reg_TN(s, reg, 0);
289 static inline void gen_movl_reg_T1(DisasContext *s, int reg)
291 gen_movl_reg_TN(s, reg, 1);
294 static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
296 int val, rm, shift, shiftop;
298 if (!(insn & (1 << 25))) {
301 if (!(insn & (1 << 23)))
304 gen_op_addl_T1_im(val);
308 shift = (insn >> 7) & 0x1f;
309 gen_movl_T2_reg(s, rm);
310 shiftop = (insn >> 5) & 3;
312 gen_shift_T2_im[shiftop](shift);
313 } else if (shiftop != 0) {
314 gen_shift_T2_0[shiftop]();
316 if (!(insn & (1 << 23)))
323 static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
327 if (insn & (1 << 22)) {
329 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
330 if (!(insn & (1 << 23)))
333 gen_op_addl_T1_im(val);
337 gen_movl_T2_reg(s, rm);
338 if (!(insn & (1 << 23)))
345 static void disas_arm_insn(DisasContext *s)
347 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
356 /* if not always execute, we generate a conditional jump to
358 gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
359 s->is_jmp = DISAS_JUMP_NEXT;
361 if (((insn & 0x0e000000) == 0 &&
362 (insn & 0x00000090) != 0x90) ||
363 ((insn & 0x0e000000) == (1 << 25))) {
364 int set_cc, logic_cc, shiftop;
366 op1 = (insn >> 21) & 0xf;
367 set_cc = (insn >> 20) & 1;
368 logic_cc = table_logic_cc[op1] & set_cc;
370 /* data processing instruction */
371 if (insn & (1 << 25)) {
372 /* immediate operand */
374 shift = ((insn >> 8) & 0xf) * 2;
376 val = (val >> shift) | (val << (32 - shift));
377 gen_op_movl_T1_im(val);
378 /* XXX: is CF modified ? */
382 gen_movl_T1_reg(s, rm);
383 shiftop = (insn >> 5) & 3;
384 if (!(insn & (1 << 4))) {
385 shift = (insn >> 7) & 0x1f;
388 gen_shift_T1_im_cc[shiftop](shift);
390 gen_shift_T1_im[shiftop](shift);
392 } else if (shiftop != 0) {
394 gen_shift_T1_0_cc[shiftop]();
396 gen_shift_T1_0[shiftop]();
400 rs = (insn >> 8) & 0xf;
401 gen_movl_T0_reg(s, rs);
403 gen_shift_T1_T0_cc[shiftop]();
405 gen_shift_T1_T0[shiftop]();
409 if (op1 != 0x0f && op1 != 0x0d) {
410 rn = (insn >> 16) & 0xf;
411 gen_movl_T0_reg(s, rn);
413 rd = (insn >> 12) & 0xf;
417 gen_movl_reg_T0(s, rd);
419 gen_op_logic_T0_cc();
423 gen_movl_reg_T0(s, rd);
425 gen_op_logic_T0_cc();
429 gen_op_subl_T0_T1_cc();
432 gen_movl_reg_T0(s, rd);
436 gen_op_rsbl_T0_T1_cc();
439 gen_movl_reg_T0(s, rd);
443 gen_op_addl_T0_T1_cc();
446 gen_movl_reg_T0(s, rd);
450 gen_op_adcl_T0_T1_cc();
453 gen_movl_reg_T0(s, rd);
457 gen_op_sbcl_T0_T1_cc();
460 gen_movl_reg_T0(s, rd);
464 gen_op_rscl_T0_T1_cc();
467 gen_movl_reg_T0(s, rd);
472 gen_op_logic_T0_cc();
478 gen_op_logic_T0_cc();
483 gen_op_subl_T0_T1_cc();
488 gen_op_addl_T0_T1_cc();
493 gen_movl_reg_T0(s, rd);
495 gen_op_logic_T0_cc();
498 gen_movl_reg_T1(s, rd);
500 gen_op_logic_T1_cc();
504 gen_movl_reg_T0(s, rd);
506 gen_op_logic_T0_cc();
511 gen_movl_reg_T1(s, rd);
513 gen_op_logic_T1_cc();
517 /* other instructions */
518 op1 = (insn >> 24) & 0xf;
522 sh = (insn >> 5) & 3;
525 rd = (insn >> 16) & 0xf;
526 rn = (insn >> 12) & 0xf;
527 rs = (insn >> 8) & 0xf;
529 if (!(insn & (1 << 23))) {
531 gen_movl_T0_reg(s, rs);
532 gen_movl_T1_reg(s, rm);
534 if (insn & (1 << 21)) {
535 gen_movl_T1_reg(s, rn);
538 if (insn & (1 << 20))
539 gen_op_logic_T0_cc();
540 gen_movl_reg_T0(s, rd);
543 gen_movl_T0_reg(s, rs);
544 gen_movl_T1_reg(s, rm);
545 if (insn & (1 << 22))
546 gen_op_imull_T0_T1();
549 if (insn & (1 << 21))
550 gen_op_addq_T0_T1(rn, rd);
551 if (insn & (1 << 20))
553 gen_movl_reg_T0(s, rn);
554 gen_movl_reg_T1(s, rd);
557 /* SWP instruction */
558 rn = (insn >> 16) & 0xf;
559 rd = (insn >> 12) & 0xf;
562 gen_movl_T0_reg(s, rm);
563 gen_movl_T1_reg(s, rn);
564 if (insn & (1 << 22)) {
569 gen_movl_reg_T0(s, rd);
572 /* load/store half word */
573 rn = (insn >> 16) & 0xf;
574 rd = (insn >> 12) & 0xf;
575 gen_movl_T1_reg(s, rn);
576 if (insn & (1 << 24))
577 gen_add_datah_offset(s, insn);
578 if (insn & (1 << 20)) {
592 gen_movl_reg_T0(s, rd);
595 gen_movl_T0_reg(s, rd);
598 if (!(insn & (1 << 24))) {
599 gen_add_datah_offset(s, insn);
600 gen_movl_reg_T1(s, rn);
601 } else if (insn & (1 << 21)) {
602 gen_movl_reg_T1(s, rn);
610 /* load/store byte/word */
611 rn = (insn >> 16) & 0xf;
612 rd = (insn >> 12) & 0xf;
613 gen_movl_T1_reg(s, rn);
614 if (insn & (1 << 24))
615 gen_add_data_offset(s, insn);
616 if (insn & (1 << 20)) {
618 if (insn & (1 << 22))
622 gen_movl_reg_T0(s, rd);
625 gen_movl_T0_reg(s, rd);
626 if (insn & (1 << 22))
631 if (!(insn & (1 << 24))) {
632 gen_add_data_offset(s, insn);
633 gen_movl_reg_T1(s, rn);
634 } else if (insn & (1 << 21))
635 gen_movl_reg_T1(s, rn); {
642 /* load/store multiple words */
643 /* XXX: store correct base if write back */
644 if (insn & (1 << 22))
645 goto illegal_op; /* only usable in supervisor mode */
646 rn = (insn >> 16) & 0xf;
647 gen_movl_T1_reg(s, rn);
649 /* compute total size */
655 /* XXX: test invalid n == 0 case ? */
656 if (insn & (1 << 23)) {
657 if (insn & (1 << 24)) {
659 gen_op_addl_T1_im(4);
664 if (insn & (1 << 24)) {
666 gen_op_addl_T1_im(-(n * 4));
670 gen_op_addl_T1_im(-((n - 1) * 4));
675 if (insn & (1 << i)) {
676 if (insn & (1 << 20)) {
679 gen_movl_reg_T0(s, i);
683 /* special case: r15 = PC + 12 */
684 val = (long)s->pc + 8;
685 gen_op_movl_TN_im[0](val);
687 gen_movl_T0_reg(s, i);
692 /* no need to add after the last transfer */
694 gen_op_addl_T1_im(4);
697 if (insn & (1 << 21)) {
699 if (insn & (1 << 23)) {
700 if (insn & (1 << 24)) {
704 gen_op_addl_T1_im(4);
707 if (insn & (1 << 24)) {
710 gen_op_addl_T1_im(-((n - 1) * 4));
713 gen_op_addl_T1_im(-(n * 4));
716 gen_movl_reg_T1(s, rn);
725 /* branch (and link) */
727 if (insn & (1 << 24)) {
728 gen_op_movl_T0_im(val);
729 gen_op_movl_reg_TN[0][14]();
731 offset = (((int)insn << 8) >> 8);
732 val += (offset << 2) + 4;
733 gen_op_jmp((long)s->tb, val);
734 s->is_jmp = DISAS_TB_JUMP;
739 gen_op_movl_T0_im((long)s->pc);
740 gen_op_movl_reg_TN[0][15]();
742 s->is_jmp = DISAS_JUMP;
746 gen_op_movl_T0_im((long)s->pc - 4);
747 gen_op_movl_reg_TN[0][15]();
749 s->is_jmp = DISAS_JUMP;
755 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
756 basic block 'tb'. If search_pc is TRUE, also generate PC
757 information for each intermediate instruction. */
758 static inline int gen_intermediate_code_internal(CPUState *env,
759 TranslationBlock *tb,
762 DisasContext dc1, *dc = &dc1;
763 uint16_t *gen_opc_end;
765 target_ulong pc_start;
767 /* generate intermediate code */
772 gen_opc_ptr = gen_opc_buf;
773 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
774 gen_opparam_ptr = gen_opparam_buf;
776 dc->is_jmp = DISAS_NEXT;
781 j = gen_opc_ptr - gen_opc_buf;
785 gen_opc_instr_start[lj++] = 0;
787 gen_opc_pc[lj] = dc->pc;
788 gen_opc_instr_start[lj] = 1;
791 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
792 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
794 case DISAS_JUMP_NEXT:
796 gen_op_jmp((long)dc->tb, (long)dc->pc);
800 /* indicate that the hash table must be used to find the next TB */
805 /* nothing more to generate */
808 *gen_opc_ptr = INDEX_op_end;
811 if (loglevel & CPU_LOG_TB_IN_ASM) {
812 fprintf(logfile, "----------------\n");
813 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
814 target_disas(logfile, pc_start, dc->pc - pc_start, 0);
815 fprintf(logfile, "\n");
816 if (loglevel & (CPU_LOG_TB_OP)) {
817 fprintf(logfile, "OP:\n");
818 dump_ops(gen_opc_buf, gen_opparam_buf);
819 fprintf(logfile, "\n");
824 tb->size = dc->pc - pc_start;
828 int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
830 return gen_intermediate_code_internal(env, tb, 0);
833 int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
835 return gen_intermediate_code_internal(env, tb, 1);
838 CPUARMState *cpu_arm_init(void)
844 env = malloc(sizeof(CPUARMState));
847 memset(env, 0, sizeof(CPUARMState));
848 cpu_single_env = env;
852 void cpu_arm_close(CPUARMState *env)
857 void cpu_dump_state(CPUState *env, FILE *f,
858 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
864 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
866 cpu_fprintf(f, "\n");
870 cpu_fprintf(f, "PSR=%08x %c%c%c%c\n",
872 env->cpsr & (1 << 31) ? 'N' : '-',
873 env->cpsr & (1 << 30) ? 'Z' : '-',
874 env->cpsr & (1 << 29) ? 'C' : '-',
875 env->cpsr & (1 << 28) ? 'V' : '-');
878 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)