Fix bugs in the simulation of the AArch64's ADDP, FADDP, LD1, CCMP and CCMP instructions.
authorNick Clifton <nickc@redhat.com>
Thu, 3 Mar 2016 15:14:35 +0000 (15:14 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 3 Mar 2016 15:22:53 +0000 (15:22 +0000)
* simulator.c (set_flags_for_sub32): Correct type of signbit.
(CondCompare): Swap interpretation of bit 30.
(DO_ADDP): Delete macro.
(do_vec_ADDP): Copy source registers before starting to update
destination register.
(do_vec_FADDP): Likewise.
(do_vec_load_store): Fix computation of sizeof_operation.
(rbit64): Fix type of constant.
(aarch64_step): When displaying insn value, display all 32 bits.

sim/aarch64/ChangeLog
sim/aarch64/simulator.c

index 115b528bc7285b7e754406690f22e4108901999e..6d8459d6393baf8fd29e23d7e2539cdd8806448c 100644 (file)
@@ -1,3 +1,15 @@
+2016-03-03  Nick Clifton  <nickc@redhat.com>
+
+       * simulator.c (set_flags_for_sub32): Correct type of signbit.
+       (CondCompare): Swap interpretation of bit 30.
+       (DO_ADDP): Delete macro.
+       (do_vec_ADDP): Copy source registers before starting to update
+       destination register.
+       (do_vec_FADDP): Likewise.
+       (do_vec_load_store): Fix computation of sizeof_operation.
+       (rbit64): Fix type of constant.
+       (aarch64_step): When displaying insn value, display all 32 bits.
+
 2016-01-10  Mike Frysinger  <vapier@gentoo.org>
 
        * config.in, configure: Regenerate.
index 224a04d748000086580a29082d901d11b7b5c9d8..f5486f400f67137ecd47ca3a04e9dc4d4fce9cf3 100644 (file)
@@ -1625,7 +1625,7 @@ set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
 {
   uint32_t result = value1 - value2;
   uint32_t flags = 0;
-  uint32_t signbit = 1ULL << 31;
+  uint32_t signbit = 1U << 31;
 
   if (result == 0)
     flags |= Z;
@@ -2454,7 +2454,7 @@ static void
 CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn  */
 {
   /* instr[31]    = size : 0 ==> 32 bit, 1 ==> 64 bit
-     instr[30]    = compare with positive (0) or negative value (1)
+     instr[30]    = compare with positive (1) or negative value (0)
      instr[29,21] = 1 1101 0010
      instr[20,16] = Rm or const
      instr[15,12] = cond
@@ -2477,7 +2477,7 @@ CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn  */
       return;
     }
 
-  negate = uimm (aarch64_get_instr (cpu), 30, 30) ? -1 : 1;
+  negate = uimm (aarch64_get_instr (cpu), 30, 30) ? 1 : -1;
   rm = uimm (aarch64_get_instr (cpu), 20, 16);
   rn = uimm (aarch64_get_instr (cpu),  9,  5);
 
@@ -5089,21 +5089,6 @@ do_vec_sub_long (sim_cpu *cpu)
     }
 }
 
-#define DO_ADDP(FN)                                                    \
-  do                                                                   \
-    {                                                                  \
-      for (i = 0; i < range; i++)                                      \
-       {                                                               \
-         aarch64_set_vec_##FN (cpu, vd, i,                             \
-                               aarch64_get_vec_##FN (cpu, vn, i * 2)   \
-                               + aarch64_get_vec_##FN (cpu, vn, i * 2 + 1)); \
-         aarch64_set_vec_##FN (cpu, vd, i + range,                     \
-                               aarch64_get_vec_##FN (cpu, vm, i * 2)   \
-                               + aarch64_get_vec_##FN (cpu, vm, i * 2 + 1)); \
-       }                                                               \
-      }                                                                        \
-    while (0)
-
 static void
 do_vec_ADDP (sim_cpu *cpu)
 {
@@ -5117,6 +5102,8 @@ do_vec_ADDP (sim_cpu *cpu)
      instr[9,5]   = Vn
      instr[4,0]   = V dest.  */
 
+  FRegister copy_vn;
+  FRegister copy_vm;
   unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
   unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
   unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
@@ -5128,28 +5115,50 @@ do_vec_ADDP (sim_cpu *cpu)
   NYI_assert (21, 21, 1);
   NYI_assert (15, 10, 0x2F);
 
+  /* Make copies of the source registers in case vd == vn/vm.  */
+  copy_vn = cpu->fr[vn];
+  copy_vm = cpu->fr[vm];
+
   switch (size)
     {
     case 0:
       range = full ? 8 : 4;
-      DO_ADDP (u8);
+      for (i = 0; i < range; i++)
+       {
+         aarch64_set_vec_u8 (cpu, vd, i,
+                             copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
+         aarch64_set_vec_u8 (cpu, vd, i + range,
+                             copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
+       }
       return;
 
     case 1:
       range = full ? 4 : 2;
-      DO_ADDP (u16);
+      for (i = 0; i < range; i++)
+       {
+         aarch64_set_vec_u16 (cpu, vd, i,
+                              copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
+         aarch64_set_vec_u16 (cpu, vd, i + range,
+                              copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
+       }
       return;
 
     case 2:
       range = full ? 2 : 1;
-      DO_ADDP (u32);
+      for (i = 0; i < range; i++)
+       {
+         aarch64_set_vec_u32 (cpu, vd, i,
+                              copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
+         aarch64_set_vec_u32 (cpu, vd, i + range,
+                              copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
+       }
       return;
 
     case 3:
       if (! full)
        HALT_UNALLOC;
-      range = 1;
-      DO_ADDP (u64);
+      aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
+      aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
       return;
 
     default:
@@ -6054,28 +6063,43 @@ do_vec_FADDP (sim_cpu *cpu)
 
   if (uimm (aarch64_get_instr (cpu), 22, 22))
     {
+      /* Extract values before adding them incase vd == vn/vm.  */
+      double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
+      double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
+      double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
+      double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
+
       if (! full)
        HALT_UNALLOC;
 
-      aarch64_set_vec_double (cpu, vd, 0, aarch64_get_vec_double (cpu, vn, 0)
-                             + aarch64_get_vec_double (cpu, vn, 1));
-      aarch64_set_vec_double (cpu, vd, 1, aarch64_get_vec_double (cpu, vm, 0)
-                             + aarch64_get_vec_double (cpu, vm, 1));
+      aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
+      aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
     }
   else
     {
-      aarch64_set_vec_float (cpu, vd, 0, aarch64_get_vec_float (cpu, vn, 0)
-                            + aarch64_get_vec_float (cpu, vn, 1));
-      if (full)
-       aarch64_set_vec_float (cpu, vd, 1, aarch64_get_vec_float (cpu, vn, 2)
-                              + aarch64_get_vec_float (cpu, vn, 3));
-      aarch64_set_vec_float (cpu, vd, full ? 2 : 1,
-                            aarch64_get_vec_float (cpu, vm, 0)
-                            + aarch64_get_vec_float (cpu, vm, 1));
+      /* Extract values before adding them incase vd == vn/vm.  */
+      float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
+      float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
+      float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
+      float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
+
       if (full)
-       aarch64_set_vec_float (cpu, vd, 3,
-                              aarch64_get_vec_float (cpu, vm, 2)
-                              + aarch64_get_vec_float (cpu, vm, 3));
+       {
+         float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
+         float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
+         float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
+         float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
+
+         aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
+         aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
+         aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
+         aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
+       }
+      else
+       {
+         aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
+         aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
+       }
     }
 }
 
@@ -10937,11 +10961,24 @@ do_vec_load_store (sim_cpu *cpu)
              sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
              break;
 
-           case 2:
-           case 6:
-           case 10:
            case 7:
-             sizeof_operation = 2 << uimm (aarch64_get_instr (cpu), 11, 10);
+             /* One register, immediate offset variant.  */
+             sizeof_operation = 8;
+             break;
+             
+           case 10:
+             /* Two registers, immediate offset variant.  */
+             sizeof_operation = 16;
+             break;
+
+           case 6:
+             /* Three registers, immediate offset variant.  */
+             sizeof_operation = 24;
+             break;
+
+           case 2:
+             /* Four registers, immediate offset variant.  */
+             sizeof_operation = 32;
              break;
 
            default:
@@ -11421,7 +11458,7 @@ rbit64 (sim_cpu *cpu)
   for (i = 0; i < 64; i++)
     {
       result <<= 1;
-      result |= (value & 1L);
+      result |= (value & 1UL);
       value >>= 1;
     }
   aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
@@ -13019,7 +13056,7 @@ aarch64_step (sim_cpu *cpu)
   aarch64_set_next_PC (cpu, pc + 4);
   aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
 
-  TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %x", pc,
+  TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
              aarch64_get_instr (cpu));
   TRACE_DISASM (cpu, pc);