Index: cpu-exec.c =================================================================== RCS file: /cvsroot/qemu/qemu/cpu-exec.c,v retrieving revision 1.38 diff -u -p -r1.38 cpu-exec.c --- cpu-exec.c 14 Jul 2004 17:20:55 -0000 1.38 +++ cpu-exec.c 1 Aug 2004 16:44:33 -0000 @@ -166,7 +166,8 @@ int cpu_exec(CPUState *env1) env->CF = (psr >> 29) & 1; env->NZF = (psr & 0xc0000000) ^ 0x40000000; env->VF = (psr << 3) & 0x80000000; - env->cpsr = psr & ~0xf0000000; + env->QF = (psr >> 27) & 1; + env->cpsr = psr & ~0xf8000000; } #elif defined(TARGET_SPARC) #elif defined(TARGET_PPC) @@ -296,7 +297,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_ARM) env->cpsr = compute_cpsr(); cpu_arm_dump_state(env, logfile, 0); - env->cpsr &= ~0xf0000000; + env->cpsr &= ~0xf8000000; #elif defined(TARGET_SPARC) cpu_sparc_dump_state (env, logfile, 0); #elif defined(TARGET_PPC) Index: target-arm/cpu.h =================================================================== RCS file: /cvsroot/qemu/qemu/target-arm/cpu.h,v retrieving revision 1.3 diff -u -p -r1.3 cpu.h --- target-arm/cpu.h 25 Apr 2004 17:53:35 -0000 1.3 +++ target-arm/cpu.h 1 Aug 2004 16:44:33 -0000 @@ -35,6 +35,7 @@ typedef struct CPUARMState { uint32_t CF; /* 0 or 1 */ uint32_t VF; /* V is the bit 31. All other bits are undefined */ uint32_t NZF; /* N is bit 31. Z is computed from NZF */ + uint32_t QF; /* 0 or 1 */ /* exception/interrupt handling */ jmp_buf jmp_env; Index: target-arm/exec.h =================================================================== RCS file: /cvsroot/qemu/qemu/target-arm/exec.h,v retrieving revision 1.1 diff -u -p -r1.1 exec.h --- target-arm/exec.h 30 Sep 2003 20:34:21 -0000 1.1 +++ target-arm/exec.h 1 Aug 2004 16:44:33 -0000 @@ -36,5 +36,5 @@ 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); + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27); } Index: target-arm/op.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-arm/op.c,v retrieving revision 1.3 diff -u -p -r1.3 op.c --- target-arm/op.c 30 Nov 2003 19:40:08 -0000 1.3 +++ target-arm/op.c 1 Aug 2004 16:44:33 -0000 @@ -382,6 +382,14 @@ void OPPROTO op_imull_T0_T1(void) T0 = res; } +/* 48 bit signed mul, top 32 bits */ +void OPPROTO op_imulw_T0_T1(void) +{ + uint64_t res; + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); + T0 = res >> 16; +} + void OPPROTO op_addq_T0_T1(void) { uint64_t res; @@ -391,6 +399,15 @@ void OPPROTO op_addq_T0_T1(void) T0 = res; } +void OPPROTO op_addq_lo_T0_T1(void) +{ + uint64_t res; + res = ((uint64_t)T1 << 32) | T0; + res += (uint64_t)(env->regs[PARAM1]); + T1 = res >> 32; + T0 = res; +} + void OPPROTO op_logicq_cc(void) { env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); @@ -643,6 +660,82 @@ void OPPROTO op_rorl_T1_T0_cc(void) FORCE_RET(); } +/* misc */ +void OPPROTO op_clz_T0(void) +{ + int count; + for (count = 32; T0 > 0; count--) + T0 = T0 >> 1; + T0 = count; + FORCE_RET(); +} + +void OPPROTO op_sarl_T0_im(void) +{ + T1 = (int32_t)T1 >> PARAM1; +} + +/* Sign extend */ +void OPPROTO op_sxl_T0(void) +{ + T0 = (int16_t)T0; +} + +void OPPROTO op_sxl_T1(void) +{ + T1 = (int16_t)T1; +} + +#define SIGNBIT 0x80000000 +/* saturating arithmetic */ +void OPPROTO op_addl_T0_T1_setq(void) +{ + uint32_t res; + + res = T0 + T1; + if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) + env->QF = 1; + + T0 = res; + FORCE_RET(); +} + +void OPPROTO op_addl_T0_T1_saturate(void) +{ + uint32_t res; + + res = T0 + T1; + if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) { + env->QF = 1; + if (T0 & SIGNBIT) + T0 = 0x80000000; + else + T0 = 0x7fffffff; + } + else + T0 = res; + + FORCE_RET(); +} + +void OPPROTO op_subl_T0_T1_saturate(void) +{ + uint32_t res; + + res = T0 - T1; + if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) { + env->QF = 1; + if (T0 & SIGNBIT) + T0 = 0x8000000; + else + T0 = 0x7fffffff; + } + else + T0 = res; + + FORCE_RET(); +} + /* exceptions */ void OPPROTO op_swi(void) Index: target-arm/translate.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-arm/translate.c,v retrieving revision 1.10 diff -u -p -r1.10 translate.c --- target-arm/translate.c 22 Jun 2004 10:55:49 -0000 1.10 +++ target-arm/translate.c 1 Aug 2004 16:44:33 -0000 @@ -326,17 +326,136 @@ static void disas_arm_insn(DisasContext s->pc += 4; cond = insn >> 28; - if (cond == 0xf) + if (cond == 0xf){ + if ((insn & 0x0fd70f00) == 0x0550f000) + return; /* PLD */ goto illegal_op; + } if (cond != 0xe) { /* 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 = DISAS_JUMP_NEXT; } - if (((insn & 0x0e000000) == 0 && - (insn & 0x00000090) != 0x90) || - ((insn & 0x0e000000) == (1 << 25))) { + if ((insn & 0x0d900000) == 0x01000000) { + /* Miscellaneous instructions */ + if (insn & (1 << 25)) { + if ((insn & 0x0ff0f000) != 0x0360f000) + goto illegal_op; + /* CPSR = immediate */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + gen_op_movl_T0_im(val); + if (insn & (1 << 19)) + gen_op_movl_psr_T0(); + } else { + /* miscellaneous instructions */ + op1 = (insn >> 21) & 3; + sh = (insn >> 4) & 0xf; + rm = insn & 0xf; + switch (sh) { + case 0x0: /* move program status register */ + if (op1 & 2) { + /* SPSR not accessible in user mode */ + goto illegal_op; + } + if (op1 & 1) { + /* CPSR = reg */ + gen_movl_T0_reg(s, rm); + if (insn & (1 << 19)) + gen_op_movl_psr_T0(); + } else { + /* reg = CPSR */ + rd = (insn >> 12) & 0xf; + gen_op_movl_T0_psr(); + gen_movl_reg_T0(s, rd); + } + case 0x1: + if (op1 == 3) { + /* clz */ + rd = (insn >> 12) & 0xf; + gen_movl_T0_reg(s, rm); + gen_op_clz_T0(); + gen_movl_reg_T0(s, rd); + } else { + goto illegal_op; + } + break; + case 0x5: /* saturating add/subtract */ + rd = (insn >> 12) & 0xf; + rn = (insn >> 16) & 0xf; + gen_movl_T0_reg (s, rn); + if (op1 & 2) { + gen_movl_T1_reg (s, rn); + if (op1 & 1) + gen_op_subl_T0_T1_saturate(); + else + gen_op_addl_T0_T1_saturate(); + } + gen_movl_T1_reg (s, rm); + if (op1 & 1) + gen_op_subl_T0_T1_saturate(); + else + gen_op_addl_T0_T1_saturate(); + gen_movl_reg_T0(s, rn); + break; + case 0x8: /* signed multiply */ + case 0xa: + case 0xc: + case 0xe: + rs = (insn >> 8) & 0xf; + rn = (insn >> 12) & 0xf; + rd = (insn >> 16) & 0xf; + if (op1 == 1) { + /* (32 * 16) >> 16 */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rs); + if (sh & 4) + gen_op_sarl_T1_im(16); + else + gen_op_sxl_T1(); + gen_op_imulw_T0_T1(); + if ((sh & 2) == 0) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } else { + /* 16 * 16 */ + gen_movl_T0_reg(s, rm); + if (sh & 2) + gen_op_sarl_T0_im(16); + else + gen_op_sxl_T0(); + gen_movl_T0_reg(s, rs); + if (sh & 4) + gen_op_sarl_T1_im(16); + else + gen_op_sxl_T1(); + if (op1 == 2) { + gen_op_imull_T0_T1(); + gen_op_addq_T0_T1(rn, rd); + gen_movl_reg_T0(s, rn); + gen_movl_reg_T1(s, rd); + } else { + gen_op_mul_T0_T1(); + if (op1 == 0) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } + } + break; + default: + goto illegal_op; + } + } + } else if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { int set_cc, logic_cc, shiftop; op1 = (insn >> 21) & 0xf; @@ -489,6 +608,7 @@ static void disas_arm_insn(DisasContext switch(op1) { case 0x0: case 0x1: + /* multiplies, extra load/stores */ sh = (insn >> 5) & 3; if (sh == 0) { if (op1 == 0x0) { @@ -496,7 +616,7 @@ static void disas_arm_insn(DisasContext rn = (insn >> 12) & 0xf; rs = (insn >> 8) & 0xf; rm = (insn) & 0xf; - if (!(insn & (1 << 23))) { + if (((insn >> 22) & 3) == 0) { /* 32 bit mul */ gen_movl_T0_reg(s, rs); gen_movl_T1_reg(s, rm); @@ -516,30 +636,39 @@ static void disas_arm_insn(DisasContext gen_op_imull_T0_T1(); else gen_op_mull_T0_T1(); - if (insn & (1 << 21)) + if (insn & (1 << 21)) /* mult accumulate */ gen_op_addq_T0_T1(rn, rd); + if (!(insn & (1 << 23))) { /* double accumulate */ + gen_op_addq_lo_T0_T1(rn); + gen_op_addq_lo_T0_T1(rd); + } if (insn & (1 << 20)) gen_op_logicq_cc(); gen_movl_reg_T0(s, rn); gen_movl_reg_T1(s, rd); } } else { - /* SWP instruction */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; - rm = (insn) & 0xf; - - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); - if (insn & (1 << 22)) { - gen_op_swpb_T0_T1(); + if (insn & (1 << 23)) { + /* load/store exclusive */ + goto illegal_op; } else { - gen_op_swpl_T0_T1(); + /* SWP instruction */ + rm = (insn) & 0xf; + + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (insn & (1 << 22)) { + gen_op_swpb_T0_T1(); + } else { + gen_op_swpl_T0_T1(); + } + gen_movl_reg_T0(s, rd); } - gen_movl_reg_T0(s, rd); } } else { - /* load/store half word */ + /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; gen_movl_T1_reg(s, rn); @@ -560,6 +689,27 @@ static void disas_arm_insn(DisasContext break; } gen_movl_reg_T0(s, rd); + } else if (sh & 2) { + /* doubleword */ + if (sh & 1) { + /* store */ + gen_movl_T0_reg(s, rd); + gen_op_stl_T0_T1(); + gen_op_addl_T1_im(4); + gen_movl_T0_reg(s, rd + 1); + gen_op_stl_T0_T1(); + if ((insn & (1 << 24)) || (insn & (1 << 20))) + gen_op_addl_T1_im(-4); + } else { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + gen_op_addl_T1_im(4); + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd + 1); + if ((insn & (1 << 24)) || (insn & (1 << 20))) + gen_op_addl_T1_im(-4); + } } else { /* store */ gen_movl_T0_reg(s, rd);