]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/bfin/bfin-sim.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / bfin / bfin-sim.c
index 25cc6d1774033bb4851e1f2aac3896b0d9a68882..2fa82abdd999fd904fd43be9979e697cbb42d67a 100644 (file)
@@ -1,6 +1,6 @@
 /* Simulator for Analog Devices Blackfin processors.
 
-   Copyright (C) 2005-2012 Free Software Foundation, Inc.
+   Copyright (C) 2005-2013 Free Software Foundation, Inc.
    Contributed by Analog Devices, Inc.
 
    This file is part of simulators.
@@ -51,6 +51,15 @@ illegal_instruction_combination (SIM_CPU *cpu)
     cec_exception (cpu, VEC_ILGAL_I);
 }
 
+static __attribute__ ((noreturn)) void
+illegal_instruction_or_combination (SIM_CPU *cpu)
+{
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+  else
+    illegal_instruction (cpu);
+}
+
 static __attribute__ ((noreturn)) void
 unhandled_instruction (SIM_CPU *cpu, const char *insn)
 {
@@ -1975,7 +1984,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       CYCLE_DELAY = 2;
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -2045,13 +2054,13 @@ decode_PushPopReg_0 (SIM_CPU *cpu, bu16 iw0)
 
   /* Can't push/pop reserved registers  */
   if (reg_is_reserved (grp, reg))
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 
   if (W == 0)
     {
       /* Dreg and Preg are not supported by this instruction.  */
       if (grp == 0 || grp == 1)
-       illegal_instruction (cpu);
+       illegal_instruction_or_combination (cpu);
       TRACE_INSN (cpu, "%s = [SP++];", reg_name);
       /* Can't pop USP while in userspace.  */
       if (PARALLEL_GROUP != BFIN_PARALLEL_NONE
@@ -2104,6 +2113,9 @@ decode_PushPopMultiple_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: d:%i p:%i W:%i dr:%i pr:%i",
                 __func__, d, p, W, dr, pr);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   if ((d == 0 && p == 0) || (p && imm5 (pr) > 5)
       || (d && !p && pr) || (p && !d && dr))
     illegal_instruction (cpu);
@@ -2215,7 +2227,7 @@ decode_CCflag_0 (SIM_CPU *cpu, bu16 iw0)
       bs64 diff = acc0 - acc1;
 
       if (x != 0 || y != 0)
-       illegal_instruction (cpu);
+       illegal_instruction_or_combination (cpu);
 
       if (opc == 5 && I == 0 && G == 0)
        {
@@ -2239,7 +2251,7 @@ decode_CCflag_0 (SIM_CPU *cpu, bu16 iw0)
          SET_CCREG (acc0 <= acc1);
        }
       else
-       illegal_instruction (cpu);
+       illegal_instruction_or_combination (cpu);
 
       SET_ASTATREG (az, diff == 0);
       SET_ASTATREG (an, diff < 0);
@@ -2304,6 +2316,9 @@ decode_CCflag_0 (SIM_CPU *cpu, bu16 iw0)
          TRACE_INSN (cpu, "CC = %c%i %s %c%i%s;", s, x, op, d, y, sign);
        }
 
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+       illegal_instruction_combination (cpu);
+
       SET_CCREG (cc);
       /* Pointer compares only touch CC.  */
       if (!G)
@@ -2350,7 +2365,7 @@ decode_CC2dreg_0 (SIM_CPU *cpu, bu16 iw0)
       SET_CCREG (!CCREG);
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -2373,13 +2388,13 @@ decode_CC2stat_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_INSN (cpu, "%s %s= %s;", D ? astat_names[cbit] : "CC",
              op_names[op], D ? "CC" : astat_names[cbit]);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   /* CC = CC; is invalid.  */
   if (cbit == 5)
     illegal_instruction (cpu);
 
-  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
-    illegal_instruction_combination (cpu);
-
   pval = !!(ASTAT & (1 << cbit));
   if (D == 0)
     switch (op)
@@ -2491,6 +2506,9 @@ decode_REGMV_0 (SIM_CPU *cpu, bu16 iw0)
 
   TRACE_INSN (cpu, "%s = %s;", dstreg_name, srcreg_name);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   /* Reserved slots cannot be a src/dst.  */
   if (reg_is_reserved (gs, src) || reg_is_reserved (gd, dst))
     goto invalid_move;
@@ -2539,6 +2557,9 @@ decode_ALU2op_0 (SIM_CPU *cpu, bu16 iw0)
   PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ALU2op);
   TRACE_EXTRACT (cpu, "%s: opc:%i src:%i dst:%i", __func__, opc, src, dst);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   if (opc == 0)
     {
       TRACE_INSN (cpu, "R%i >>>= R%i;", dst, src);
@@ -2647,6 +2668,9 @@ decode_PTR2op_0 (SIM_CPU *cpu, bu16 iw0)
   PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_PTR2op);
   TRACE_EXTRACT (cpu, "%s: opc:%i src:%i dst:%i", __func__, opc, src, dst);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   if (opc == 0)
     {
       TRACE_INSN (cpu, "%s -= %s", dst_name, src_name);
@@ -2780,6 +2804,9 @@ decode_COMP3op_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: opc:%i dst:%i src1:%i src0:%i",
                 __func__, opc, dst, src1, src0);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   if (opc == 0)
     {
       TRACE_INSN (cpu, "R%i = R%i + R%i;", dst, src0, src1);
@@ -2843,6 +2870,9 @@ decode_COMPI2opD_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: op:%i src:%i dst:%i", __func__, op, src, dst);
   TRACE_DECODE (cpu, "%s: imm7:%#x", __func__, imm);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   if (op == 0)
     {
       TRACE_INSN (cpu, "R%i = %s (X);", dst, imm7_str (imm));
@@ -2872,6 +2902,9 @@ decode_COMPI2opP_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: op:%i src:%i dst:%i", __func__, op, src, dst);
   TRACE_DECODE (cpu, "%s: imm:%#x", __func__, imm);
 
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+    illegal_instruction_combination (cpu);
+
   if (op == 0)
     {
       TRACE_INSN (cpu, "%s = %s;", dst_name, imm7_str (imm));
@@ -2904,6 +2937,9 @@ decode_LDSTpmod_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: W:%i aop:%i reg:%i idx:%i ptr:%i",
                 __func__, W, aop, reg, idx, ptr);
 
+  if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+    illegal_instruction_combination (cpu);
+
   if (aop == 1 && W == 0 && idx == ptr)
     {
       TRACE_INSN (cpu, "R%i.L = W[%s];", reg, ptr_name);
@@ -3000,7 +3036,7 @@ decode_LDSTpmod_0 (SIM_CPU *cpu, bu16 iw0)
        STORE (PREG (ptr), addr + PREG (idx));
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -3018,6 +3054,9 @@ decode_dagMODim_0 (SIM_CPU *cpu, bu16 iw0)
   PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_dagMODim);
   TRACE_EXTRACT (cpu, "%s: br:%i op:%i m:%i i:%i", __func__, br, op, m, i);
 
+  if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+    illegal_instruction_combination (cpu);
+
   if (op == 0 && br == 1)
     {
       TRACE_INSN (cpu, "I%i += M%i (BREV);", i, m);
@@ -3034,7 +3073,7 @@ decode_dagMODim_0 (SIM_CPU *cpu, bu16 iw0)
       dagsub (cpu, i, MREG (m));
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -3050,6 +3089,9 @@ decode_dagMODik_0 (SIM_CPU *cpu, bu16 iw0)
   PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_dagMODik);
   TRACE_EXTRACT (cpu, "%s: op:%i i:%i", __func__, op, i);
 
+  if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+    illegal_instruction_combination (cpu);
+
   if (op == 0)
     {
       TRACE_INSN (cpu, "I%i += 2;", i);
@@ -3071,7 +3113,7 @@ decode_dagMODik_0 (SIM_CPU *cpu, bu16 iw0)
       dagsub (cpu, i, 4);
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -3234,7 +3276,7 @@ decode_dspLDST_0 (SIM_CPU *cpu, bu16 iw0)
       PUT_LONG (addr, DREG (reg));
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -3258,8 +3300,8 @@ decode_LDST_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: sz:%i W:%i aop:%i Z:%i ptr:%i reg:%i",
                 __func__, sz, W, aop, Z, ptr, reg);
 
-  if (aop == 3)
-    illegal_instruction (cpu);
+  if (aop == 3 || PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+    illegal_instruction_or_combination (cpu);
 
   if (W == 0)
     {
@@ -3296,7 +3338,7 @@ decode_LDST_0 (SIM_CPU *cpu, bu16 iw0)
          SET_DREG (reg, (bs32) (bs8) GET_BYTE (PREG (ptr)));
        }
       else
-       illegal_instruction (cpu);
+       illegal_instruction_or_combination (cpu);
     }
   else
     {
@@ -3321,7 +3363,7 @@ decode_LDST_0 (SIM_CPU *cpu, bu16 iw0)
          PUT_BYTE (PREG (ptr), DREG (reg));
        }
       else
-       illegal_instruction (cpu);
+       illegal_instruction_or_combination (cpu);
     }
 
   if (aop == 0)
@@ -3353,6 +3395,9 @@ decode_LDSTiiFP_0 (SIM_CPU *cpu, bu16 iw0)
                 W, offset, grp, reg);
   TRACE_DECODE (cpu, "%s: negimm5s4:%#x", __func__, imm);
 
+  if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+    illegal_instruction_or_combination (cpu);
+
   if (W == 0)
     {
       TRACE_INSN (cpu, "%s = [FP + %s];", reg_name, imm_str);
@@ -3393,6 +3438,9 @@ decode_LDSTii_0 (SIM_CPU *cpu, bu16 iw0)
 
   TRACE_DECODE (cpu, "%s: uimm4s4/uimm4s2:%#x", __func__, imm);
 
+  if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+    illegal_instruction_combination (cpu);
+
   if (W == 1 && op == 2)
     illegal_instruction (cpu);
 
@@ -5158,7 +5206,16 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       if (shft <= 0)
        val = ashiftrt (cpu, val, -shft, 16);
       else
-       val = lshift (cpu, val, shft, 16, sop == 1, 1);
+       {
+         int sgn = (val >> 15) & 0x1;
+
+         val = lshift (cpu, val, shft, 16, sop == 1, 1);
+         if (((val >> 15) & 0x1) != sgn)
+           {
+             SET_ASTATREG (v, 1);
+             SET_ASTATREG (vs, 1);
+           }
+       }
 
       if ((HLs & 2) == 0)
        STORE (DREG (dst0), REG_H_L (DREG (dst0), val));
@@ -5210,42 +5267,40 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
   else if (sop == 0 && sopcde == 3 && (HLs == 0 || HLs == 1))
     {
       bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
-      bu64 val = get_extended_acc (cpu, HLs);
+      bu64 acc = get_extended_acc (cpu, HLs);
+      bu64 val;
 
       HLs = !!HLs;
       TRACE_INSN (cpu, "A%i = ASHIFT A%i BY R%i.L;", HLs, HLs, src0);
-      TRACE_DECODE (cpu, "A%i:%#"PRIx64" shift:%i", HLs, val, shft);
+      TRACE_DECODE (cpu, "A%i:%#"PRIx64" shift:%i", HLs, acc, shft);
 
       if (shft <= 0)
-       val = ashiftrt (cpu, val, -shft, 40);
+       val = ashiftrt (cpu, acc, -shft, 40);
       else
-       val = lshift (cpu, val, shft, 40, 0, 0);
+       val = lshift (cpu, acc, shft, 40, 0, 0);
 
       STORE (AXREG (HLs), (val >> 32) & 0xff);
       STORE (AWREG (HLs), (val & 0xffffffff));
-      STORE (ASTATREG (av[HLs]), val == 0);
-      if (val == 0)
-       STORE (ASTATREG (avs[HLs]), 1);
+      STORE (ASTATREG (av[HLs]), 0);
     }
   else if (sop == 1 && sopcde == 3 && (HLs == 0 || HLs == 1))
     {
       bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
+      bu64 acc = get_unextended_acc (cpu, HLs);
       bu64 val;
 
       HLs = !!HLs;
       TRACE_INSN (cpu, "A%i = LSHIFT A%i BY R%i.L;", HLs, HLs, src0);
-      val = get_unextended_acc (cpu, HLs);
+      TRACE_DECODE (cpu, "A%i:%#"PRIx64" shift:%i", HLs, acc, shft);
 
       if (shft <= 0)
-       val = lshiftrt (cpu, val, -shft, 40);
+       val = lshiftrt (cpu, acc, -shft, 40);
       else
-       val = lshift (cpu, val, shft, 40, 0, 0);
+       val = lshift (cpu, acc, shft, 40, 0, 0);
 
       STORE (AXREG (HLs), (val >> 32) & 0xff);
       STORE (AWREG (HLs), (val & 0xffffffff));
-      STORE (ASTATREG (av[HLs]), val == 0);
-      if (val == 0)
-       STORE (ASTATREG (avs[HLs]), 1);
+      STORE (ASTATREG (av[HLs]), 0);
     }
   else if ((sop == 0 || sop == 1) && sopcde == 1)
     {
@@ -5267,9 +5322,18 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        }
       else
        {
+         int sgn0 = (val0 >> 15) & 0x1;
+         int sgn1 = (val1 >> 15) & 0x1;
+
          val0 = lshift (cpu, val0, shft, 16, sop == 1, 1);
          astat = ASTAT;
          val1 = lshift (cpu, val1, shft, 16, sop == 1, 1);
+
+         if ((sgn0 != ((val0 >> 15) & 0x1)) || (sgn1 != ((val1 >> 15) & 0x1)))
+           {
+             SET_ASTATREG (v, 1);
+             SET_ASTATREG (vs, 1);
+           }
        }
       SET_ASTAT (ASTAT | astat);
       STORE (DREG (dst0), (val1 << 16) | val0);
@@ -5294,7 +5358,16 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
            STORE (DREG (dst0), ashiftrt (cpu, v, -shft, 32));
        }
       else
-       STORE (DREG (dst0), lshift (cpu, v, shft, 32, sop == 1, 1));
+       {
+         bu32 val = lshift (cpu, v, shft, 32, sop == 1, 1);
+
+         STORE (DREG (dst0), val);
+         if (((v >> 31) & 0x1) != ((val >> 31) & 0x1))
+           {
+             SET_ASTATREG (v, 1);
+             SET_ASTATREG (vs, 1);
+           }
+       }
     }
   else if (sop == 3 && sopcde == 2)
     {
@@ -5668,6 +5741,26 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
     illegal_instruction (cpu);
 }
 
+static bu64
+sgn_extend (bu40 org, bu40 val, int size)
+{
+  bu64 ret = val;
+
+  if (org & (1ULL << (size - 1)))
+    {
+      /* We need to shift in to the MSB which is set.  */
+      int n;
+
+      for (n = 40; n >= 0; n--)
+       if (ret & (1ULL << n))
+         break;
+      ret |= (-1ULL << n);
+    }
+  else
+    ret &= ~(-1ULL << 39);
+
+  return ret;
+}
 static void
 decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
 {
@@ -5702,7 +5795,14 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
                      dst0, (HLs & 2) ? 'H' : 'L',
                      src1, (HLs & 1) ? 'H' : 'L', newimmag);
          if (newimmag > 16)
-           result = lshift (cpu, in, 16 - (newimmag & 0xF), 16, 0, 1);
+           {
+             result = lshift (cpu, in, 16 - (newimmag & 0xF), 16, 0, 1);
+             if (((result >> 15) & 0x1) != ((in >> 15) & 0x1))
+               {
+                 SET_ASTATREG (v, 1);
+                 SET_ASTATREG (vs, 1);
+               }
+           }
          else
            result = ashiftrt (cpu, in, newimmag, 16);
        }
@@ -5717,8 +5817,37 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        {
          TRACE_INSN (cpu, "R%i.%c = R%i.%c >>> %i (S);",
                      dst0, (HLs & 2) ? 'H' : 'L',
-                     src1, (HLs & 1) ? 'H' : 'L', immag);
-         result = lshift (cpu, in, immag, 16, 1, 1);
+                     src1, (HLs & 1) ? 'H' : 'L', newimmag);
+         if (newimmag > 16)
+           {
+             int shift = 32 - newimmag;
+             bu16 inshift = in << shift;
+
+             if (((inshift & ~0xFFFF)
+                  && ((inshift & ~0xFFFF) >> 16) != ~(~0 << shift))
+                 || (inshift & 0x8000) != (in & 0x8000))
+               {
+                 if (in & 0x8000)
+                   result = 0x8000;
+                 else
+                   result = 0x7fff;
+                 SET_ASTATREG (v, 1);
+                 SET_ASTATREG (vs, 1);
+               }
+             else
+               {
+                 result = inshift;
+                 SET_ASTATREG (v, 0);
+               }
+
+             SET_ASTATREG (az, !result);
+             SET_ASTATREG (an, !!(result & 0x8000));
+           }
+         else
+           {
+             result = ashiftrt (cpu, in, newimmag, 16);
+             result = sgn_extend (in, result, 16);
+           }
        }
       else if (sop == 2 && bit8)
        {
@@ -5760,22 +5889,23 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
   else if (sop == 0 && sopcde == 3 && bit8 == 1)
     {
       /* Arithmetic shift, so shift in sign bit copies.  */
-      bu64 acc;
+      bu64 acc, val;
       int shift = uimm5 (newimmag);
       HLs = !!HLs;
 
       TRACE_INSN (cpu, "A%i = A%i >>> %i;", HLs, HLs, shift);
 
       acc = get_extended_acc (cpu, HLs);
-      acc >>= shift;
+      val = acc >> shift;
+
       /* Sign extend again.  */
-      if (acc & (1ULL << 39))
-       acc |= -(1ULL << 39);
-      else
-       acc &= ~(-(1ULL << 39));
+      val = sgn_extend (acc, val, 40);
 
-      STORE (AXREG (HLs), (acc >> 32) & 0xFF);
-      STORE (AWREG (HLs), acc & 0xFFFFFFFF);
+      STORE (AXREG (HLs), (val >> 32) & 0xFF);
+      STORE (AWREG (HLs), val & 0xFFFFFFFF);
+      STORE (ASTATREG (an), !!(val & (1ULL << 39)));
+      STORE (ASTATREG (az), !val);
+      STORE (ASTATREG (av[HLs]), 0);
     }
   else if ((sop == 0 && sopcde == 3 && bit8 == 0)
           || (sop == 1 && sopcde == 3))
@@ -5874,11 +6004,20 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "R%i = R%i >>> %i %s;", dst0, src1, count,
                  sop == 0 ? "(V)" : "(V,S)");
 
-      if (count & 0x10)
+      if (count > 16)
        {
+         int sgn0 = (val0 >> 15) & 0x1;
+         int sgn1 = (val1 >> 15) & 0x1;
+
          val0 = lshift (cpu, val0, 16 - (count & 0xF), 16, 0, 1);
          astat = ASTAT;
          val1 = lshift (cpu, val1, 16 - (count & 0xF), 16, 0, 1);
+
+         if ((sgn0 != ((val0 >> 15) & 0x1)) || (sgn1 != ((val1 >> 15) & 0x1)))
+           {
+             SET_ASTATREG (v, 1);
+             SET_ASTATREG (vs, 1);
+           }
        }
       else
        {
@@ -6165,7 +6304,7 @@ _interp_insn_bfin (SIM_CPU *cpu, bu32 pc)
       else
        {
          TRACE_EXTRACT (cpu, "%s: no matching 16-bit pattern", __func__);
-         illegal_instruction (cpu);
+         illegal_instruction_or_combination (cpu);
        }
       return insn_len;
     }