From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1BrJsM-0004fb-GF for qemu-devel@nongnu.org; Sun, 01 Aug 2004 13:11:58 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1BrJsL-0004f4-CK for qemu-devel@nongnu.org; Sun, 01 Aug 2004 13:11:58 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1BrJsL-0004eu-AS for qemu-devel@nongnu.org; Sun, 01 Aug 2004 13:11:57 -0400 Received: from [62.241.160.9] (helo=shockwave.systems.pipex.net) by monty-python.gnu.org with esmtp (Exim 4.34) id 1BrJop-0007uS-PU for qemu-devel@nongnu.org; Sun, 01 Aug 2004 13:08:20 -0400 Received: from nowt.org (81-178-252-250.dsl.pipex.com [81.178.252.250]) by shockwave.systems.pipex.net (Postfix) with ESMTP id CF8091C0019D for ; Sun, 1 Aug 2004 18:08:18 +0100 (BST) Received: from wren.home (wren.home [192.168.1.7]) by nowt.org (Postfix) with ESMTP id 9FFB4AC92 for ; Sun, 1 Aug 2004 18:08:17 +0100 (BST) From: Paul Brook Date: Sun, 1 Aug 2004 18:08:17 +0100 MIME-Version: 1.0 Content-Disposition: inline Content-Type: Multipart/Mixed; boundary="Boundary-00=_BOSDBX6ZoVUWRUN" Message-Id: <200408011808.17492.paul@codesourcery.com> Subject: [Qemu-devel] [patch] Arm arch5 support Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --Boundary-00=_BOSDBX6ZoVUWRUN Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline The attached patch adds qemu target support for the new arm instructions present in the armv5e instruction set. I'm probably going to look at adding thumb support next, time permitting. Paul --Boundary-00=_BOSDBX6ZoVUWRUN Content-Type: text/x-diff; charset="us-ascii"; name="patch.qemu_5e" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="patch.qemu_5e" 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); --Boundary-00=_BOSDBX6ZoVUWRUN--