ARM thumb fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1418 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
6a0f9e82c5
commit
5899f386ba
@ -824,12 +824,13 @@ void OPPROTO op_shrl_T0_im_thumb(void)
|
|||||||
|
|
||||||
shift = PARAM1;
|
shift = PARAM1;
|
||||||
if (shift == 0) {
|
if (shift == 0) {
|
||||||
env->CF = 0;
|
env->CF = ((uint32_t)shift) >> 31;
|
||||||
T0 = 0;
|
T0 = 0;
|
||||||
} else {
|
} else {
|
||||||
env->CF = (T0 >> (shift - 1)) & 1;
|
env->CF = (T0 >> (shift - 1)) & 1;
|
||||||
T0 = T0 >> shift;
|
T0 = T0 >> shift;
|
||||||
}
|
}
|
||||||
|
env->NZF = T0;
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ typedef struct DisasContext {
|
|||||||
int condlabel;
|
int condlabel;
|
||||||
struct TranslationBlock *tb;
|
struct TranslationBlock *tb;
|
||||||
int singlestep_enabled;
|
int singlestep_enabled;
|
||||||
|
int thumb;
|
||||||
} DisasContext;
|
} DisasContext;
|
||||||
|
|
||||||
#define DISAS_JUMP_NEXT 4
|
#define DISAS_JUMP_NEXT 4
|
||||||
@ -268,7 +269,10 @@ static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
|
|||||||
int val;
|
int val;
|
||||||
|
|
||||||
if (reg == 15) {
|
if (reg == 15) {
|
||||||
/* normaly, since we updated PC, we need only to add 4 */
|
/* normaly, since we updated PC, we need only to add one insn */
|
||||||
|
if (s->thumb)
|
||||||
|
val = (long)s->pc + 2;
|
||||||
|
else
|
||||||
val = (long)s->pc + 4;
|
val = (long)s->pc + 4;
|
||||||
gen_op_movl_TN_im[t](val);
|
gen_op_movl_TN_im[t](val);
|
||||||
} else {
|
} else {
|
||||||
@ -897,6 +901,8 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
|
|||||||
{
|
{
|
||||||
if (__builtin_expect(s->singlestep_enabled, 0)) {
|
if (__builtin_expect(s->singlestep_enabled, 0)) {
|
||||||
/* An indirect jump so that we still trigger the debug exception. */
|
/* An indirect jump so that we still trigger the debug exception. */
|
||||||
|
if (s->thumb)
|
||||||
|
dest |= 1;
|
||||||
gen_op_movl_T0_im(dest);
|
gen_op_movl_T0_im(dest);
|
||||||
gen_bx(s);
|
gen_bx(s);
|
||||||
} else {
|
} else {
|
||||||
@ -1552,7 +1558,7 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_movl_T1_reg(s, rm);
|
gen_movl_T1_reg(s, rm);
|
||||||
}
|
}
|
||||||
if (insn & (1 << 9))
|
if (insn & (1 << 9))
|
||||||
gen_op_addl_T0_T1_cc();
|
gen_op_subl_T0_T1_cc();
|
||||||
else
|
else
|
||||||
gen_op_addl_T0_T1_cc();
|
gen_op_addl_T0_T1_cc();
|
||||||
gen_movl_reg_T0(s, rd);
|
gen_movl_reg_T0(s, rd);
|
||||||
@ -1595,11 +1601,10 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
case 4:
|
case 4:
|
||||||
if (insn & (1 << 11)) {
|
if (insn & (1 << 11)) {
|
||||||
rd = (insn >> 8) & 7;
|
rd = (insn >> 8) & 7;
|
||||||
/* load pc-relative */
|
/* load pc-relative. Bit 1 of PC is ignored. */
|
||||||
val = (insn & 0xff) * 4;
|
val = s->pc + 2 + ((insn & 0xff) * 4);
|
||||||
|
val &= ~(uint32_t)2;
|
||||||
gen_op_movl_T1_im(val);
|
gen_op_movl_T1_im(val);
|
||||||
gen_movl_T2_reg(s, 15);
|
|
||||||
gen_op_addl_T1_T2();
|
|
||||||
gen_op_ldl_T0_T1();
|
gen_op_ldl_T0_T1();
|
||||||
gen_movl_reg_T0(s, rd);
|
gen_movl_reg_T0(s, rd);
|
||||||
break;
|
break;
|
||||||
@ -1658,7 +1663,7 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_movl_T0_reg(s, rd);
|
gen_movl_T0_reg(s, rd);
|
||||||
|
|
||||||
gen_movl_T1_reg(s, rm);
|
gen_movl_T1_reg(s, rm);
|
||||||
switch (insn >> 6) {
|
switch (op) {
|
||||||
case 0x0: /* and */
|
case 0x0: /* and */
|
||||||
gen_op_andl_T0_T1();
|
gen_op_andl_T0_T1();
|
||||||
gen_op_logic_T0_cc();
|
gen_op_logic_T0_cc();
|
||||||
@ -1689,8 +1694,9 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_op_andl_T0_T1();
|
gen_op_andl_T0_T1();
|
||||||
gen_op_logic_T0_cc();
|
gen_op_logic_T0_cc();
|
||||||
rd = 16;
|
rd = 16;
|
||||||
|
break;
|
||||||
case 0x9: /* neg */
|
case 0x9: /* neg */
|
||||||
gen_op_rsbl_T0_T1_cc();
|
gen_op_subl_T0_T1_cc();
|
||||||
break;
|
break;
|
||||||
case 0xa: /* cmp */
|
case 0xa: /* cmp */
|
||||||
gen_op_subl_T0_T1_cc();
|
gen_op_subl_T0_T1_cc();
|
||||||
@ -1716,11 +1722,12 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_op_notl_T1();
|
gen_op_notl_T1();
|
||||||
gen_op_logic_T1_cc();
|
gen_op_logic_T1_cc();
|
||||||
val = 1;
|
val = 1;
|
||||||
|
rm = rd;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rd != 16) {
|
if (rd != 16) {
|
||||||
if (val)
|
if (val)
|
||||||
gen_movl_reg_T1(s, rd);
|
gen_movl_reg_T1(s, rm);
|
||||||
else
|
else
|
||||||
gen_movl_reg_T0(s, rd);
|
gen_movl_reg_T0(s, rd);
|
||||||
}
|
}
|
||||||
@ -1756,7 +1763,7 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_op_ldl_T0_T1();
|
gen_op_ldl_T0_T1();
|
||||||
break;
|
break;
|
||||||
case 5: /* ldrh */
|
case 5: /* ldrh */
|
||||||
gen_op_ldsw_T0_T1();
|
gen_op_lduw_T0_T1();
|
||||||
break;
|
break;
|
||||||
case 6: /* ldrb */
|
case 6: /* ldrb */
|
||||||
gen_op_ldub_T0_T1();
|
gen_op_ldub_T0_T1();
|
||||||
@ -1851,11 +1858,13 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
case 10:
|
case 10:
|
||||||
/* add to high reg */
|
/* add to high reg */
|
||||||
rd = (insn >> 8) & 7;
|
rd = (insn >> 8) & 7;
|
||||||
if (insn & (1 << 11))
|
if (insn & (1 << 11)) {
|
||||||
rm = 13; /* sp */
|
/* SP */
|
||||||
else
|
gen_movl_T0_reg(s, 13);
|
||||||
rm = 15; /* pc */
|
} else {
|
||||||
gen_movl_T0_reg(s, rm);
|
/* PC. bit 1 is ignored. */
|
||||||
|
gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
|
||||||
|
}
|
||||||
val = (insn & 0xff) * 4;
|
val = (insn & 0xff) * 4;
|
||||||
gen_op_movl_T1_im(val);
|
gen_op_movl_T1_im(val);
|
||||||
gen_op_addl_T0_T1();
|
gen_op_addl_T0_T1();
|
||||||
@ -1880,11 +1889,19 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
case 4: case 5: case 0xc: case 0xd:
|
case 4: case 5: case 0xc: case 0xd:
|
||||||
/* push/pop */
|
/* push/pop */
|
||||||
gen_movl_T1_reg(s, 13);
|
gen_movl_T1_reg(s, 13);
|
||||||
if (insn & (1 << 11))
|
if (insn & (1 << 8))
|
||||||
val = 4;
|
offset = 4;
|
||||||
else
|
else
|
||||||
val = -4;
|
offset = 0;
|
||||||
gen_op_movl_T2_im(val);
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (insn & (1 << i))
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
if ((insn & (1 << 11)) == 0) {
|
||||||
|
gen_op_movl_T2_im(-offset);
|
||||||
|
gen_op_addl_T1_T2();
|
||||||
|
}
|
||||||
|
gen_op_movl_T2_im(4);
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
if (insn & (1 << i)) {
|
if (insn & (1 << i)) {
|
||||||
if (insn & (1 << 11)) {
|
if (insn & (1 << 11)) {
|
||||||
@ -1896,7 +1913,7 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_movl_T0_reg(s, i);
|
gen_movl_T0_reg(s, i);
|
||||||
gen_op_stl_T0_T1();
|
gen_op_stl_T0_T1();
|
||||||
}
|
}
|
||||||
/* move to the next address */
|
/* advance to the next address. */
|
||||||
gen_op_addl_T1_T2();
|
gen_op_addl_T1_T2();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1913,7 +1930,10 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
}
|
}
|
||||||
gen_op_addl_T1_T2();
|
gen_op_addl_T1_T2();
|
||||||
}
|
}
|
||||||
|
if ((insn & (1 << 11)) == 0) {
|
||||||
|
gen_op_movl_T2_im(-offset);
|
||||||
|
gen_op_addl_T1_T2();
|
||||||
|
}
|
||||||
/* write back the new stack pointer */
|
/* write back the new stack pointer */
|
||||||
gen_movl_reg_T1(s, 13);
|
gen_movl_reg_T1(s, 13);
|
||||||
/* set the new PC value */
|
/* set the new PC value */
|
||||||
@ -1931,14 +1951,8 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
rn = (insn >> 8) & 0x7;
|
rn = (insn >> 8) & 0x7;
|
||||||
gen_movl_T1_reg(s, rn);
|
gen_movl_T1_reg(s, rn);
|
||||||
gen_op_movl_T2_im(4);
|
gen_op_movl_T2_im(4);
|
||||||
val = 0;
|
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
if (insn & (1 << i)) {
|
if (insn & (1 << i)) {
|
||||||
/* advance to the next address */
|
|
||||||
if (val)
|
|
||||||
gen_op_addl_T1_T2();
|
|
||||||
else
|
|
||||||
val = 1;
|
|
||||||
if (insn & (1 << 11)) {
|
if (insn & (1 << 11)) {
|
||||||
/* load */
|
/* load */
|
||||||
gen_op_ldl_T0_T1();
|
gen_op_ldl_T0_T1();
|
||||||
@ -1948,8 +1962,12 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_movl_T0_reg(s, i);
|
gen_movl_T0_reg(s, i);
|
||||||
gen_op_stl_T0_T1();
|
gen_op_stl_T0_T1();
|
||||||
}
|
}
|
||||||
|
/* advance to the next address */
|
||||||
|
gen_op_addl_T1_T2();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Base register writeback. */
|
||||||
|
gen_movl_reg_T1(s, rn);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 13:
|
case 13:
|
||||||
@ -1976,9 +1994,9 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_movl_T1_reg(s, 15);
|
gen_movl_T1_reg(s, 15);
|
||||||
|
|
||||||
/* jump to the offset */
|
/* jump to the offset */
|
||||||
val = (uint32_t)s->pc;
|
val = (uint32_t)s->pc + 2;
|
||||||
offset = ((int32_t)insn << 24) >> 24;
|
offset = ((int32_t)insn << 24) >> 24;
|
||||||
val += (offset << 1) + 2;
|
val += offset << 1;
|
||||||
gen_jmp(s, val);
|
gen_jmp(s, val);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2002,19 +2020,20 @@ static void disas_thumb_insn(DisasContext *s)
|
|||||||
gen_op_movl_T1_im(val | 1);
|
gen_op_movl_T1_im(val | 1);
|
||||||
gen_movl_reg_T1(s, 14);
|
gen_movl_reg_T1(s, 14);
|
||||||
|
|
||||||
val += offset;
|
val += offset << 1;
|
||||||
if (insn & (1 << 11)) {
|
if (insn & (1 << 11)) {
|
||||||
/* bl */
|
/* bl */
|
||||||
gen_jmp(s, val);
|
gen_jmp(s, val);
|
||||||
} else {
|
} else {
|
||||||
/* blx */
|
/* blx */
|
||||||
|
val &= ~(uint32_t)2;
|
||||||
gen_op_movl_T0_im(val);
|
gen_op_movl_T0_im(val);
|
||||||
gen_bx(s);
|
gen_bx(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
undef:
|
undef:
|
||||||
gen_op_movl_T0_im((long)s->pc - 4);
|
gen_op_movl_T0_im((long)s->pc - 2);
|
||||||
gen_op_movl_reg_TN[0][15]();
|
gen_op_movl_reg_TN[0][15]();
|
||||||
gen_op_undef_insn();
|
gen_op_undef_insn();
|
||||||
s->is_jmp = DISAS_JUMP;
|
s->is_jmp = DISAS_JUMP;
|
||||||
@ -2045,6 +2064,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
dc->pc = pc_start;
|
dc->pc = pc_start;
|
||||||
dc->singlestep_enabled = env->singlestep_enabled;
|
dc->singlestep_enabled = env->singlestep_enabled;
|
||||||
dc->condjmp = 0;
|
dc->condjmp = 0;
|
||||||
|
dc->thumb = env->thumb;
|
||||||
nb_gen_labels = 0;
|
nb_gen_labels = 0;
|
||||||
lj = -1;
|
lj = -1;
|
||||||
do {
|
do {
|
||||||
@ -2128,7 +2148,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
|||||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||||
fprintf(logfile, "----------------\n");
|
fprintf(logfile, "----------------\n");
|
||||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||||
target_disas(logfile, pc_start, dc->pc - pc_start, 0);
|
target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
|
||||||
fprintf(logfile, "\n");
|
fprintf(logfile, "\n");
|
||||||
if (loglevel & (CPU_LOG_TB_OP)) {
|
if (loglevel & (CPU_LOG_TB_OP)) {
|
||||||
fprintf(logfile, "OP:\n");
|
fprintf(logfile, "OP:\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user