qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [patch] Arm arch5 support
@ 2004-08-01 17:08 Paul Brook
  2004-08-01 17:41 ` Lennert Buytenhek
  0 siblings, 1 reply; 7+ messages in thread
From: Paul Brook @ 2004-08-01 17:08 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 194 bytes --]

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

[-- Attachment #2: patch.qemu_5e --]
[-- Type: text/x-diff, Size: 14168 bytes --]

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2004-08-01 23:18 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-01 17:08 [Qemu-devel] [patch] Arm arch5 support Paul Brook
2004-08-01 17:41 ` Lennert Buytenhek
2004-08-01 18:32   ` Paul Brook
2004-08-01 21:38     ` Lennert Buytenhek
2004-08-01 22:16       ` Lennert Buytenhek
2004-08-01 23:03         ` Paul Brook
2004-08-01 23:14         ` Paul Brook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).