diff --git a/arm-dis.c b/arm-dis.c index adacd898b6..a84d91b488 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -560,8 +560,8 @@ static arm_regname regnames[] = { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }} }; -/* Default to GCC register name set. */ -static unsigned int regname_selected = 1; +/* Default to STD register name set. */ +static unsigned int regname_selected = 2; #define NUM_ARM_REGNAMES NUM_ELEM (regnames) #define arm_regnames regnames[regname_selected].reg_names diff --git a/exec-arm.h b/exec-arm.h index 8da263672b..e838e88239 100644 --- a/exec-arm.h +++ b/exec-arm.h @@ -30,3 +30,11 @@ register uint32_t T2 asm(AREG3); void cpu_lock(void); void cpu_unlock(void); void cpu_loop_exit(void); + +static inline int compute_cpsr(void) +{ + int ZF; + ZF = (env->NZF == 0); + return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); +} diff --git a/op-arm.c b/op-arm.c index 40cf3cd253..8e5cce0e9b 100644 --- a/op-arm.c +++ b/op-arm.c @@ -154,11 +154,11 @@ void OPPROTO op_adcl_T0_T1_cc(void) FORCE_RET(); } -#define OPSUB(sub, sbc, T0, T1) \ +#define OPSUB(sub, sbc, res, T0, T1) \ \ void OPPROTO op_ ## sub ## l_T0_T1(void) \ { \ - T0 -= T1; \ + res = T0 - T1; \ } \ \ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ @@ -167,13 +167,14 @@ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ src1 = T0; \ T0 -= T1; \ env->NZF = T0; \ - env->CF = src1 < T1; \ + env->CF = src1 >= T1; \ env->VF = (src1 ^ T1) & (src1 ^ T0); \ + res = T0; \ } \ \ void OPPROTO op_ ## sbc ## l_T0_T1(void) \ { \ - T0 = T0 - T1 + env->CF - 1; \ + res = T0 - T1 + env->CF - 1; \ } \ \ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ @@ -182,20 +183,20 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ src1 = T0; \ if (!env->CF) { \ T0 = T0 - T1 - 1; \ - T0 += T1; \ - env->CF = src1 < T1; \ + env->CF = src1 >= T1; \ } else { \ T0 = T0 - T1; \ - env->CF = src1 <= T1; \ + env->CF = src1 > T1; \ } \ env->VF = (src1 ^ T1) & (src1 ^ T0); \ env->NZF = T0; \ + res = T0; \ FORCE_RET(); \ } -OPSUB(sub, sbc, T0, T1) +OPSUB(sub, sbc, T0, T0, T1) -OPSUB(rsb, rsc, T1, T0) +OPSUB(rsb, rsc, T0, T1, T0) void OPPROTO op_andl_T0_T1(void) { @@ -222,11 +223,16 @@ void OPPROTO op_notl_T1(void) T1 = ~T1; } -void OPPROTO op_logic_cc(void) +void OPPROTO op_logic_T0_cc(void) { env->NZF = T0; } +void OPPROTO op_logic_T1_cc(void) +{ + env->NZF = T1; +} + #define EIP (env->regs[15]) void OPPROTO op_test_eq(void) @@ -334,10 +340,7 @@ void OPPROTO op_jmp(void) void OPPROTO op_movl_T0_psr(void) { - int ZF; - ZF = (env->NZF == 0); - T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); + T0 = compute_cpsr(); } /* NOTE: N = 1 and Z = 1 cannot be stored currently */ diff --git a/translate-arm.c b/translate-arm.c index 2413f02a55..6020e772d3 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -34,6 +34,8 @@ typedef struct DisasContext { struct TranslationBlock *tb; } DisasContext; +#define DISAS_JUMP_NEXT 4 + /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; @@ -333,10 +335,11 @@ static void disas_arm_insn(DisasContext *s) /* if not always execute, we generate a conditional jump to next instruction */ gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - s->is_jmp = 1; + s->is_jmp = DISAS_JUMP_NEXT; } - if ((insn & 0x0c000000) == 0 && - (insn & 0x00000090) != 0x90) { + if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { int set_cc, logic_cc, shiftop; op1 = (insn >> 21) & 0xf; @@ -367,7 +370,7 @@ static void disas_arm_insn(DisasContext *s) } } } else { - rs = (insn >> 16) & 0xf; + rs = (insn >> 8) & 0xf; gen_movl_T0_reg(s, rs); if (logic_cc) { gen_shift_T1_T0_cc[shiftop](); @@ -385,10 +388,14 @@ static void disas_arm_insn(DisasContext *s) case 0x00: gen_op_andl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; case 0x01: gen_op_xorl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; case 0x02: if (set_cc) @@ -435,11 +442,13 @@ static void disas_arm_insn(DisasContext *s) case 0x08: if (set_cc) { gen_op_andl_T0_T1(); + gen_op_logic_T0_cc(); } break; case 0x09: if (set_cc) { gen_op_xorl_T0_T1(); + gen_op_logic_T0_cc(); } break; case 0x0a: @@ -455,22 +464,28 @@ static void disas_arm_insn(DisasContext *s) case 0x0c: gen_op_orl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; case 0x0d: gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); break; case 0x0e: gen_op_bicl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; default: case 0x0f: gen_op_notl_T1(); gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); break; } - if (logic_cc) - gen_op_logic_cc(); } else { /* other instructions */ op1 = (insn >> 24) & 0xf; @@ -494,7 +509,7 @@ static void disas_arm_insn(DisasContext *s) gen_op_addl_T0_T1(); } if (insn & (1 << 20)) - gen_op_logic_cc(); + gen_op_logic_T0_cc(); gen_movl_reg_T0(s, rd); } else { /* 64 bit mul */ @@ -551,10 +566,12 @@ static void disas_arm_insn(DisasContext *s) /* store */ gen_op_stw_T0_T1(); } - if (!(insn & (1 << 24))) + if (!(insn & (1 << 24))) { gen_add_datah_offset(s, insn); - if (insn & (1 << 21)) gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) { + gen_movl_reg_T1(s, rn); + } } break; case 0x4: @@ -582,40 +599,94 @@ static void disas_arm_insn(DisasContext *s) else gen_op_stl_T0_T1(); } - if (!(insn & (1 << 24))) + if (!(insn & (1 << 24))) { gen_add_data_offset(s, insn); - if (insn & (1 << 21)) gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); { + } break; case 0x08: case 0x09: - /* load/store multiple words */ - if (insn & (1 << 22)) - goto illegal_op; /* only usable in supervisor mode */ - rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); - val = 4; - if (!(insn & (1 << 23))) - val = -val; - for(i=0;i<16;i++) { - if (insn & (1 << i)) { - if (insn & (1 << 24)) - gen_op_addl_T1_im(val); - if (insn & (1 << 20)) { - /* load */ - gen_op_ldl_T0_T1(); - gen_movl_reg_T0(s, i); + { + int j, n; + /* load/store multiple words */ + /* XXX: store correct base if write back */ + if (insn & (1 << 22)) + goto illegal_op; /* only usable in supervisor mode */ + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + + /* compute total size */ + n = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) + n++; + } + /* XXX: test invalid n == 0 case ? */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + gen_op_addl_T1_im(4); } else { - /* store */ - gen_movl_T0_reg(s, i); - gen_op_stl_T0_T1(); + /* post increment */ } - if (!(insn & (1 << 24))) - gen_op_addl_T1_im(val); + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + gen_op_addl_T1_im(-(n * 4)); + } else { + /* post decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } + } + j = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 20)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, i); + } else { + /* store */ + if (i == 15) { + /* special case: r15 = PC + 12 */ + val = (long)s->pc + 8; + gen_op_movl_TN_im[0](val); + } else { + gen_movl_T0_reg(s, i); + } + gen_op_stl_T0_T1(); + } + j++; + /* no need to add after the last transfer */ + if (j != n) + gen_op_addl_T1_im(4); + } + } + if (insn & (1 << 21)) { + /* write back */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + } else { + /* post increment */ + gen_op_addl_T1_im(4); + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } else { + /* post decrement */ + gen_op_addl_T1_im(-(n * 4)); + } + } + gen_movl_reg_T1(s, rn); } } - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); break; case 0xa: case 0xb: @@ -641,6 +712,66 @@ static void disas_arm_insn(DisasContext *s) gen_op_swi(); s->is_jmp = DISAS_JUMP; break; + case 0xc: + case 0xd: + rd = (insn >> 12) & 0x7; + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + val = (insn) & 0xff; + if (!(insn & (1 << 23))) + val = -val; + switch((insn >> 8) & 0xf) { + case 0x1: + /* load/store */ + if ((insn & (1 << 24))) + gen_op_addl_T1_im(val); + /* XXX: do it */ + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + break; + case 0x2: + { + int n, i; + /* load store multiple */ + if ((insn & (1 << 24))) + gen_op_addl_T1_im(val); + switch(insn & 0x00408000) { + case 0x00008000: n = 1; break; + case 0x00400000: n = 2; break; + case 0x00408000: n = 3; break; + default: n = 4; break; + } + for(i = 0;i < n; i++) { + /* XXX: do it */ + } + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + } + break; + default: + goto illegal_op; + } + break; + case 0x0e: + /* float ops */ + /* XXX: do it */ + switch((insn >> 20) & 0xf) { + case 0x2: /* wfs */ + break; + case 0x3: /* rfs */ + break; + case 0x4: /* wfc */ + break; + case 0x5: /* rfc */ + break; + default: + goto illegal_op; + } + break; default: illegal_op: gen_op_movl_T0_im((long)s->pc - 4); @@ -688,15 +819,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc disas_arm_insn(dc); } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - /* we must store the eflags state if it is not already done */ - if (dc->is_jmp != DISAS_TB_JUMP && - dc->is_jmp != DISAS_JUMP) { - gen_op_movl_T0_im((long)dc->pc - 4); - gen_op_movl_reg_TN[0][15](); - } - if (dc->is_jmp != DISAS_TB_JUMP) { + switch(dc->is_jmp) { + case DISAS_JUMP_NEXT: + case DISAS_NEXT: + gen_op_jmp((long)dc->tb, (long)dc->pc); + break; + default: + case DISAS_JUMP: /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; } *gen_opc_ptr = INDEX_op_end; @@ -756,5 +891,10 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) else fprintf(f, " "); } - fprintf(f, "CPSR=%08x", env->cpsr); + fprintf(f, "PSR=%08x %c%c%c%c\n", + env->cpsr, + env->cpsr & (1 << 31) ? 'N' : '-', + env->cpsr & (1 << 30) ? 'Z' : '-', + env->cpsr & (1 << 29) ? 'C' : '-', + env->cpsr & (1 << 28) ? 'V' : '-'); }