ARM fixes

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@314 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-07-09 17:10:32 +00:00
parent f2674e31e0
commit 6e295807ac
4 changed files with 209 additions and 58 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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' : '-');
}