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,
52 #include "gen-op-arm.h"
54 typedef void (GenOpFunc)(void);
55 typedef void (GenOpFunc1)(long);
56 typedef void (GenOpFunc2)(long, long);
57 typedef void (GenOpFunc3)(long, long, long);
59 static GenOpFunc2 *gen_test_cc[14] = {
76 const uint8_t table_logic_cc[16] = {
95 static GenOpFunc1 *gen_shift_T1_im[4] = {
102 static GenOpFunc1 *gen_shift_T2_im[4] = {
109 static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
110 gen_op_shll_T1_im_cc,
111 gen_op_shrl_T1_im_cc,
112 gen_op_sarl_T1_im_cc,
113 gen_op_rorl_T1_im_cc,
116 static GenOpFunc *gen_shift_T1_T0[4] = {
123 static GenOpFunc *gen_shift_T1_T0_cc[4] = {
124 gen_op_shll_T1_T0_cc,
125 gen_op_shrl_T1_T0_cc,
126 gen_op_sarl_T1_T0_cc,
127 gen_op_rorl_T1_T0_cc,
130 static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
187 static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
226 static GenOpFunc1 *gen_op_movl_TN_im[3] = {
232 static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
237 /* normaly, since we updated PC, we need only to add 4 */
238 val = (long)s->pc + 4;
239 gen_op_movl_TN_im[t](val);
241 gen_op_movl_TN_reg[t][reg]();
245 static inline void gen_movl_T0_reg(DisasContext *s, int reg)
247 gen_movl_TN_reg(s, reg, 0);
250 static inline void gen_movl_T1_reg(DisasContext *s, int reg)
252 gen_movl_TN_reg(s, reg, 1);
255 static inline void gen_movl_T2_reg(DisasContext *s, int reg)
257 gen_movl_TN_reg(s, reg, 2);
260 static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
262 gen_op_movl_reg_TN[t][reg]();
264 s->is_jmp = DISAS_JUMP;
268 static inline void gen_movl_reg_T0(DisasContext *s, int reg)
270 gen_movl_reg_TN(s, reg, 0);
273 static inline void gen_movl_reg_T1(DisasContext *s, int reg)
275 gen_movl_reg_TN(s, reg, 1);
278 static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
282 if (!(insn & (1 << 25))) {
285 if (!(insn & (1 << 23)))
287 gen_op_addl_T1_im(val);
291 shift = (insn >> 7) & 0x1f;
292 gen_movl_T2_reg(s, rm);
294 gen_shift_T2_im[(insn >> 5) & 3](shift);
296 if (!(insn & (1 << 23)))
303 static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
307 if (insn & (1 << 22)) {
309 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
310 if (!(insn & (1 << 23)))
312 gen_op_addl_T1_im(val);
316 gen_movl_T2_reg(s, rm);
317 if (!(insn & (1 << 23)))
324 static void disas_arm_insn(DisasContext *s)
326 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
335 /* if not always execute, we generate a conditional jump to
337 gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
338 s->is_jmp = DISAS_JUMP_NEXT;
340 if (((insn & 0x0e000000) == 0 &&
341 (insn & 0x00000090) != 0x90) ||
342 ((insn & 0x0e000000) == (1 << 25))) {
343 int set_cc, logic_cc, shiftop;
345 op1 = (insn >> 21) & 0xf;
346 set_cc = (insn >> 20) & 1;
347 logic_cc = table_logic_cc[op1] & set_cc;
349 /* data processing instruction */
350 if (insn & (1 << 25)) {
351 /* immediate operand */
353 shift = ((insn >> 8) & 0xf) * 2;
355 val = (val >> shift) | (val << (32 - shift));
356 gen_op_movl_T1_im(val);
357 /* XXX: is CF modified ? */
361 gen_movl_T1_reg(s, rm);
362 shiftop = (insn >> 5) & 3;
363 if (!(insn & (1 << 4))) {
364 shift = (insn >> 7) & 0x1f;
367 gen_shift_T1_im_cc[shiftop](shift);
369 gen_shift_T1_im[shiftop](shift);
373 rs = (insn >> 8) & 0xf;
374 gen_movl_T0_reg(s, rs);
376 gen_shift_T1_T0_cc[shiftop]();
378 gen_shift_T1_T0[shiftop]();
382 if (op1 != 0x0f && op1 != 0x0d) {
383 rn = (insn >> 16) & 0xf;
384 gen_movl_T0_reg(s, rn);
386 rd = (insn >> 12) & 0xf;
390 gen_movl_reg_T0(s, rd);
392 gen_op_logic_T0_cc();
396 gen_movl_reg_T0(s, rd);
398 gen_op_logic_T0_cc();
402 gen_op_subl_T0_T1_cc();
405 gen_movl_reg_T0(s, rd);
409 gen_op_rsbl_T0_T1_cc();
412 gen_movl_reg_T0(s, rd);
416 gen_op_addl_T0_T1_cc();
419 gen_movl_reg_T0(s, rd);
423 gen_op_adcl_T0_T1_cc();
426 gen_movl_reg_T0(s, rd);
430 gen_op_sbcl_T0_T1_cc();
433 gen_movl_reg_T0(s, rd);
437 gen_op_rscl_T0_T1_cc();
440 gen_movl_reg_T0(s, rd);
445 gen_op_logic_T0_cc();
451 gen_op_logic_T0_cc();
456 gen_op_subl_T0_T1_cc();
461 gen_op_addl_T0_T1_cc();
466 gen_movl_reg_T0(s, rd);
468 gen_op_logic_T0_cc();
471 gen_movl_reg_T1(s, rd);
473 gen_op_logic_T1_cc();
477 gen_movl_reg_T0(s, rd);
479 gen_op_logic_T0_cc();
484 gen_movl_reg_T1(s, rd);
486 gen_op_logic_T1_cc();
490 /* other instructions */
491 op1 = (insn >> 24) & 0xf;
495 sh = (insn >> 5) & 3;
498 rd = (insn >> 16) & 0xf;
499 rn = (insn >> 12) & 0xf;
500 rs = (insn >> 8) & 0xf;
502 if (!(insn & (1 << 23))) {
504 gen_movl_T0_reg(s, rs);
505 gen_movl_T1_reg(s, rm);
507 if (insn & (1 << 21)) {
508 gen_movl_T1_reg(s, rn);
511 if (insn & (1 << 20))
512 gen_op_logic_T0_cc();
513 gen_movl_reg_T0(s, rd);
516 gen_movl_T0_reg(s, rs);
517 gen_movl_T1_reg(s, rm);
518 if (insn & (1 << 22))
521 gen_op_imull_T0_T1();
522 if (insn & (1 << 21))
523 gen_op_addq_T0_T1(rn, rd);
524 if (insn & (1 << 20))
526 gen_movl_reg_T0(s, rn);
527 gen_movl_reg_T1(s, rd);
530 /* SWP instruction */
531 rn = (insn >> 16) & 0xf;
532 rd = (insn >> 12) & 0xf;
535 gen_movl_T0_reg(s, rm);
536 gen_movl_T1_reg(s, rn);
537 if (insn & (1 << 22)) {
542 gen_movl_reg_T0(s, rd);
545 /* load/store half word */
546 rn = (insn >> 16) & 0xf;
547 rd = (insn >> 12) & 0xf;
548 gen_movl_T1_reg(s, rn);
549 if (insn & (1 << 25))
550 gen_add_datah_offset(s, insn);
551 if (insn & (1 << 20)) {
569 if (!(insn & (1 << 24))) {
570 gen_add_datah_offset(s, insn);
571 gen_movl_reg_T1(s, rn);
572 } else if (insn & (1 << 21)) {
573 gen_movl_reg_T1(s, rn);
581 /* load/store byte/word */
582 rn = (insn >> 16) & 0xf;
583 rd = (insn >> 12) & 0xf;
584 gen_movl_T1_reg(s, rn);
585 if (insn & (1 << 24))
586 gen_add_data_offset(s, insn);
587 if (insn & (1 << 20)) {
589 if (insn & (1 << 22))
593 gen_movl_reg_T0(s, rd);
596 gen_movl_T0_reg(s, rd);
597 if (insn & (1 << 22))
602 if (!(insn & (1 << 24))) {
603 gen_add_data_offset(s, insn);
604 gen_movl_reg_T1(s, rn);
605 } else if (insn & (1 << 21))
606 gen_movl_reg_T1(s, rn); {
613 /* load/store multiple words */
614 /* XXX: store correct base if write back */
615 if (insn & (1 << 22))
616 goto illegal_op; /* only usable in supervisor mode */
617 rn = (insn >> 16) & 0xf;
618 gen_movl_T1_reg(s, rn);
620 /* compute total size */
626 /* XXX: test invalid n == 0 case ? */
627 if (insn & (1 << 23)) {
628 if (insn & (1 << 24)) {
630 gen_op_addl_T1_im(4);
635 if (insn & (1 << 24)) {
637 gen_op_addl_T1_im(-(n * 4));
641 gen_op_addl_T1_im(-((n - 1) * 4));
646 if (insn & (1 << i)) {
647 if (insn & (1 << 20)) {
650 gen_movl_reg_T0(s, i);
654 /* special case: r15 = PC + 12 */
655 val = (long)s->pc + 8;
656 gen_op_movl_TN_im[0](val);
658 gen_movl_T0_reg(s, i);
663 /* no need to add after the last transfer */
665 gen_op_addl_T1_im(4);
668 if (insn & (1 << 21)) {
670 if (insn & (1 << 23)) {
671 if (insn & (1 << 24)) {
675 gen_op_addl_T1_im(4);
678 if (insn & (1 << 24)) {
681 gen_op_addl_T1_im(-((n - 1) * 4));
684 gen_op_addl_T1_im(-(n * 4));
687 gen_movl_reg_T1(s, rn);
696 /* branch (and link) */
698 if (insn & (1 << 24)) {
699 gen_op_movl_T0_im(val);
700 gen_op_movl_reg_TN[0][14]();
702 offset = (((int)insn << 8) >> 8);
703 val += (offset << 2) + 4;
704 gen_op_jmp((long)s->tb, val);
705 s->is_jmp = DISAS_TB_JUMP;
710 gen_op_movl_T0_im((long)s->pc);
711 gen_op_movl_reg_TN[0][15]();
713 s->is_jmp = DISAS_JUMP;
717 rd = (insn >> 12) & 0x7;
718 rn = (insn >> 16) & 0xf;
719 gen_movl_T1_reg(s, rn);
721 if (!(insn & (1 << 23)))
723 switch((insn >> 8) & 0xf) {
726 if ((insn & (1 << 24)))
727 gen_op_addl_T1_im(val);
729 if (!(insn & (1 << 24)))
730 gen_op_addl_T1_im(val);
731 if (insn & (1 << 21))
732 gen_movl_reg_T1(s, rn);
737 /* load store multiple */
738 if ((insn & (1 << 24)))
739 gen_op_addl_T1_im(val);
740 switch(insn & 0x00408000) {
741 case 0x00008000: n = 1; break;
742 case 0x00400000: n = 2; break;
743 case 0x00408000: n = 3; break;
744 default: n = 4; break;
746 for(i = 0;i < n; i++) {
749 if (!(insn & (1 << 24)))
750 gen_op_addl_T1_im(val);
751 if (insn & (1 << 21))
752 gen_movl_reg_T1(s, rn);
762 switch((insn >> 20) & 0xf) {
777 gen_op_movl_T0_im((long)s->pc - 4);
778 gen_op_movl_reg_TN[0][15]();
780 s->is_jmp = DISAS_JUMP;
786 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
787 basic block 'tb'. If search_pc is TRUE, also generate PC
788 information for each intermediate instruction. */
789 static inline int gen_intermediate_code_internal(CPUState *env,
790 TranslationBlock *tb,
793 DisasContext dc1, *dc = &dc1;
794 uint16_t *gen_opc_end;
798 /* generate intermediate code */
799 pc_start = (uint8_t *)tb->pc;
803 gen_opc_ptr = gen_opc_buf;
804 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
805 gen_opparam_ptr = gen_opparam_buf;
807 dc->is_jmp = DISAS_NEXT;
812 j = gen_opc_ptr - gen_opc_buf;
816 gen_opc_instr_start[lj++] = 0;
818 gen_opc_pc[lj] = (uint32_t)dc->pc;
819 gen_opc_instr_start[lj] = 1;
822 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
823 (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
825 case DISAS_JUMP_NEXT:
827 gen_op_jmp((long)dc->tb, (long)dc->pc);
831 /* indicate that the hash table must be used to find the next TB */
836 /* nothing more to generate */
839 *gen_opc_ptr = INDEX_op_end;
843 fprintf(logfile, "----------------\n");
844 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
845 disas(logfile, pc_start, dc->pc - pc_start, 0, 0);
846 fprintf(logfile, "\n");
848 fprintf(logfile, "OP:\n");
849 dump_ops(gen_opc_buf, gen_opparam_buf);
850 fprintf(logfile, "\n");
854 tb->size = dc->pc - pc_start;
858 int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
860 return gen_intermediate_code_internal(env, tb, 0);
863 int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
865 return gen_intermediate_code_internal(env, tb, 1);
868 CPUARMState *cpu_arm_init(void)
874 env = malloc(sizeof(CPUARMState));
877 memset(env, 0, sizeof(CPUARMState));
881 void cpu_arm_close(CPUARMState *env)
886 void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
891 fprintf(f, "R%02d=%08x", i, env->regs[i]);
897 fprintf(f, "PSR=%08x %c%c%c%c\n",
899 env->cpsr & (1 << 31) ? 'N' : '-',
900 env->cpsr & (1 << 30) ? 'Z' : '-',
901 env->cpsr & (1 << 29) ? 'C' : '-',
902 env->cpsr & (1 << 28) ? 'V' : '-');