ubsan: aarch64: left shift cannot be represented in type 'int64_t'
[deliverable/binutils-gdb.git] / sim / bfin / bfin-sim.c
index b982aaf70a084be1a2ce3de090ec38c0ae0013e5..c7214c38da1dd66f92ec00a9fbc9c9869d39b578 100644 (file)
@@ -1,6 +1,6 @@
 /* Simulator for Analog Devices Blackfin processors.
 
-   Copyright (C) 2005-2011 Free Software Foundation, Inc.
+   Copyright (C) 2005-2019 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)
 {
@@ -223,16 +232,7 @@ fmtconst_str (const_forms_t cf, bs32 x, bu32 pc)
     x <<= constant_formats[cf].scale;
 
   if (constant_formats[cf].decimal)
-    {
-      if (constant_formats[cf].leading)
-       {
-         char ps[10];
-         sprintf (ps, "%%%ii", constant_formats[cf].leading);
-         sprintf (buf, ps, x);
-       }
-      else
-       sprintf (buf, "%i", x);
-    }
+    sprintf (buf, "%*i", constant_formats[cf].leading, x);
   else
     {
       if (constant_formats[cf].issigned && x < 0)
@@ -713,8 +713,8 @@ ashiftrt (SIM_CPU *cpu, bu40 val, int cnt, int size)
   val |= sgn;
   SET_ASTATREG (an, val >> (size - 1));
   SET_ASTATREG (az, val == 0);
-  /* XXX: Need to check ASTAT[v] behavior here.  */
-  SET_ASTATREG (v, 0);
+  if (size != 40)
+    SET_ASTATREG (v, 0);
   return val;
 }
 
@@ -742,17 +742,18 @@ lshiftrt (SIM_CPU *cpu, bu64 val, int cnt, int size)
     }
   SET_ASTATREG (an, val >> (size - 1));
   SET_ASTATREG (az, val == 0);
-  SET_ASTATREG (v, 0);
+  if (size != 40)
+    SET_ASTATREG (v, 0);
   return val;
 }
 
 static bu64
-lshift (SIM_CPU *cpu, bu64 val, int cnt, int size, bool saturate)
+lshift (SIM_CPU *cpu, bu64 val, int cnt, int size, bool saturate, bool overflow)
 {
-  int i, j, real_cnt = cnt > size ? size : cnt;
+  int v_i, real_cnt = cnt > size ? size : cnt;
   bu64 sgn = ~((val >> (size - 1)) - 1);
   int mask_cnt = size - 1;
-  bu64 masked, new_val = val, tmp;
+  bu64 masked, new_val = val;
   bu64 mask = ~0;
 
   mask <<= mask_cnt;
@@ -776,31 +777,35 @@ lshift (SIM_CPU *cpu, bu64 val, int cnt, int size, bool saturate)
 
      However, it's a little more complex than looking at sign bits, we need
      to see if we are shifting the sign information away...  */
-  tmp = val & ((~mask << 1) | 1);
-
-  j = 0;
-  for (i = 1; i <= real_cnt && saturate; i++)
-    {
-      if ((tmp & ((bu64)1 << (size - 1))) !=
-         (((val >> mask_cnt) & 0x1) << mask_cnt))
-       j++;
-      tmp <<= 1;
-    }
-  saturate &= (!sgn && (new_val & (1 << mask_cnt)))
-             || (sgn && !(new_val & (1 << mask_cnt)));
+  if (((val << cnt) >> size) == 0
+      || (((val << cnt) >> size) == ~(~0 << cnt)
+         && ((new_val >> (size - 1)) & 0x1)))
+    v_i = 0;
+  else
+    v_i = 1;
 
   switch (size)
     {
     case 16:
-      if (j || (saturate && (new_val & mask)))
-       new_val = sgn == 0 ? 0x7fff : 0x8000, saturate = 1;
       new_val &= 0xFFFF;
+      if (saturate && (v_i || ((val >> (size - 1)) != (new_val >> (size - 1)))))
+       {
+         new_val = (val >> (size - 1)) == 0 ? 0x7fff : 0x8000;
+         v_i = 1;
+       }
       break;
     case 32:
       new_val &= 0xFFFFFFFF;
       masked &= 0xFFFFFFFF;
-      if (j || (saturate && ((sgn != masked) || (!sgn && new_val == 0))))
-       new_val = sgn == 0 ? 0x7fffffff : 0x80000000, saturate = 1;
+      sgn &= 0xFFFFFFFF;
+      if (saturate
+         && (v_i
+             || (sgn != masked)
+             || (!sgn && new_val == 0 && val != 0)))
+       {
+         new_val = sgn == 0 ? 0x7fffffff : 0x80000000;
+         v_i = 1;
+       }
       break;
     case 40:
       new_val &= 0xFFFFFFFFFFull;
@@ -813,9 +818,13 @@ lshift (SIM_CPU *cpu, bu64 val, int cnt, int size, bool saturate)
 
   SET_ASTATREG (an, new_val >> (size - 1));
   SET_ASTATREG (az, new_val == 0);
-  SET_ASTATREG (v, !!(saturate || j));
-  if (saturate || j)
-    SET_ASTATREG (vs, 1);
+  if (size != 40)
+    {
+      SET_ASTATREG (v, overflow && v_i);
+      if (overflow && v_i)
+       SET_ASTATREG (vs, 1);
+    }
+
   return new_val;
 }
 
@@ -1617,10 +1626,20 @@ decode_macfunc (SIM_CPU *cpu, int which, int op, int h0, int h1, int src0,
            acc = 0x7fffffffffull, sat = 1;
          break;
        case M_TFU:
-         if (!MM && (bs64)acc < 0)
-           acc = 0, sat = 1;
-         if (!MM && (bs64)acc > 0xFFFFFFFFFFull)
-           acc = 0xFFFFFFFFFFull, sat = 1;
+         if (MM)
+           {
+             if ((bs64)acc < -((bs64)1 << 39))
+               acc = -((bu64)1 << 39), sat = 1;
+             if ((bs64)acc > 0x7FFFFFFFFFll)
+               acc = 0x7FFFFFFFFFull, sat = 1;
+           }
+         else
+           {
+             if ((bs64)acc < 0)
+               acc = 0, sat = 1;
+             if ((bs64)acc > 0xFFFFFFFFFFull)
+               acc = 0xFFFFFFFFFFull, sat = 1;
+           }
          break;
        case M_IU:
          if (!MM && acc & 0x8000000000000000ull)
@@ -1633,16 +1652,22 @@ decode_macfunc (SIM_CPU *cpu, int which, int op, int h0, int h1, int src0,
            acc |= 0xffffff0000000000ull;
          break;
        case M_FU:
-         if (!MM && (bs64)acc < 0)
-           acc = 0x0, sat = 1;
-         if (MM && (bs64)acc < -((bs64)1 << 39))
-           acc = -((bu64)1 << 39), sat = 1;
-         if (!MM && (bs64)acc > (bs64)0xFFFFFFFFFFll)
-           acc = 0xFFFFFFFFFFull, sat = 1;
-         if (MM && acc > 0xFFFFFFFFFFull)
-           acc &= 0xFFFFFFFFFFull;
-         if (MM && acc & 0x8000000000ull)
-           acc |= 0xffffff0000000000ull;
+         if (MM)
+           {
+             if ((bs64)acc < -((bs64)1 << 39))
+               acc = -((bu64)1 << 39), sat = 1;
+             if ((bs64)acc > 0x7FFFFFFFFFll)
+               acc = 0x7FFFFFFFFFull, sat = 1;
+             else if (acc & 0x8000000000ull)
+               acc |= 0xffffff0000000000ull;
+           }
+         else
+           {
+             if ((bs64)acc < 0)
+               acc = 0x0, sat = 1;
+             else if ((bs64)acc > (bs64)0xFFFFFFFFFFll)
+               acc = 0xFFFFFFFFFFull, sat = 1;
+           }
          break;
        case M_IH:
          if ((bs64)acc < -0x80000000ll)
@@ -1716,7 +1741,7 @@ hwloop_get_next_pc (SIM_CPU *cpu, bu32 pc, bu32 insn_len)
   for (i = 1; i >= 0; --i)
     if (LCREG (i) > 1 && pc == LBREG (i))
       {
-       TRACE_BRANCH (cpu, pc, LTREG (i), i, "Hardware loop %i", i);
+       BFIN_TRACE_BRANCH (cpu, pc, LTREG (i), i, "Hardware loop %i", i);
        return LTREG (i);
       }
 
@@ -1746,9 +1771,9 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "RTS;");
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
-      TRACE_BRANCH (cpu, pc, newpc, -1, "RTS");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "RTS");
       SET_PCREG (newpc);
       BFIN_CPU_STATE.did_jump = true;
       CYCLE_DELAY = 5;
@@ -1758,7 +1783,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "RTI;");
       /* Do not do IFETCH_CHECK here -- LSB has special meaning.  */
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_return (cpu, -1);
       CYCLE_DELAY = 5;
@@ -1770,7 +1795,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       TRACE_INSN (cpu, "RTX;");
       /* XXX: Not sure if this is what the hardware does.  */
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_return (cpu, IVG_EVX);
       CYCLE_DELAY = 5;
@@ -1782,7 +1807,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       TRACE_INSN (cpu, "RTN;");
       /* XXX: Not sure if this is what the hardware does.  */
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_return (cpu, IVG_NMI);
       CYCLE_DELAY = 5;
@@ -1791,7 +1816,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
     {
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "RTE;");
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_return (cpu, IVG_EMU);
       CYCLE_DELAY = 5;
@@ -1806,7 +1831,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
          in user mode, it's a NOP ...  */
       TRACE_INSN (cpu, "IDLE;");
 
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
 
       /* Timewarp !  */
@@ -1820,7 +1845,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_sync);
       /* Just NOP it.  */
       TRACE_INSN (cpu, "CSYNC;");
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       CYCLE_DELAY = 10;
     }
@@ -1829,7 +1854,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_sync);
       /* Just NOP it.  */
       TRACE_INSN (cpu, "SSYNC;");
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
 
       /* Really 10+, but no model info for this.  */
@@ -1839,7 +1864,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
     {
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
       TRACE_INSN (cpu, "EMUEXCPT;");
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_exception (cpu, VEC_SIM_TRAP);
     }
@@ -1847,7 +1872,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
     {
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
       TRACE_INSN (cpu, "CLI R%i;", poprnd);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (poprnd, cec_cli (cpu));
     }
@@ -1855,7 +1880,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
     {
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
       TRACE_INSN (cpu, "STI R%i;", poprnd);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_sti (cpu, DREG (poprnd));
       CYCLE_DELAY = 3;
@@ -1866,9 +1891,9 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "JUMP (%s);", get_preg_name (poprnd));
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
-      TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (Preg)");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (Preg)");
       SET_PCREG (newpc);
       BFIN_CPU_STATE.did_jump = true;
       PROFILE_BRANCH_TAKEN (cpu);
@@ -1880,9 +1905,9 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "CALL (%s);", get_preg_name (poprnd));
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
-      TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (Preg)");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (Preg)");
       /* If we're at the end of a hardware loop, RETS is going to be
          the top of the loop rather than the next instruction.  */
       SET_RETSREG (hwloop_get_next_pc (cpu, pc, 2));
@@ -1897,9 +1922,9 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "CALL (PC + %s);", get_preg_name (poprnd));
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
-      TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (PC + Preg)");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (PC + Preg)");
       SET_RETSREG (hwloop_get_next_pc (cpu, pc, 2));
       SET_PCREG (newpc);
       BFIN_CPU_STATE.did_jump = true;
@@ -1912,9 +1937,9 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
       TRACE_INSN (cpu, "JUMP (PC + %s);", get_preg_name (poprnd));
       IFETCH_CHECK (newpc);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
-      TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (PC + Preg)");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (PC + Preg)");
       SET_PCREG (newpc);
       BFIN_CPU_STATE.did_jump = true;
       PROFILE_BRANCH_TAKEN (cpu);
@@ -1925,7 +1950,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       int raise = uimm4 (poprnd);
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
       TRACE_INSN (cpu, "RAISE %s;", uimm4_str (raise));
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_require_supervisor (cpu);
       if (raise == IVG_IVHW)
@@ -1939,7 +1964,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       int excpt = uimm4 (poprnd);
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
       TRACE_INSN (cpu, "EXCPT %s;", uimm4_str (excpt));
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       cec_exception (cpu, excpt);
       CYCLE_DELAY = 3;
@@ -1950,7 +1975,7 @@ decode_ProgCtrl_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
       bu8 byte;
       PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_atomic);
       TRACE_INSN (cpu, "TESTSET (%s);", get_preg_name (poprnd));
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       byte = GET_WORD (addr);
       SET_CCREG (byte == 0);
@@ -1959,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
@@ -1979,7 +2004,7 @@ decode_CaCTRL_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_EXTRACT (cpu, "%s: a:%i op:%i reg:%i", __func__, a, op, reg);
   TRACE_INSN (cpu, "%s [%s%s];", sinsn[op], get_preg_name (reg), a ? "++" : "");
 
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     /* None of these can be part of a parallel instruction.  */
     illegal_instruction_combination (cpu);
 
@@ -2029,16 +2054,17 @@ 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 (INSN_LEN == 8 || (grp == 7 && reg == 0 && cec_is_user_mode(cpu)))
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE
+         || (grp == 7 && reg == 0 && cec_is_user_mode(cpu)))
        illegal_instruction_combination (cpu);
       /* XXX: The valid register check is in reg_write(), so we might
               incorrectly do a GET_LONG() here ...  */
@@ -2052,7 +2078,7 @@ decode_PushPopReg_0 (SIM_CPU *cpu, bu16 iw0)
   else
     {
       TRACE_INSN (cpu, "[--SP] = %s;", reg_name);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
 
       sp -= 4;
@@ -2087,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);
@@ -2167,7 +2196,7 @@ decode_ccMV_0 (SIM_CPU *cpu, bu16 iw0)
   TRACE_INSN (cpu, "IF %sCC %s = %s;", T ? "" : "! ",
              get_allreg_name (d, dst),
              get_allreg_name (s, src));
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     illegal_instruction_combination (cpu);
 
   if (cond)
@@ -2198,31 +2227,31 @@ 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)
        {
          TRACE_INSN (cpu, "CC = A0 == A1;");
-         if (INSN_LEN == 8)
+         if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
            illegal_instruction_combination (cpu);
          SET_CCREG (acc0 == acc1);
        }
       else if (opc == 6 && I == 0 && G == 0)
        {
          TRACE_INSN (cpu, "CC = A0 < A1");
-         if (INSN_LEN == 8)
+         if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
            illegal_instruction_combination (cpu);
          SET_CCREG (acc0 < acc1);
        }
       else if (opc == 7 && I == 0 && G == 0)
        {
          TRACE_INSN (cpu, "CC = A0 <= A1");
-         if (INSN_LEN == 8)
+         if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
            illegal_instruction_combination (cpu);
          SET_CCREG (acc0 <= acc1);
        }
       else
-       illegal_instruction (cpu);
+       illegal_instruction_or_combination (cpu);
 
       SET_ASTATREG (az, diff == 0);
       SET_ASTATREG (an, diff < 0);
@@ -2287,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)
@@ -2314,26 +2346,26 @@ decode_CC2dreg_0 (SIM_CPU *cpu, bu16 iw0)
   if (op == 0)
     {
       TRACE_INSN (cpu, "R%i = CC;", reg);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (reg, CCREG);
     }
   else if (op == 1)
     {
       TRACE_INSN (cpu, "CC = R%i;", reg);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_CCREG (DREG (reg) != 0);
     }
   else if (op == 3 && reg == 0)
     {
       TRACE_INSN (cpu, "CC = !CC;");
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_CCREG (!CCREG);
     }
   else
-    illegal_instruction (cpu);
+    illegal_instruction_or_combination (cpu);
 }
 
 static void
@@ -2356,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 (INSN_LEN == 8)
-    illegal_instruction_combination (cpu);
-
   pval = !!(ASTAT & (1 << cbit));
   if (D == 0)
     switch (op)
@@ -2406,13 +2438,13 @@ decode_BRCC_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
   TRACE_INSN (cpu, "IF %sCC JUMP %#x%s;", T ? "" : "! ",
              pcrel, B ? " (bp)" : "");
 
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     illegal_instruction_combination (cpu);
 
   if (cond)
     {
       bu32 newpc = pc + pcrel;
-      TRACE_BRANCH (cpu, pc, newpc, -1, "Conditional JUMP");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "Conditional JUMP");
       SET_PCREG (newpc);
       BFIN_CPU_STATE.did_jump = true;
       PROFILE_BRANCH_TAKEN (cpu);
@@ -2442,10 +2474,10 @@ decode_UJUMP_0 (SIM_CPU *cpu, bu16 iw0, bu32 pc)
 
   TRACE_INSN (cpu, "JUMP.S %#x;", pcrel);
 
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     illegal_instruction_combination (cpu);
 
-  TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.S");
+  BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.S");
 
   SET_PCREG (newpc);
   BFIN_CPU_STATE.did_jump = true;
@@ -2474,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;
@@ -2522,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);
@@ -2540,7 +2578,7 @@ decode_ALU2op_0 (SIM_CPU *cpu, bu16 iw0)
   else if (opc == 2)
     {
       TRACE_INSN (cpu, "R%i <<= R%i;", dst, src);
-      SET_DREG (dst, lshift (cpu, DREG (dst), DREG (src), 32, 0));
+      SET_DREG (dst, lshift (cpu, DREG (dst), DREG (src), 32, 0, 0));
     }
   else if (opc == 3)
     {
@@ -2630,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);
@@ -2689,21 +2730,21 @@ decode_LOGI2op_0 (SIM_CPU *cpu, bu16 iw0)
   if (opc == 0)
     {
       TRACE_INSN (cpu, "CC = ! BITTST (R%i, %s);", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_CCREG ((~DREG (dst) >> uimm) & 1);
     }
   else if (opc == 1)
     {
       TRACE_INSN (cpu, "CC = BITTST (R%i, %s);", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_CCREG ((DREG (dst) >> uimm) & 1);
     }
   else if (opc == 2)
     {
       TRACE_INSN (cpu, "BITSET (R%i, %s);", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (dst, DREG (dst) | (1 << uimm));
       setflags_logical (cpu, DREG (dst));
@@ -2711,7 +2752,7 @@ decode_LOGI2op_0 (SIM_CPU *cpu, bu16 iw0)
   else if (opc == 3)
     {
       TRACE_INSN (cpu, "BITTGL (R%i, %s);", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (dst, DREG (dst) ^ (1 << uimm));
       setflags_logical (cpu, DREG (dst));
@@ -2719,7 +2760,7 @@ decode_LOGI2op_0 (SIM_CPU *cpu, bu16 iw0)
   else if (opc == 4)
     {
       TRACE_INSN (cpu, "BITCLR (R%i, %s);", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (dst, DREG (dst) & ~(1 << uimm));
       setflags_logical (cpu, DREG (dst));
@@ -2727,23 +2768,23 @@ decode_LOGI2op_0 (SIM_CPU *cpu, bu16 iw0)
   else if (opc == 5)
     {
       TRACE_INSN (cpu, "R%i >>>= %s;", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (dst, ashiftrt (cpu, DREG (dst), uimm, 32));
     }
   else if (opc == 6)
     {
       TRACE_INSN (cpu, "R%i >>= %s;", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_DREG (dst, lshiftrt (cpu, DREG (dst), uimm, 32));
     }
   else if (opc == 7)
     {
       TRACE_INSN (cpu, "R%i <<= %s;", dst, uimm_str);
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
-      SET_DREG (dst, lshift (cpu, DREG (dst), uimm, 32, 0));
+      SET_DREG (dst, lshift (cpu, DREG (dst), uimm, 32, 0, 0));
     }
 }
 
@@ -2763,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);
@@ -2826,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));
@@ -2855,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));
@@ -2887,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);
@@ -2983,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
@@ -3001,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);
@@ -3017,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
@@ -3033,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);
@@ -3054,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
@@ -3217,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
@@ -3233,7 +3292,7 @@ decode_LDST_0 (SIM_CPU *cpu, bu16 iw0)
   int aop = ((iw0 >> LDST_aop_bits) & LDST_aop_mask);
   int reg = ((iw0 >> LDST_reg_bits) & LDST_reg_mask);
   int ptr = ((iw0 >> LDST_ptr_bits) & LDST_ptr_mask);
-  const char * const posts[] = { "++", "--", "" };
+  const char * const posts[] = { "++", "--", "", "<INV>" };
   const char *post = posts[aop];
   const char *ptr_name = get_preg_name (ptr);
 
@@ -3241,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)
     {
@@ -3279,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
     {
@@ -3304,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)
@@ -3336,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);
@@ -3376,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);
 
@@ -3449,7 +3514,7 @@ decode_LoopSetup_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1, bu32 pc)
   if (reg > 7)
     illegal_instruction (cpu);
 
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     illegal_instruction_combination (cpu);
 
   if (rop == 0)
@@ -3497,7 +3562,7 @@ decode_LDIMMhalf_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
   TRACE_EXTRACT (cpu, "%s: Z:%i H:%i S:%i grp:%i reg:%i hword:%#x",
                 __func__, Z, H, S, grp, reg, hword);
 
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     illegal_instruction_combination (cpu);
 
   if (S == 1)
@@ -3549,16 +3614,16 @@ decode_CALLa_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1, bu32 pc)
 
   TRACE_INSN (cpu, "%s %#x;", S ? "CALL" : "JUMP.L", pcrel);
 
-  if (INSN_LEN == 8)
+  if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
     illegal_instruction_combination (cpu);
 
   if (S == 1)
     {
-      TRACE_BRANCH (cpu, pc, newpc, -1, "CALL");
+      BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "CALL");
       SET_RETSREG (hwloop_get_next_pc (cpu, pc, 4));
     }
   else
-    TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.L");
+    BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.L");
 
   SET_PCREG (newpc);
   BFIN_CPU_STATE.did_jump = true;
@@ -3683,7 +3748,7 @@ decode_linkage_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       int size = uimm16s4 (framesize);
       sp = SPREG;
       TRACE_INSN (cpu, "LINK %s;", uimm16s4_str (framesize));
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       sp -= 4;
       PUT_LONG (sp, RETSREG);
@@ -3698,7 +3763,7 @@ decode_linkage_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Restore SP from FP.  */
       sp = FPREG;
       TRACE_INSN (cpu, "UNLINK;");
-      if (INSN_LEN == 8)
+      if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
        illegal_instruction_combination (cpu);
       SET_FPREG (GET_LONG (sp));
       sp += 4;
@@ -4004,19 +4069,19 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
                      "dst1:%i src0:%i src1:%i",
                 __func__, M, HL, aopcde, aop, s, x, dst0, dst1, src0, src1);
 
-  if ((aop == 0 || aop == 2) && aopcde == 9 && HL == 0 && s == 0)
+  if ((aop == 0 || aop == 2) && aopcde == 9 && x == 0 && s == 0 && HL == 0)
     {
       int a = aop >> 1;
       TRACE_INSN (cpu, "A%i.L = R%i.L;", a, src0);
       SET_AWREG (a, REG_H_L (AWREG (a), DREG (src0)));
     }
-  else if ((aop == 0 || aop == 2) && aopcde == 9 && HL == 1 && s == 0)
+  else if ((aop == 0 || aop == 2) && aopcde == 9 && x == 0 && s == 0 && HL == 1)
     {
       int a = aop >> 1;
       TRACE_INSN (cpu, "A%i.H = R%i.H;", a, src0);
       SET_AWREG (a, REG_H_L (DREG (src0), AWREG (a)));
     }
-  else if ((aop == 1 || aop == 0) && aopcde == 5)
+  else if ((aop == 1 || aop == 0) && aopcde == 5 && x == 0 && s == 0)
     {
       bs32 val0 = DREG (src0);
       bs32 val1 = DREG (src1);
@@ -4093,7 +4158,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       if (ovX)
        SET_ASTATREG (vs, ovX);
     }
-  else if ((aop == 2 || aop == 3) && aopcde == 5)
+  else if ((aop == 2 || aop == 3) && aopcde == 5 && x == 1 && s == 0)
     {
       bs32 val0 = DREG (src0);
       bs32 val1 = DREG (src1);
@@ -4122,7 +4187,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (an, res & 0x8000);
       SET_ASTATREG (v, 0);
     }
-  else if (aopcde == 2 || aopcde == 3)
+  else if ((aopcde == 2 || aopcde == 3) && x == 0)
     {
       bu32 s1, s2, val, ac0_i = 0, v_i = 0;
 
@@ -4158,19 +4223,19 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (an, val & 0x8000);
       SET_ASTATREG (az, val == 0);
     }
-  else if ((aop == 0 || aop == 2) && aopcde == 9 && s == 1)
+  else if ((aop == 0 || aop == 2) && aopcde == 9 && x == 0 && s == 1 && HL == 0)
     {
       int a = aop >> 1;
       TRACE_INSN (cpu, "A%i = R%i;", a, src0);
       SET_AREG32 (a, DREG (src0));
     }
-  else if ((aop == 1 || aop == 3) && aopcde == 9 && s == 0)
+  else if ((aop == 1 || aop == 3) && aopcde == 9 && x == 0 && s == 0 && HL == 0)
     {
       int a = aop >> 1;
       TRACE_INSN (cpu, "A%i.X = R%i.L;", a, src0);
       SET_AXREG (a, (bs8)DREG (src0));
     }
-  else if (aop == 3 && aopcde == 11 && (s == 0 || s == 1))
+  else if (aop == 3 && aopcde == 11 && x == 0 && HL == 0)
     {
       bu64 acc0 = get_extended_acc (cpu, 0);
       bu64 acc1 = get_extended_acc (cpu, 1);
@@ -4203,7 +4268,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       if (sat)
        STORE (ASTATREG (av0s), sat);
     }
-  else if ((aop == 0 || aop == 1) && aopcde == 22)
+  else if ((aop == 0 || aop == 1) && aopcde == 22 && x == 0)
     {
       bu32 s0, s0L, s0H, s1, s1L, s1H;
       bu32 tmp0, tmp1, i;
@@ -4213,6 +4278,9 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
                  src0 + 1, src0, src1 + 1, src1, opts[HL + (aop << 1)],
                  s ? ", r" : "");
 
+      if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+       illegal_instruction (cpu);
+
       s0L = DREG (src0);
       s0H = DREG (src0 + 1);
       s1L = DREG (src1);
@@ -4238,18 +4306,19 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if ((aop == 0 || aop == 1) && s == 0 && aopcde == 8)
+  else if ((aop == 0 || aop == 1) && aopcde == 8 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "A%i = 0;", aop);
       SET_AREG (aop, 0);
     }
-  else if (aop == 2 && s == 0 && aopcde == 8)
+  else if (aop == 2 && aopcde == 8 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "A1 = A0 = 0;");
       SET_AREG (0, 0);
       SET_AREG (1, 0);
     }
-  else if ((aop == 0 || aop == 1 || aop == 2) && s == 1 && aopcde == 8)
+  else if ((aop == 0 || aop == 1 || aop == 2) && s == 1 && aopcde == 8
+          && x == 0 && HL == 0)
     {
       bs40 acc0 = get_extended_acc (cpu, 0);
       bs40 acc1 = get_extended_acc (cpu, 1);
@@ -4291,13 +4360,13 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (az, (acc0 == 0) || (acc1 == 0));
       SET_ASTATREG (an, ((acc0 >> 31) & 1) || ((acc1 >> 31) & 1));
     }
-  else if (aop == 3 && (s == 0 || s == 1) && aopcde == 8)
+  else if (aop == 3 && aopcde == 8 && x == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "A%i = A%i;", s, !s);
       SET_AXREG (s, AXREG (!s));
       SET_AWREG (s, AWREG (!s));
     }
-  else if (aop == 3 && HL == 0 && aopcde == 16)
+  else if (aop == 3 && HL == 0 && aopcde == 16 && x == 0 && s == 0)
     {
       int i;
       bu32 az;
@@ -4325,7 +4394,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (az, az);
       SET_ASTATREG (an, 0);
     }
-  else if (aop == 0 && aopcde == 23)
+  else if (aop == 0 && aopcde == 23 && x == 0)
     {
       bu32 s0, s0L, s0H, s1, s1L, s1H;
       bs32 tmp0, tmp1;
@@ -4334,6 +4403,9 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
                  src0 + 1, src0, src1 + 1, src1, HL ? "HI" : "LO",
                  s ? ", R" : "");
 
+      if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+       illegal_instruction (cpu);
+
       s0L = DREG (src0);
       s0H = DREG (src0 + 1);
       s1L = DREG (src1);
@@ -4357,7 +4429,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if ((aop == 0 || aop == 1) && aopcde == 16)
+  else if ((aop == 0 || aop == 1) && aopcde == 16 && x == 0 && s == 0)
     {
       bu32 av;
       bs40 acc;
@@ -4378,7 +4450,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (az, acc == 0);
       SET_ASTATREG (an, 0);
     }
-  else if (aop == 3 && aopcde == 12)
+  else if (aop == 3 && aopcde == 12 && x == 0 && s == 0)
     {
       bs32 res = DREG (src0);
       bs32 ovX;
@@ -4419,7 +4491,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       if (ovX)
        SET_ASTATREG (vs, ovX);
     }
-  else if (aop == 3 && HL == 0 && aopcde == 15)
+  else if (aop == 3 && HL == 0 && aopcde == 15 && x == 0 && s == 0)
     {
       bu32 hi = (-(bs16)(DREG (src0) >> 16)) << 16;
       bu32 lo = (-(bs16)(DREG (src0) & 0xFFFF)) & 0xFFFF;
@@ -4454,7 +4526,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (ac1, ac1);
       setflags_nz_2x16 (cpu, DREG (dst0));
     }
-  else if (aop == 3 && HL == 0 && aopcde == 14)
+  else if (aop == 3 && HL == 0 && aopcde == 14 && x == 0 && s == 0)
     {
       TRACE_INSN (cpu, "A1 = - A1 , A0 = - A0;");
 
@@ -4462,10 +4534,10 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_AREG (1, saturate_s40 (-get_extended_acc (cpu, 1)));
       /* XXX: what ASTAT flags need updating ?  */
     }
-  else if ((aop == 0 || aop == 1) && (HL == 0 || HL == 1) && aopcde == 14)
+  else if ((aop == 0 || aop == 1) && aopcde == 14 && x == 0 && s == 0)
     {
       bs40 src_acc = get_extended_acc (cpu, aop);
-      int v = 0;
+      bu32 v = 0;
 
       TRACE_INSN (cpu, "A%i = - A%i;", HL, aop);
 
@@ -4488,7 +4560,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
            SET_ASTATREG (av1s, 1);
        }
     }
-  else if (aop == 0 && aopcde == 12)
+  else if (aop == 0 && aopcde == 12 && x == 0 && s == 0 && HL == 0)
     {
       bs16 tmp0_hi = DREG (src0) >> 16;
       bs16 tmp0_lo = DREG (src0);
@@ -4508,7 +4580,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
 
       STORE (DREG (dst0), REG_H_L (tmp1_hi << 16, tmp1_hi));
     }
-  else if (aopcde == 0)
+  else if (aopcde == 0 && HL == 0)
     {
       bu32 s0 = DREG (src0);
       bu32 s1 = DREG (src1);
@@ -4547,7 +4619,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       else
        SET_DREG (dst0, (t0 << 16) | t1);
     }
-  else if (aop == 1 && aopcde == 12)
+  else if (aop == 1 && aopcde == 12 && x == 0 && s == 0 && HL == 0)
     {
       bs32 val0 = (bs16)(AWREG (0) >> 16) + (bs16)AWREG (0);
       bs32 val1 = (bs16)(AWREG (1) >> 16) + (bs16)AWREG (1);
@@ -4560,7 +4632,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_DREG (dst0, val0);
       SET_DREG (dst1, val1);
     }
-  else if (aopcde == 1)
+  else if ((aop == 0 || aop == 2 || aop == 3) && aopcde == 1)
     {
       bu32 d0, d1;
       bu32 x0, x1;
@@ -4613,7 +4685,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       STORE (DREG (dst0), d0);
       STORE (DREG (dst1), d1);
     }
-  else if ((aop == 0 || aop == 1 || aop == 2) && aopcde == 11)
+  else if ((aop == 0 || aop == 1 || aop == 2) && aopcde == 11 && x == 0)
     {
       bs40 acc0 = get_extended_acc (cpu, 0);
       bs40 acc1 = get_extended_acc (cpu, 1);
@@ -4621,11 +4693,23 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       bu32 carry = !!((bu40)~acc1 < (bu40)acc0);
 
       if (aop == 0)
-       TRACE_INSN (cpu, "R%i = (A0 += A1);", dst0);
+       {
+         if (s != 0 || HL != 0)
+           illegal_instruction (cpu);
+         TRACE_INSN (cpu, "R%i = (A0 += A1);", dst0);
+       }
       else if (aop == 1)
-       TRACE_INSN (cpu, "R%i.%c = (A0 += A1);", dst0, HL ? 'H' : 'L');
+       {
+         if (s != 0)
+           illegal_instruction (cpu);
+         TRACE_INSN (cpu, "R%i.%c = (A0 += A1);", dst0, HL ? 'H' : 'L');
+       }
       else
-       TRACE_INSN (cpu, "A0 += A1%s;", s ? " (W32)" : "");
+       {
+         if (HL != 0)
+           illegal_instruction (cpu);
+         TRACE_INSN (cpu, "A0 += A1%s;", s ? " (W32)" : "");
+       }
 
       acc0 += acc1;
       acc0 = saturate_s40_astat (acc0, &v);
@@ -4677,22 +4761,22 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
          STORE (ASTATREG (ac0_copy), carry);
        }
     }
-  else if ((aop == 0 || aop == 1) && aopcde == 10)
+  else if ((aop == 0 || aop == 1) && aopcde == 10 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i.L = A%i.X;", dst0, aop);
       SET_DREG_L (dst0, (bs8)AXREG (aop));
     }
-  else if (aop == 0 && aopcde == 4)
+  else if (aop == 0 && aopcde == 4 && x == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = R%i + R%i%s;", dst0, src0, src1, amod1 (s, x));
       SET_DREG (dst0, add32 (cpu, DREG (src0), DREG (src1), 1, s));
     }
-  else if (aop == 1 && aopcde == 4)
+  else if (aop == 1 && aopcde == 4 && x == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = R%i - R%i%s;", dst0, src0, src1, amod1 (s, x));
       SET_DREG (dst0, sub32 (cpu, DREG (src0), DREG (src1), 1, s, 0));
     }
-  else if (aop == 2 && aopcde == 4)
+  else if (aop == 2 && aopcde == 4 && x == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = R%i + R%i, R%i = R%i - R%i%s;",
                  dst1, src0, src1, dst0, src0, src1, amod1 (s, x));
@@ -4703,7 +4787,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       STORE (DREG (dst1), add32 (cpu, DREG (src0), DREG (src1), 1, s));
       STORE (DREG (dst0), sub32 (cpu, DREG (src0), DREG (src1), 1, s, 1));
     }
-  else if ((aop == 0 || aop == 1) && aopcde == 17)
+  else if ((aop == 0 || aop == 1) && aopcde == 17 && x == 0 && HL == 0)
     {
       bs40 acc0 = get_extended_acc (cpu, 0);
       bs40 acc1 = get_extended_acc (cpu, 1);
@@ -4750,7 +4834,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       else
        SET_ASTATREG (ac0, !!((bu40)acc0 <= (bu40)acc1));
     }
-  else if (aop == 0 && aopcde == 18)
+  else if (aop == 0 && aopcde == 18 && x == 0 && HL == 0)
     {
       bu40 acc0 = get_extended_acc (cpu, 0);
       bu40 acc1 = get_extended_acc (cpu, 1);
@@ -4809,12 +4893,12 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if (aop == 3 && aopcde == 18)
+  else if (aop == 3 && aopcde == 18 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "DISALGNEXCPT");
       DIS_ALGN_EXPT |= 1;
     }
-  else if ((aop == 0 || aop == 1) && aopcde == 20)
+  else if ((aop == 0 || aop == 1) && aopcde == 20 && x == 0 && HL == 0)
     {
       bu32 s0, s0L, s0H, s1, s1L, s1H;
       const char * const opts[] = { "", " (R)", " (T)", " (T, R)" };
@@ -4822,6 +4906,9 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "R%i = BYTEOP1P (R%i:%i, R%i:%i)%s;", dst0,
                  src0 + 1, src0, src1 + 1, src1, opts[s + (aop << 1)]);
 
+      if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+       illegal_instruction (cpu);
+
       s0L = DREG (src0);
       s0H = DREG (src0 + 1);
       s1L = DREG (src1);
@@ -4846,13 +4933,16 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if (aop == 0 && aopcde == 21)
+  else if (aop == 0 && aopcde == 21 && x == 0 && HL == 0)
     {
       bu32 s0, s0L, s0H, s1, s1L, s1H;
 
       TRACE_INSN (cpu, "(R%i, R%i) = BYTEOP16P (R%i:%i, R%i:%i)%s;", dst1, dst0,
                  src0 + 1, src0, src1 + 1, src1, s ? " (R)" : "");
 
+      if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+       illegal_instruction (cpu);
+
       if (dst0 == dst1)
        illegal_instruction_combination (cpu);
 
@@ -4881,13 +4971,16 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if (aop == 1 && aopcde == 21)
+  else if (aop == 1 && aopcde == 21 && x == 0 && HL == 0)
     {
       bu32 s0, s0L, s0H, s1, s1L, s1H;
 
       TRACE_INSN (cpu, "(R%i, R%i) = BYTEOP16M (R%i:%i, R%i:%i)%s;", dst1, dst0,
                  src0 + 1, src0, src1 + 1, src1, s ? " (R)" : "");
 
+      if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+       illegal_instruction (cpu);
+
       if (dst0 == dst1)
        illegal_instruction_combination (cpu);
 
@@ -4916,17 +5009,17 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if (aop == 1 && aopcde == 7)
+  else if (aop == 1 && aopcde == 7 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = MIN (R%i, R%i);", dst0, src0, src1);
       SET_DREG (dst0, min32 (cpu, DREG (src0), DREG (src1)));
     }
-  else if (aop == 0 && aopcde == 7)
+  else if (aop == 0 && aopcde == 7 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = MAX (R%i, R%i);", dst0, src0, src1);
       SET_DREG (dst0, max32 (cpu, DREG (src0), DREG (src1)));
     }
-  else if (aop == 2 && aopcde == 7)
+  else if (aop == 2 && aopcde == 7 && x == 0 && s == 0 && HL == 0)
     {
       bu32 val = DREG (src0);
       int v;
@@ -4945,11 +5038,11 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        SET_ASTATREG (vs, 1);
       setflags_nz (cpu, val);
     }
-  else if (aop == 3 && aopcde == 7)
+  else if (aop == 3 && aopcde == 7 && x == 0 && HL == 0)
     {
       bu32 val = DREG (src0);
 
-      TRACE_INSN (cpu, "R%i = - R%i %s;", dst0, src0, amod1 (s, 0));
+      TRACE_INSN (cpu, "R%i = - R%i%s;", dst0, src0, amod1 (s, 0));
 
       if (s && val == 0x80000000)
        {
@@ -4966,7 +5059,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (az, val == 0);
       SET_ASTATREG (an, val & 0x80000000);
     }
-  else if (aop == 2 && aopcde == 6)
+  else if (aop == 2 && aopcde == 6 && x == 0 && s == 0 && HL == 0)
     {
       bu32 in = DREG (src0);
       bu32 hi = (in & 0x80000000 ? (bu32)-(bs16)(in >> 16) : in >> 16) << 16;
@@ -4993,17 +5086,17 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        SET_ASTATREG (vs, 1);
       setflags_nz_2x16 (cpu, DREG (dst0));
     }
-  else if (aop == 1 && aopcde == 6)
+  else if (aop == 1 && aopcde == 6 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = MIN (R%i, R%i) (V);", dst0, src0, src1);
       SET_DREG (dst0, min2x16 (cpu, DREG (src0), DREG (src1)));
     }
-  else if (aop == 0 && aopcde == 6)
+  else if (aop == 0 && aopcde == 6 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = MAX (R%i, R%i) (V);", dst0, src0, src1);
       SET_DREG (dst0, max2x16 (cpu, DREG (src0), DREG (src1)));
     }
-  else if (aop == 0 && aopcde == 24)
+  else if (aop == 0 && aopcde == 24 && x == 0 && s == 0 && HL == 0)
     {
       TRACE_INSN (cpu, "R%i = BYTEPACK (R%i, R%i);", dst0, src0, src1);
       STORE (DREG (dst0),
@@ -5015,7 +5108,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if (aop == 1 && aopcde == 24)
+  else if (aop == 1 && aopcde == 24 && x == 0 && HL == 0)
     {
       int order, lo, hi;
       bu64 comb_src;
@@ -5024,6 +5117,9 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "(R%i, R%i) = BYTEUNPACK R%i:%i%s;",
                  dst1, dst0, src0 + 1, src0, s ? " (R)" : "");
 
+      if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+       illegal_instruction (cpu);
+
       if (dst0 == dst1)
        illegal_instruction_combination (cpu);
 
@@ -5043,7 +5139,7 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       /* Implicit DISALGNEXCPT in parallel.  */
       DIS_ALGN_EXPT |= 1;
     }
-  else if (aopcde == 13)
+  else if (aopcde == 13 && HL == 0 && x == 0 && s == 0)
     {
       const char *searchmodes[] = { "GT", "GE", "LT", "LE" };
       bool up_hi, up_lo;
@@ -5052,6 +5148,19 @@ decode_dsp32alu_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "(R%i, R%i) = SEARCH R%i (%s);",
                  dst1, dst0, src0, searchmodes[aop]);
 
+      /* XXX: The parallel version is a bit weird in its limits:
+
+         This instruction can be issued in parallel with the combination of one
+         16-bit length load instruction to the P0 register and one 16-bit NOP.
+         No other instructions can be issued in parallel with the Vector Search
+         instruction. Note the following legal and illegal forms.
+         (r1, r0) = search r2 (LT) || r2 = [p0++p3]; // ILLEGAL
+         (r1, r0) = search r2 (LT) || r2 = [p0++];   // LEGAL
+         (r1, r0) = search r2 (LT) || r2 = [p0++];   // LEGAL
+
+         Unfortunately, our parallel insn state doesn't (currently) track enough
+         details to be able to check this.  */
+
       if (dst0 == dst1)
        illegal_instruction_combination (cpu);
 
@@ -5141,7 +5250,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);
+       {
+         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));
@@ -5193,38 +5311,45 @@ 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);
+       val = lshift (cpu, acc, shft, 40, 0, 0);
 
       STORE (AXREG (HLs), (val >> 32) & 0xff);
       STORE (AWREG (HLs), (val & 0xffffffff));
+      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_extended_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);
+       val = lshift (cpu, acc, shft, 40, 0, 0);
 
       STORE (AXREG (HLs), (val >> 32) & 0xff);
       STORE (AWREG (HLs), (val & 0xffffffff));
+      STORE (ASTATREG (av[HLs]), 0);
     }
-  else if ((sop == 0 || sop == 1) && sopcde == 1)
+  else if (HLs != 0)
+    /* All the insns after this point don't use HLs.  */
+    illegal_instruction (cpu);
+  else if ((sop == 0 || sop == 1) && sopcde == 1 && HLs == 0)
     {
       bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
       bu16 val0, val1;
@@ -5244,9 +5369,18 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        }
       else
        {
-         val0 = lshift (cpu, val0, shft, 16, sop == 1);
+         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);
+         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);
@@ -5271,7 +5405,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));
+       {
+         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)
     {
@@ -5288,7 +5431,7 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       if (shift)
        SET_CCREG (cc);
     }
-  else if (sop == 2 && sopcde == 1)
+  else if (sop == 2 && sopcde == 1 && HLs == 0)
     {
       bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
       bu16 val0, val1;
@@ -5307,9 +5450,9 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        }
       else
        {
-         val0 = lshift (cpu, val0, shft, 16, 0);
+         val0 = lshift (cpu, val0, shft, 16, 0, 0);
          astat = ASTAT;
-         val1 = lshift (cpu, val1, shft, 16, 0);
+         val1 = lshift (cpu, val1, shft, 16, 0, 0);
        }
       SET_ASTAT (ASTAT | astat);
       STORE (DREG (dst0), (val1 << 16) | val0);
@@ -5493,7 +5636,7 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        out = sL;
 
       SET_AREG (0, acc0);
-      SET_DREG (dst0, REG_H_L (DREG (dst0), out));
+      STORE (DREG (dst0), REG_H_L (DREG (dst0), out));
     }
   else if ((sop == 2 || sop == 3) && sopcde == 9)
     {
@@ -5530,7 +5673,7 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
        out1 = s1L;
 
       SET_AREG (0, acc0);
-      SET_DREG (dst0, REG_H_L (out1 << 16, out0));
+      STORE (DREG (dst0), REG_H_L (out1 << 16, out0));
     }
   else if (sop == 0 && sopcde == 10)
     {
@@ -5573,7 +5716,7 @@ decode_dsp32shift_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       bu32 fg = DREG (src0);
       bu32 bg = DREG (src1);
       bu32 len = fg & 0x1f;
-      bu32 mask = (1 << MIN (16, len)) - 1;
+      bu32 mask = (1 << min (16, len)) - 1;
       bu32 fgnd = (fg >> 16) & mask;
       int shft = ((fg >> 8) & 0x1f);
 
@@ -5645,6 +5788,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)
 {
@@ -5679,7 +5842,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);
+           {
+             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);
        }
@@ -5688,14 +5858,43 @@ 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);
+         result = lshift (cpu, in, immag, 16, 1, 1);
        }
       else if (sop == 1 && bit8)
        {
          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);
+                     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)
        {
@@ -5709,7 +5908,7 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
          TRACE_INSN (cpu, "R%i.%c = R%i.%c << %i;",
                      dst0, (HLs & 2) ? 'H' : 'L',
                      src1, (HLs & 1) ? 'H' : 'L', immag);
-         result = lshift (cpu, in, immag, 16, 0);
+         result = lshift (cpu, in, immag, 16, 0, 1);
        }
       else
        illegal_instruction (cpu);
@@ -5734,33 +5933,32 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       if (shift)
        SET_CCREG (cc);
     }
-  else if (sop == 0 && sopcde == 3 && bit8 == 1)
+  else if (sop == 0 && sopcde == 3 && bit8 == 1 && HLs < 2)
     {
       /* 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))
+  else if (((sop == 0 && sopcde == 3 && bit8 == 0)
+          || (sop == 1 && sopcde == 3)) && HLs < 2)
     {
       bu64 acc;
       int shiftup = uimm5 (immag);
       int shiftdn = uimm5 (newimmag);
-      HLs = !!HLs;
 
       TRACE_INSN (cpu, "A%i = A%i %s %i;", HLs, HLs,
                  sop == 0 ? "<<" : ">>",
@@ -5787,6 +5985,9 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       SET_ASTATREG (an, !!(acc & 0x8000000000ull));
       SET_ASTATREG (az, (acc & 0xFFFFFFFFFF) == 0);
     }
+  else if (HLs != 0)
+    /* All the insns after this point don't use HLs.  */
+    illegal_instruction (cpu);
   else if (sop == 1 && sopcde == 1 && bit8 == 0)
     {
       int count = imm5 (immag);
@@ -5797,9 +5998,9 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "R%i = R%i << %i (V,S);", dst0, src1, count);
       if (count >= 0)
        {
-         val0 = lshift (cpu, val0, count, 16, 1);
+         val0 = lshift (cpu, val0, count, 16, 1, 1);
          astat = ASTAT;
-         val1 = lshift (cpu, val1, count, 16, 1);
+         val1 = lshift (cpu, val1, count, 16, 1, 1);
        }
       else
        {
@@ -5834,9 +6035,9 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       bu32 astat;
 
       TRACE_INSN (cpu, "R%i = R%i << %i (V);", dst0, src1, count);
-      val0 = lshift (cpu, val0, count, 16, 0);
+      val0 = lshift (cpu, val0, count, 16, 0, 1);
       astat = ASTAT;
-      val1 = lshift (cpu, val1, count, 16, 0);
+      val1 = lshift (cpu, val1, count, 16, 0, 1);
       SET_ASTAT (ASTAT | astat);
 
       STORE (DREG (dst0), val0 | (val1 << 16));
@@ -5851,11 +6052,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)
        {
-         val0 = lshift (cpu, val0, 16 - (count & 0xF), 16, 0);
+         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);
+         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
        {
@@ -5873,7 +6083,11 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       int count = imm6 (immag);
 
       TRACE_INSN (cpu, "R%i = R%i << %i (S);", dst0, src1, count);
-      STORE (DREG (dst0), lshift (cpu, DREG (src1), count, 32, 1));
+
+      if (count < 0)
+       STORE (DREG (dst0), ashiftrt (cpu, DREG (src1), -count, 32));
+      else
+       STORE (DREG (dst0), lshift (cpu, DREG (src1), count, 32, 1, 1));
     }
   else if (sop == 2 && sopcde == 2)
     {
@@ -5882,7 +6096,7 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "R%i = R%i >> %i;", dst0, src1, count);
 
       if (count < 0)
-       STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0));
+       STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0, 1));
       else
        STORE (DREG (dst0), lshiftrt (cpu, DREG (src1), count, 32));
     }
@@ -5908,7 +6122,7 @@ decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
       TRACE_INSN (cpu, "R%i = R%i >>> %i;", dst0, src1, count);
 
       if (count < 0)
-       STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0));
+       STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0, 1));
       else
        STORE (DREG (dst0), ashiftrt (cpu, DREG (src1), count, 32));
     }
@@ -6142,7 +6356,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;
     }
@@ -6155,6 +6369,7 @@ _interp_insn_bfin (SIM_CPU *cpu, bu32 pc)
       trace_prefix (sd, cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
                        NULL, 0, "|| %#"PRIx64, sim_events_time (sd));
       insn_len = 8;
+      PARALLEL_GROUP = BFIN_PARALLEL_GROUP0;
     }
   else
     insn_len = 4;
@@ -6165,6 +6380,9 @@ _interp_insn_bfin (SIM_CPU *cpu, bu32 pc)
   /* Only cache on first run through (in case of parallel insns).  */
   if (INSN_LEN == 0)
     INSN_LEN = insn_len;
+  else
+    /* Once you're past the first slot, only 16bit insns are valid.  */
+    illegal_instruction_combination (cpu);
 
   if ((iw0 & 0xf7ff) == 0xc003 && (iw1 & 0xfe00) == 0x1800)
     {
@@ -6213,6 +6431,7 @@ interp_insn_bfin (SIM_CPU *cpu, bu32 pc)
   bu32 insn_len;
 
   BFIN_CPU_STATE.n_stores = 0;
+  PARALLEL_GROUP = BFIN_PARALLEL_NONE;
   DIS_ALGN_EXPT &= ~1;
   CYCLE_DELAY = 1;
   INSN_LEN = 0;
@@ -6222,7 +6441,9 @@ interp_insn_bfin (SIM_CPU *cpu, bu32 pc)
   /* Proper display of multiple issue instructions.  */
   if (insn_len == 8)
     {
+      PARALLEL_GROUP = BFIN_PARALLEL_GROUP1;
       _interp_insn_bfin (cpu, pc + 4);
+      PARALLEL_GROUP = BFIN_PARALLEL_GROUP2;
       _interp_insn_bfin (cpu, pc + 6);
     }
   for (i = 0; i < BFIN_CPU_STATE.n_stores; i++)
This page took 0.049362 seconds and 4 git commands to generate.