2002-06-02 Chris Demetriou <cgd@broadcom.com>
authorChris Demetriou <cgd@google.com>
Sun, 2 Jun 2002 07:39:26 +0000 (07:39 +0000)
committerChris Demetriou <cgd@google.com>
Sun, 2 Jun 2002 07:39:26 +0000 (07:39 +0000)
            Ed Satterthwaite  <ehs@broadcom.com>

* mips.igen (mdmx): New (pseudo-)model.
* mdmx.c, mdmx.igen: New files.
* Makefile.in (SIM_OBJS): Add mdmx.o.
* sim-main.h (MDMX_accumulator, MX_fmtsel, signed24, signed48):
New typedefs.
(ACC, MX_Add, MX_AddA, MX_AddL, MX_And, MX_C_EQ, MX_C_LT, MX_Comp)
(MX_FMT_OB, MX_FMT_QH, MX_Max, MX_Min, MX_Msgn, MX_Mul, MX_MulA)
(MX_MulL, MX_MulS, MX_MulSL, MX_Nor, MX_Or, MX_Pick, MX_RAC)
(MX_RAC_H, MX_RAC_L, MX_RAC_M, MX_RNAS, MX_RNAU, MX_RND_AS)
(MX_RND_AU, MX_RND_ES, MX_RND_EU, MX_RND_ZS, MX_RND_ZU, MX_RNES)
(MX_RNEU, MX_RZS, MX_RZU, MX_SHFL, MX_ShiftLeftLogical)
(MX_ShiftRightArith, MX_ShiftRightLogical, MX_Sub, MX_SubA, MX_SubL)
(MX_VECT_ADD, MX_VECT_ADDA, MX_VECT_ADDL, MX_VECT_AND)
(MX_VECT_MAX, MX_VECT_MIN, MX_VECT_MSGN, MX_VECT_MUL, MX_VECT_MULA)
(MX_VECT_MULL, MX_VECT_MULS, MX_VECT_MULSL, MX_VECT_NOR)
(MX_VECT_OR, MX_VECT_SLL, MX_VECT_SRA, MX_VECT_SRL, MX_VECT_SUB)
(MX_VECT_SUBA, MX_VECT_SUBL, MX_VECT_XOR, MX_WACH, MX_WACL, MX_Xor)
(SIM_ARGS, SIM_STATE, UnpredictableResult, fmt_mdmx, ob_fmtsel)
(qh_fmtsel): New macros.
(_sim_cpu): New member "acc".
(mdmx_acc_op, mdmx_cc_op, mdmx_cpr_op, mdmx_pick_op, mdmx_rac_op)
(mdmx_round_op, mdmx_shuffle, mdmx_wach, mdmx_wacl): New functions.

sim/mips/ChangeLog
sim/mips/Makefile.in
sim/mips/mdmx.c [new file with mode: 0644]
sim/mips/mdmx.igen [new file with mode: 0644]
sim/mips/mips.igen
sim/mips/sim-main.h

index 388753966c5cca277a1cf389302f6f6bc0f09ba2..5de700fd8fb2f881f048ae2496b66a564bab56e4 100644 (file)
@@ -1,3 +1,29 @@
+2002-06-02  Chris Demetriou  <cgd@broadcom.com>
+            Ed Satterthwaite  <ehs@broadcom.com>
+
+       * mips.igen (mdmx): New (pseudo-)model.
+       * mdmx.c, mdmx.igen: New files.
+       * Makefile.in (SIM_OBJS): Add mdmx.o.
+       * sim-main.h (MDMX_accumulator, MX_fmtsel, signed24, signed48):
+       New typedefs.
+       (ACC, MX_Add, MX_AddA, MX_AddL, MX_And, MX_C_EQ, MX_C_LT, MX_Comp)
+       (MX_FMT_OB, MX_FMT_QH, MX_Max, MX_Min, MX_Msgn, MX_Mul, MX_MulA)
+       (MX_MulL, MX_MulS, MX_MulSL, MX_Nor, MX_Or, MX_Pick, MX_RAC)
+       (MX_RAC_H, MX_RAC_L, MX_RAC_M, MX_RNAS, MX_RNAU, MX_RND_AS)
+       (MX_RND_AU, MX_RND_ES, MX_RND_EU, MX_RND_ZS, MX_RND_ZU, MX_RNES)
+       (MX_RNEU, MX_RZS, MX_RZU, MX_SHFL, MX_ShiftLeftLogical)
+       (MX_ShiftRightArith, MX_ShiftRightLogical, MX_Sub, MX_SubA, MX_SubL)
+       (MX_VECT_ADD, MX_VECT_ADDA, MX_VECT_ADDL, MX_VECT_AND)
+       (MX_VECT_MAX, MX_VECT_MIN, MX_VECT_MSGN, MX_VECT_MUL, MX_VECT_MULA)
+       (MX_VECT_MULL, MX_VECT_MULS, MX_VECT_MULSL, MX_VECT_NOR)
+       (MX_VECT_OR, MX_VECT_SLL, MX_VECT_SRA, MX_VECT_SRL, MX_VECT_SUB)
+       (MX_VECT_SUBA, MX_VECT_SUBL, MX_VECT_XOR, MX_WACH, MX_WACL, MX_Xor)
+       (SIM_ARGS, SIM_STATE, UnpredictableResult, fmt_mdmx, ob_fmtsel)
+       (qh_fmtsel): New macros.
+       (_sim_cpu): New member "acc".
+       (mdmx_acc_op, mdmx_cc_op, mdmx_cpr_op, mdmx_pick_op, mdmx_rac_op)
+       (mdmx_round_op, mdmx_shuffle, mdmx_wach, mdmx_wacl): New functions.
+
 2002-05-01  Chris Demetriou  <cgd@broadcom.com>
 
        * interp.c: Use 'deprecated' rather than 'depreciated.'
index 5d0a3364e8fc8ccb8694b249fcbcde8baab52246..d95fbbc2b1c3d2e6c5daae6c752c2ff33590ac47 100644 (file)
@@ -43,6 +43,7 @@ SIM_OBJS = \
        $(MIPS_EXTRA_OBJS) \
        cp1.o \
        interp.o \
+       mdmx.o \
        sim-main.o \
        sim-hload.o \
        sim-engine.o \
@@ -71,6 +72,7 @@ SIM_RUN_OBJS = nrun.o
 interp.o: $(srcdir)/interp.c config.h sim-main.h itable.h
 cp1.o: $(srcdir)/cp1.c config.h sim-main.h
 
+mdmx.o: $(srcdir)/mdmx.c $(srcdir)/sim-main.h
 
 ../igen/igen:
        cd ../igen && $(MAKE)
diff --git a/sim/mips/mdmx.c b/sim/mips/mdmx.c
new file mode 100644 (file)
index 0000000..2b08922
--- /dev/null
@@ -0,0 +1,1449 @@
+/* Simulation code for the MIPS MDMX ASE.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   Contributed by Broadcom Corporation (SiByte).
+
+This file is part of GDB, the GNU debugger.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <stdio.h>
+
+#include "sim-main.h"
+
+/* Within mdmx.c we refer to the sim_cpu directly. */
+#define CPU cpu
+#define SD  (CPU_STATE(CPU))
+#define        SD_ cpu, cia, -1
+
+/* MDMX Representations
+
+   An 8-bit packed byte element (OB) is always unsigned.
+   The 24-bit accumulators are signed and are represented as 32-bit
+   signed values, which are reduced to 24-bit signed values prior to
+   Round and Clamp operations.
+  
+   A 16-bit packed halfword element (QH) is always signed.
+   The 48-bit accumulators are signed and are represented as 64-bit
+   signed values, which are reduced to 48-bit signed values prior to
+   Round and Clamp operations.
+  
+   The code below assumes a 2's-complement representation of signed
+   quantities.  Care is required to clear extended sign bits when
+   repacking fields.
+  
+   The code (and the code for arithmetic shifts in mips.igen) also makes
+   the (not guaranteed portable) assumption that right shifts of signed
+   quantities in C do sign extension.  */
+
+typedef unsigned64 unsigned48;
+#define MASK48 (UNSIGNED64 (0xffffffffffff))
+
+typedef unsigned32 unsigned24;
+#define MASK24 (UNSIGNED32 (0xffffff))
+
+typedef enum {
+  mdmx_ob,          /* OB (octal byte) */
+  mdmx_qh           /* QH (quad half-word) */
+} MX_fmt;
+
+typedef enum {
+  sel_elem,         /* element select */
+  sel_vect,         /* vector select */
+  sel_imm           /* immediate select */
+} VT_select;
+
+#define OB_MAX  ((unsigned8)0xFF)
+#define QH_MIN  ((signed16)0x8000)
+#define QH_MAX  ((signed16)0x7FFF)
+
+#define OB_CLAMP(x)  ((unsigned8)((x) > OB_MAX ? OB_MAX : (x)))
+#define QH_CLAMP(x)  ((signed16)((x) < QH_MIN ? QH_MIN : \
+                                ((x) > QH_MAX ? QH_MAX : (x))))
+
+#define MX_FMT(fmtsel) (((fmtsel) & 0x1) == 0 ? mdmx_ob : mdmx_qh)
+#define MX_VT(fmtsel)  (((fmtsel) & 0x10) == 0 ?    sel_elem : \
+                       (((fmtsel) & 0x18) == 0x10 ? sel_vect : sel_imm))
+
+#define QH_ELEM(v,fmtsel) \
+        ((signed16)(((v) >> (((fmtsel) & 0xC) << 2)) & 0xFFFF))
+#define OB_ELEM(v,fmtsel) \
+        ((unsigned8)(((v) >> (((fmtsel) & 0xE) << 2)) & 0xFF))
+
+
+typedef signed16 (*QH_FUNC)(signed16, signed16);
+typedef unsigned8 (*OB_FUNC)(unsigned8, unsigned8);
+
+/* vectorized logical operators */
+
+static signed16
+AndQH(signed16 ts, signed16 tt)
+{
+  return (signed16)((unsigned16)ts & (unsigned16)tt);
+}
+
+static unsigned8
+AndOB(unsigned8 ts, unsigned8 tt)
+{
+  return ts & tt;
+}
+
+static signed16
+NorQH(signed16 ts, signed16 tt)
+{
+  return (signed16)(((unsigned16)ts | (unsigned16)tt) ^ 0xFFFF);
+}
+
+static unsigned8
+NorOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts | tt) ^ 0xFF;
+}
+
+static signed16
+OrQH(signed16 ts, signed16 tt)
+{
+  return (signed16)((unsigned16)ts | (unsigned16)tt);
+}
+
+static unsigned8
+OrOB(unsigned8 ts, unsigned8 tt)
+{
+  return ts | tt;
+}
+
+static signed16
+XorQH(signed16 ts, signed16 tt)
+{
+  return (signed16)((unsigned16)ts ^ (unsigned16)tt);
+}
+
+static unsigned8
+XorOB(unsigned8 ts, unsigned8 tt)
+{
+  return ts ^ tt;
+}
+
+static signed16
+SLLQH(signed16 ts, signed16 tt)
+{
+  unsigned32 s = (unsigned32)tt & 0xF;
+  return (signed16)(((unsigned32)ts << s) & 0xFFFF);
+}
+
+static unsigned8
+SLLOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 s = tt & 0x7;
+  return (ts << s) & 0xFF;
+}
+
+static signed16
+SRLQH(signed16 ts, signed16 tt)
+{
+  unsigned32 s = (unsigned32)tt & 0xF;
+  return (signed16)((unsigned16)ts >> s);
+}
+
+static unsigned8
+SRLOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 s = tt & 0x7;
+  return ts >> s;
+}
+
+
+/* Vectorized arithmetic operators.  */
+
+static signed16
+AddQH(signed16 ts, signed16 tt)
+{
+  signed32 t = (signed32)ts + (signed32)tt;
+  return QH_CLAMP(t);
+}
+
+static unsigned8
+AddOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 t = (unsigned32)ts + (unsigned32)tt;
+  return OB_CLAMP(t);
+}
+
+static signed16
+SubQH(signed16 ts, signed16 tt)
+{
+  signed32 t = (signed32)ts - (signed32)tt;
+  return QH_CLAMP(t);
+}
+
+static unsigned8
+SubOB(unsigned8 ts, unsigned8 tt)
+{
+  signed32 t;
+  t = (signed32)ts - (signed32)tt;
+  if (t < 0)
+    t = 0;
+  return (unsigned8)t;
+}
+
+static signed16
+MinQH(signed16 ts, signed16 tt)
+{
+  return (ts < tt ? ts : tt);
+}
+
+static unsigned8
+MinOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts < tt ? ts : tt);
+}
+
+static signed16
+MaxQH(signed16 ts, signed16 tt)
+{
+  return (ts > tt ? ts : tt);
+}
+
+static unsigned8
+MaxOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts > tt ? ts : tt);
+}
+
+static signed16
+MulQH(signed16 ts, signed16 tt)
+{
+  signed32 t = (signed32)ts * (signed32)tt;
+  return QH_CLAMP(t);
+}
+
+static unsigned8
+MulOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 t = (unsigned32)ts * (unsigned32)tt;
+  return OB_CLAMP(t);
+}
+
+/* "msgn" and "sra" are defined only for QH format.  */
+
+static signed16
+MsgnQH(signed16 ts, signed16 tt)
+{
+  signed16 t;
+  if (ts < 0)
+    t = (tt == QH_MIN ? QH_MAX : -tt);
+  else if (ts == 0)
+    t = 0;
+  else
+    t = tt;
+  return t;
+}
+
+
+static signed16
+SRAQH(signed16 ts, signed16 tt)
+{
+  unsigned32 s = (unsigned32)tt & 0xF;
+  return (signed16)((signed32)ts >> s);
+}
+
+
+/* Dispatch tables for operations that update a CPR.  */
+
+static const QH_FUNC qh_func[] = {
+  AndQH,  NorQH,  OrQH,   XorQH, SLLQH, SRLQH,
+  AddQH,  SubQH,  MinQH,  MaxQH,
+  MulQH,  MsgnQH, SRAQH,  NULL,  NULL
+};
+
+static const OB_FUNC ob_func[] = {
+  AndOB,  NorOB,  OrOB,   XorOB, SLLOB, SRLOB,
+  AddOB,  SubOB,  MinOB,  MaxOB,
+  MulOB,  NULL,   NULL,   NULL, NULL
+};
+
+/* Auxiliary functions for CPR updates.  */
+
+/* Vector mapping for QH format.  */
+static unsigned64
+qh_vector_op(unsigned64 v1, unsigned64 v2, QH_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  signed16 h, h1, h2;
+
+  for (i = 0; i < 64; i += 16)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h2 = (signed16)(v2 & 0xFFFF);  v2 >>= 16;
+      h = (*func)(h1, h2);
+      result |= ((unsigned64)((unsigned16)h) << i);
+    }
+  return result;
+}
+
+static unsigned64
+qh_map_op(unsigned64 v1, signed16 h2, QH_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  signed16 h, h1;
+
+  for (i = 0; i < 64; i += 16)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h = (*func)(h1, h2);
+      result |= ((unsigned64)((unsigned16)h) << i);
+    }
+  return result;
+}
+
+
+/* Vector operations for OB format.  */
+
+static unsigned64
+ob_vector_op(unsigned64 v1, unsigned64 v2, OB_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  unsigned8 b, b1, b2;
+
+  for (i = 0; i < 64; i += 8)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      b = (*func)(b1, b2);
+      result |= ((unsigned64)b << i);
+    }
+  return result;
+}
+
+static unsigned64
+ob_map_op(unsigned64 v1, unsigned8 b2, OB_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  unsigned8 b, b1;
+
+  for (i = 0; i < 64; i += 8)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b = (*func)(b1, b2);
+      result |= ((unsigned64)b << i);
+    }
+  return result;
+}
+
+
+/* Primary entry for operations that update CPRs.  */
+unsigned64
+mdmx_cpr_op(sim_cpu *cpu,
+           address_word cia,
+           int op,
+           unsigned64 op1,
+           int vt,
+           MX_fmtsel fmtsel) 
+{
+  unsigned64 op2;
+  unsigned64 result = 0;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_map_op(op1, QH_ELEM(op2, fmtsel), qh_func[op]);
+         break;
+       case sel_vect:
+         result = qh_vector_op(op1, ValueFPR(vt, fmt_mdmx), qh_func[op]);
+         break;
+       case sel_imm:
+         result = qh_map_op(op1, vt, qh_func[op]);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_map_op(op1, OB_ELEM(op2, fmtsel), ob_func[op]);
+         break;
+       case sel_vect:
+         result = ob_vector_op(op1, ValueFPR(vt, fmt_mdmx), ob_func[op]);
+         break;
+       case sel_imm:
+         result = ob_map_op(op1, vt, ob_func[op]);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+
+  return result;
+}
+
+
+/* Operations that update CCs */
+
+static void
+qh_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond)
+{
+  int  i;
+  signed16 h1, h2;
+  int  boolean;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h2 = (signed16)(v2 & 0xFFFF);  v2 >>= 16;
+      boolean = ((cond & MX_C_EQ) && (h1 == h2)) ||
+       ((cond & MX_C_LT) && (h1 < h2));
+      SETFCC(i, boolean);
+    }
+}
+
+static void
+qh_map_test(sim_cpu *cpu, unsigned64 v1, signed16 h2, int cond)
+{
+  int  i;
+  signed16 h1;
+  int  boolean;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      boolean = ((cond & MX_C_EQ) && (h1 == h2)) ||
+       ((cond & MX_C_LT) && (h1 < h2));
+      SETFCC(i, boolean);
+    }
+}
+
+static void
+ob_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond)
+{
+  int  i;
+  unsigned8 b1, b2;
+  int  boolean;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      boolean = ((cond & MX_C_EQ) && (b1 == b2)) ||
+       ((cond & MX_C_LT) && (b1 < b2));
+      SETFCC(i, boolean);
+    }
+}
+
+static void
+ob_map_test(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int cond)
+{
+  int  i;
+  unsigned8 b1;
+  int  boolean;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = (unsigned8)(v1 & 0xFF);  v1 >>= 8;
+      boolean = ((cond & MX_C_EQ) && (b1 == b2)) ||
+       ((cond & MX_C_LT) && (b1 < b2));
+      SETFCC(i, boolean);
+    }
+}
+
+
+void
+mdmx_cc_op(sim_cpu *cpu,
+          address_word cia,
+          int cond,
+          unsigned64 v1,
+          int vt,
+          MX_fmtsel fmtsel)
+{
+  unsigned64 op2;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         qh_map_test(cpu, v1, QH_ELEM(op2, fmtsel), cond);
+         break;
+       case sel_vect:
+         qh_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond);
+         break;
+       case sel_imm:
+         qh_map_test(cpu, v1, vt, cond);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         ob_map_test(cpu, v1, OB_ELEM(op2, fmtsel), cond);
+         break;
+       case sel_vect:
+         ob_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond);
+         break;
+       case sel_imm:
+         ob_map_test(cpu, v1, vt, cond);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+
+/* Pick operations.  */
+
+static unsigned64
+qh_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned16 h;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      h = ((GETFCC(i) == tf) ? (v1 & 0xFFFF) : (v2 & 0xFFFF));
+      v1 >>= 16;  v2 >>= 16;
+      result |= ((unsigned64)h << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+qh_map_pick(sim_cpu *cpu, unsigned64 v1, signed16 h2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned16 h;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      h = (GETFCC(i) == tf) ? (v1 & 0xFFFF) : (unsigned16)h2;
+      v1 >>= 16;
+      result |= ((unsigned64)h << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+ob_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b = (GETFCC(i) == tf) ? (v1 & 0xFF) : (v2 & 0xFF);
+      v1 >>= 8;  v2 >>= 8;
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+static unsigned64
+ob_map_pick(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b = (GETFCC(i) == tf) ? (v1 & 0xFF) : b2;
+      v1 >>= 8;
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+
+unsigned64
+mdmx_pick_op(sim_cpu *cpu,
+            address_word cia,
+            int tf,
+            unsigned64 v1,
+            int vt,
+            MX_fmtsel fmtsel)
+{
+  unsigned64 result = 0;
+  unsigned64 op2;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_map_pick(cpu, v1, QH_ELEM(op2, fmtsel), tf);
+         break;
+       case sel_vect:
+         result = qh_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf);
+         break;
+       case sel_imm:
+         result = qh_map_pick(cpu, v1, vt, tf);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_map_pick(cpu, v1, OB_ELEM(op2, fmtsel), tf);
+         break;
+       case sel_vect:
+         result = ob_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf);
+         break;
+       case sel_imm:
+         result = ob_map_pick(cpu, v1, vt, tf);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+  return result;
+}
+
+
+/* Accumulators.  */
+
+typedef void (*QH_ACC)(signed48 *a, signed16 ts, signed16 tt);
+
+static void
+AccAddAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a += (signed48)ts + (signed48)tt;
+}
+
+static void
+AccAddLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a = (signed48)ts + (signed48)tt;
+}
+
+static void
+AccMulAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a += (signed48)ts * (signed48)tt;
+}
+
+static void
+AccMulLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a = (signed48)ts * (signed48)tt;
+}
+
+static void
+SubMulAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a -= (signed48)ts * (signed48)tt;
+}
+
+static void
+SubMulLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a = -((signed48)ts * (signed48)tt);
+}
+
+static void
+AccSubAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a += (signed48)ts - (signed48)tt;
+}
+
+static void
+AccSubLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a =  (signed48)ts - (signed48)tt;
+}
+
+
+typedef void (*OB_ACC)(signed24 *acc, unsigned8 ts, unsigned8 tt);
+
+static void
+AccAddAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a += (signed24)ts + (signed24)tt;
+}
+
+static void
+AccAddLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = (signed24)ts + (signed24)tt;
+}
+
+static void
+AccMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a += (signed24)ts * (signed24)tt;
+}
+
+static void
+AccMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = (signed24)ts * (signed24)tt;
+}
+
+static void
+SubMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a -= (signed24)ts * (signed24)tt;
+}
+
+static void
+SubMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = -((signed24)ts * (signed24)tt);
+}
+
+static void
+AccSubAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a += (signed24)ts - (signed24)tt;
+}
+
+static void
+AccSubLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = (signed24)ts - (signed24)tt;
+}
+
+
+/* Dispatch tables for operations that update a CPR.  */
+
+static const QH_ACC qh_acc[] = {
+  AccAddAQH, AccAddAQH, AccMulAQH, AccMulLQH,
+  SubMulAQH, SubMulLQH, AccSubAQH, AccSubLQH
+};
+
+static const OB_ACC ob_acc[] = {
+  AccAddAOB, AccAddLOB, AccMulAOB, AccMulLOB,
+  SubMulAOB, SubMulLOB, AccSubAOB, AccSubLOB
+};
+
+
+static void
+qh_vector_acc(signed48 a[], unsigned64 v1, unsigned64 v2, QH_ACC acc)
+{
+  int  i;
+  signed16 h1, h2;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h2 = (signed16)(v2 & 0xFFFF);  v2 >>= 16;
+      (*acc)(&a[i], h1, h2);
+    }
+}
+
+static void
+qh_map_acc(signed48 a[], unsigned64 v1, signed16 h2, QH_ACC acc)
+{
+  int  i;
+  signed16 h1;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      (*acc)(&a[i], h1, h2);
+    }
+}
+
+static void
+ob_vector_acc(signed24 a[], unsigned64 v1, unsigned64 v2, OB_ACC acc)
+{
+  int  i;
+  unsigned8  b1, b2;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      (*acc)(&a[i], b1, b2);
+    }
+}
+
+static void
+ob_map_acc(signed24 a[], unsigned64 v1, unsigned8 b2, OB_ACC acc)
+{
+  int  i;
+  unsigned8 b1;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      (*acc)(&a[i], b1, b2);
+    }
+}
+
+
+/* Primary entry for operations that accumulate */
+void
+mdmx_acc_op(sim_cpu *cpu,
+           address_word cia,
+           int op,
+           unsigned64 op1,
+           int vt,
+           MX_fmtsel fmtsel) 
+{
+  unsigned64 op2;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         qh_map_acc(ACC.qh, op1, QH_ELEM(op2, fmtsel), qh_acc[op]);
+         break;
+       case sel_vect:
+         qh_vector_acc(ACC.qh, op1, ValueFPR(vt, fmt_mdmx), qh_acc[op]);
+         break;
+       case sel_imm:
+         qh_map_acc(ACC.qh, op1, vt, qh_acc[op]);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         ob_map_acc(ACC.ob, op1, OB_ELEM(op2, fmtsel), ob_acc[op]);
+         break;
+       case sel_vect:
+         ob_vector_acc(ACC.ob, op1, ValueFPR(vt, fmt_mdmx), ob_acc[op]);
+         break;
+       case sel_imm:
+         ob_map_acc(ACC.ob, op1, op2, ob_acc[op]);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+
+/* Reading and writing accumulator (no conversion).  */
+
+unsigned64
+mdmx_rac_op(sim_cpu *cpu,
+           address_word cia,
+           int op,
+           int fmt) 
+{
+  unsigned64    result;
+  unsigned int  shift;
+  int           i;
+
+  shift = op;          /* L = 00, M = 01, H = 10.  */
+  result = 0;
+
+  switch (fmt)
+    {
+    case MX_FMT_QH:
+      shift <<= 4;              /* 16 bits per element.  */
+      for (i = 3; i >= 0; --i)
+       {
+         result <<= 16;
+         result |= ((ACC.qh[i] >> shift) & 0xFFFF);
+       }
+      break;
+    case MX_FMT_OB:
+      shift <<= 3;              /*  8 bits per element.  */
+      for (i = 7; i >= 0; --i)
+       {
+         result <<= 8;
+         result |= ((ACC.ob[i] >> shift) & 0xFF);
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+  return result;
+}
+
+void
+mdmx_wacl(sim_cpu *cpu,
+         address_word cia,
+         int fmt,
+         unsigned64 vs,
+         unsigned64 vt) 
+{
+  int           i;
+
+  switch (fmt)
+    {
+    case MX_FMT_QH:
+      for (i = 0; i < 4; i++)
+       {
+         signed32  s = (signed16)(vs & 0xFFFF);
+         ACC.qh[i] = ((signed48)s << 16) | (vt & 0xFFFF);
+         vs >>= 16;  vt >>= 16;
+       }
+      break;
+    case MX_FMT_OB:
+      for (i = 0; i < 8; i++)
+       {
+         signed16  s = (signed8)(vs & 0xFF);
+         ACC.ob[i] = ((signed24)s << 8) | (vt & 0xFF);
+         vs >>= 8;   vt >>= 8;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+void
+mdmx_wach(sim_cpu *cpu,
+         address_word cia,
+         int fmt,
+         unsigned64 vs)
+{
+  int           i;
+
+  switch (fmt)
+    {
+    case MX_FMT_QH:
+      for (i = 0; i < 4; i++)
+       {
+         signed32  s = (signed16)(vs & 0xFFFF);
+         ACC.qh[i] &= ~((signed48)0xFFFF << 32);
+         ACC.qh[i] |=  ((signed48)s << 32);
+         vs >>= 16;
+       }
+      break;
+    case MX_FMT_OB:
+      for (i = 0; i < 8; i++)
+       {
+         ACC.ob[i] &= ~((signed24)0xFF << 16);
+         ACC.ob[i] |=  ((signed24)(vs & 0xFF) << 16);
+         vs >>= 8;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+
+/* Reading and writing accumulator (rounding conversions).
+   Enumerating function guarantees s >= 0 for QH ops.  */
+
+typedef signed16 (*QH_ROUND)(signed48 a, signed16 s);
+
+#define QH_BIT(n)  ((unsigned48)1 << (n))
+#define QH_ONES(n) (((unsigned48)1 << (n))-1)
+
+static signed16
+RNASQH(signed48 a, signed16 s)
+{
+  signed48 t;
+  signed16 result = 0;
+
+  if (s > 48)
+    result = 0;
+  else
+    {
+      t = (a >> s);
+      if ((a & QH_BIT(47)) == 0)
+       {
+         if (s > 0 && ((a >> (s-1)) & 1) == 1)
+           t++;
+         if (t > QH_MAX)
+           t = QH_MAX;
+       }
+      else
+       {
+         if (s > 0 && ((a >> (s-1)) & 1) == 1)
+           {
+             if (s > 1 && ((unsigned48)a & QH_ONES(s-1)) != 0)
+               t++;
+           }
+         if (t < QH_MIN)
+           t = QH_MIN;
+       }
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RNAUQH(signed48 a, signed16 s)
+{
+  unsigned48 t;
+  signed16 result;
+
+  if (s > 48)
+    result = 0;
+  else if (s == 48)
+    result = ((unsigned48)a & MASK48) >> 47;
+  else
+    {
+      t = ((unsigned48)a & MASK48) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       t++;
+      if (t > 0xFFFF)
+       t = 0xFFFF;
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RNESQH(signed48 a, signed16 s)
+{
+  signed48 t;
+  signed16 result = 0;
+
+  if (s > 47)
+    result = 0;
+  else
+    {
+      t = (a >> s);
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       {
+         if (s == 1 || (a & QH_ONES(s-1)) == 0)
+           t += t & 1;
+         else
+           t += 1;
+       }
+      if ((a & QH_BIT(47)) == 0)
+       {
+         if (t > QH_MAX)
+           t = QH_MAX;
+       }
+      else
+       {
+         if (t < QH_MIN)
+           t = QH_MIN;
+       }
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RNEUQH(signed48 a, signed16 s)
+{
+  unsigned48 t;
+  signed16 result;
+
+  if (s > 48)
+    result = 0;
+  else if (s == 48)
+    result = ((unsigned48)a > QH_BIT(47) ? 1 : 0);
+  else
+    {
+      t = ((unsigned48)a & MASK48) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       {
+         if (s > 1 && (a & QH_ONES(s-1)) != 0)
+           t++;
+         else
+           t += t & 1;
+       }
+      if (t > 0xFFFF)
+       t = 0xFFFF;
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RZSQH(signed48 a, signed16 s)
+{
+  signed48 t;
+  signed16 result = 0;
+
+  if (s > 47)
+    result = 0;
+  else
+    {
+      t = (a >> s);
+      if ((a & QH_BIT(47)) == 0)
+       {
+         if (t > QH_MAX)
+           t = QH_MAX;
+       }
+      else
+       {
+         if (t < QH_MIN)
+           t = QH_MIN;
+       }
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RZUQH(signed48 a, signed16 s)
+{
+  unsigned48 t;
+  signed16 result = 0;
+
+  if (s > 48)
+    result = 0;
+  else if (s == 48)
+    result = ((unsigned48)a > QH_BIT(47) ? 1 : 0);
+  else
+    {
+      t = ((unsigned48)a & MASK48) >> s;
+      if (t > 0xFFFF)
+       t = 0xFFFF;
+      result = (signed16)t;
+    }
+  return result;
+}
+
+
+typedef unsigned8 (*OB_ROUND)(signed24 a, unsigned8 s);
+
+#define OB_BIT(n)  ((unsigned24)1 << (n))
+#define OB_ONES(n) (((unsigned24)1 << (n))-1)
+
+static unsigned8
+RNAUOB(signed24 a, unsigned8 s)
+{
+  unsigned8 result;
+  unsigned24 t;
+
+  if (s > 24)
+    result = 0;
+  else if (s == 24)
+    result = ((unsigned24)a & MASK24) >> 23;
+  else
+    {
+      t = ((unsigned24)a & MASK24) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       t ++;
+      result = OB_CLAMP(t);
+    }
+  return result;
+}
+
+static unsigned8
+RNEUOB(signed24 a, unsigned8 s)
+{
+  unsigned8 result;
+  unsigned24 t;
+
+  if (s > 24)
+    result = 0;
+  else if (s == 24)
+    result = (((unsigned24)a & MASK24) > OB_BIT(23) ? 1 : 0);
+  else
+    {
+      t = ((unsigned24)a & MASK24) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       {
+         if (s > 1 && (a & OB_ONES(s-1)) != 0)
+           t++;
+         else
+           t += t & 1;
+       }
+      result = OB_CLAMP(t);
+    }
+  return result;
+}
+
+static unsigned8
+RZUOB(signed24 a, unsigned8 s)
+{
+  unsigned8 result;
+  unsigned24 t;
+
+  if (s >= 24)
+    result = 0;
+  else
+    {
+      t = ((unsigned24)a & MASK24) >> s;
+      result = OB_CLAMP(t);
+    }
+  return result;
+}
+
+
+static const QH_ROUND qh_round[] = {
+  RNASQH, RNAUQH, RNESQH, RNEUQH, RZSQH,  RZUQH
+};
+
+static const OB_ROUND ob_round[] = {
+  NULL,   RNAUOB, NULL,   RNEUOB, NULL,   RZUOB
+};
+
+
+static unsigned64
+qh_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, QH_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  signed16 h, h2;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      h2 = (signed16)(v2 & 0xFFFF);
+      if (h2 >= 0)
+       h = (*round)(ACC.qh[i], h2);
+      else
+       {
+         UnpredictableResult ();
+         h = 0xdead;
+       }
+      v2 >>= 16;
+      result |= ((unsigned64)((unsigned16)h) << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+qh_map_round(sim_cpu *cpu, address_word cia, signed16 h2, QH_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  signed16  h;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      if (h2 >= 0)
+       h = (*round)(ACC.qh[i], h2);
+      else
+       {
+         UnpredictableResult ();
+         h = 0xdead;
+       }
+      result |= ((unsigned64)((unsigned16)h) << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+ob_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, OB_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b, b2;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      b = (*round)(ACC.ob[i], b2);
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+static unsigned64
+ob_map_round(sim_cpu *cpu, address_word cia, unsigned8 b2, OB_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b = (*round)(ACC.ob[i], b2);
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+
+unsigned64
+mdmx_round_op(sim_cpu *cpu,
+             address_word cia,
+             int rm,
+             int vt,
+             MX_fmtsel fmtsel) 
+{
+  unsigned64 op2;
+  unsigned64 result = 0;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_map_round(cpu, cia, QH_ELEM(op2, fmtsel), qh_round[rm]);
+         break;
+       case sel_vect:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_vector_round(cpu, cia, op2, qh_round[rm]);
+         break;
+       case sel_imm:
+         result = qh_map_round(cpu, cia, vt, qh_round[rm]);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_map_round(cpu, cia, OB_ELEM(op2, fmtsel), ob_round[rm]);
+         break;
+       case sel_vect:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_vector_round(cpu, cia, op2, ob_round[rm]);
+         break;
+       case sel_imm:
+         result = ob_map_round(cpu, cia, vt, ob_round[rm]);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+
+  return result;
+}
+
+
+/* Shuffle operation.  */
+
+typedef struct {
+  enum {vs, ss, vt} source;
+  unsigned int      index;
+} sh_map;
+
+static const sh_map ob_shuffle[][8] = {
+  /* MDMX 2.0 encodings (3-4, 6-7).  */
+  /* vr5400   encoding  (5), otherwise.  */
+  {                                                              }, /* RSVD */
+  {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* RSVD */
+  {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* RSVD */
+  {{vs,0}, {ss,0}, {vs,1}, {ss,1}, {vs,2}, {ss,2}, {vs,3}, {ss,3}}, /* upsl */
+  {{vt,1}, {vt,3}, {vt,5}, {vt,7}, {vs,1}, {vs,3}, {vs,5}, {vs,7}}, /* pach */
+  {{vt,0}, {vt,2}, {vt,4}, {vt,6}, {vs,0}, {vs,2}, {vs,4}, {vs,6}}, /* pacl */
+  {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* mixh */
+  {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}  /* mixl */
+};
+
+static const sh_map qh_shuffle[][4] = {
+  {{vt,2}, {vs,2}, {vt,3}, {vs,3}},  /* mixh */
+  {{vt,0}, {vs,0}, {vt,1}, {vs,1}},  /* mixl */
+  {{vt,1}, {vt,3}, {vs,1}, {vs,3}},  /* pach */
+  {                              },  /* RSVD */
+  {{vt,1}, {vs,0}, {vt,3}, {vs,2}},  /* bfla */
+  {                              },  /* RSVD */
+  {{vt,2}, {vt,3}, {vs,2}, {vs,3}},  /* repa */
+  {{vt,0}, {vt,1}, {vs,0}, {vs,1}}   /* repb */
+};
+
+
+unsigned64
+mdmx_shuffle(sim_cpu *cpu,
+            address_word cia,
+            int shop,
+            unsigned64 op1,
+            unsigned64 op2)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  int  op;
+
+  if ((shop & 0x3) == 0x1)       /* QH format.  */
+    {
+      op = shop >> 2;
+      s = 0;
+      for (i = 0; i < 4; i++)
+       {
+         unsigned64 v;
+
+         switch (qh_shuffle[op][i].source)
+           {
+           case vs:
+             v = op1;
+             break;
+           case vt:
+             v = op2;
+             break;
+           default:
+             Unpredictable ();
+             v = 0;
+           }
+         result |= (((v >> 16*qh_shuffle[op][i].index) & 0xFFFF) << s);
+         s += 16;
+       }
+    }
+  else if ((shop & 0x1) == 0x0)  /* OB format.  */
+    {
+      op = shop >> 1;
+      s = 0;
+      for (i = 0; i < 8; i++)
+       {
+         unsigned8 b;
+         unsigned int ishift = 8*ob_shuffle[op][i].index;
+
+         switch (ob_shuffle[op][i].source)
+           {
+           case vs:
+             b = (op1 >> ishift) & 0xFF;
+             break;
+           case ss:
+             b = ((op1 >> ishift) & 0x80) ? 0xFF : 0;
+             break;
+           case vt:
+             b = (op2 >> ishift) & 0xFF;
+             break;
+           default:
+             Unpredictable ();
+             b = 0;
+           }
+         result |= ((unsigned64)b << s);
+         s += 8;
+       }
+    }
+  else
+    Unpredictable ();
+
+  return result;
+}
diff --git a/sim/mips/mdmx.igen b/sim/mips/mdmx.igen
new file mode 100644 (file)
index 0000000..ddc075c
--- /dev/null
@@ -0,0 +1,550 @@
+// -*- C -*-
+
+// Simulator definition for the MIPS MDMX ASE.
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Broadcom Corporation (SiByte).
+//
+// This file is part of GDB, the GNU debugger.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+//  Reference: MIPS64 Architecture Volume IV-b:
+//             The MDMX Application-Specific Extension
+
+//  Notes on "format selectors" (FMTSEL):
+//
+//   A selector with final bit 0 indicates OB format.
+//   A selector with final bits 01 indicates QH format.
+//   A selector with final bits 11 has UNPREDICTABLE result per the spec.
+//
+//  Similarly, for the single-bit fields which differentiate between
+//  formats (FMTOP), 0 is OB format and 1 is QH format.
+
+
+// Helper:
+//
+// Check whether MDMX is usable, and if not signal an appropriate exception.
+//
+
+:function:::void:check_mdmx:instruction_word insn
+*mdmx:
+{
+  if (! COP_Usable (1))
+    SignalExceptionCoProcessorUnusable (1);
+  if ((SR & (status_MX|status_FR)) != (status_MX|status_FR))
+    SignalExceptionMDMX ();
+  check_u64 (SD_, insn);
+}
+
+
+// Helper:
+//
+// Check whether a given MDMX format selector indicates a valid and usable
+// format, and if not signal an appropriate exception.
+//
+
+:function:::int:check_mdmx_fmtsel:instruction_word insn, int fmtsel
+*mdmx:
+{
+  switch (fmtsel & 0x03)
+    {
+    case 0x00:     /* ob */
+    case 0x02:
+    case 0x01:     /* qh */
+      return 1;
+    case 0x03:     /* UNPREDICTABLE */
+      SignalException (ReservedInstruction, insn);
+      return 0;
+    }
+  return 0;
+}
+
+
+// Helper:
+//
+// Check whether a given MDMX format bit indicates a valid and usable
+// format, and if not signal an appropriate exception.
+//
+
+:function:::int:check_mdmx_fmtop:instruction_word insn, int fmtop
+*mdmx:
+{
+  switch (fmtop & 0x01)
+    {
+    case 0x00:     /* ob */
+    case 0x01:     /* qh */
+      return 1;
+    }
+  return 0;
+}
+
+
+:%s::::FMTSEL:int fmtsel
+*mdmx:
+{
+  if ((fmtsel & 0x1) == 0)
+    return "ob";
+  else if ((fmtsel & 0x3) == 1)
+    return "qh";
+  else
+    return "?";
+}
+
+
+:%s::::FMTOP:int fmtop
+*mdmx:
+{
+  switch (fmtop)
+    {
+    case 0: return "ob";
+    case 1: return "qh";
+    default: return "?";
+    }
+}
+
+
+:%s::::SHOP:int shop
+*mdmx:
+{
+  if ((shop & 0x11) == 0x00)
+    switch ((shop >> 1) & 0x07)
+      {
+      case 3:  return "upsl.ob";
+      case 4:  return "pach.ob";
+      case 6:  return "mixh.ob";
+      case 7:  return "mixl.ob";
+      default: return "?";
+      }
+  else if ((shop & 0x03) == 0x01)
+    switch ((shop >> 2) & 0x07)
+      {
+      case 0:  return "mixh.qh";
+      case 1:  return "mixl.qh";
+      case 2:  return "pach.qh";
+      case 4:  return "bfla.qh";
+      case 6:  return "repa.qh";
+      case 7:  return "repb.qh";
+      default: return "?";
+      }
+  else
+    return "?";
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001011:MDMX:64::ADD.fmt
+"add.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Add(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110111:MDMX:64::ADDA.fmt
+"adda.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_AddA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110111:MDMX:64::ADDL.fmt
+"addl.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_AddL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,00,3.IMM,5.VT,5.VS,5.VD,0110,1.FMTOP,0:MDMX:64::ALNI.fmt
+"alni.%s<FMTOP> v<VD>, v<VS>, v<VT>, <IMM>"
+*mdmx:
+{
+  unsigned64 result;
+  int s;
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  s = (IMM << 3);
+  result = ValueFPR(VS,fmt_mdmx) << s;
+  if (s != 0)  // x86 gcc treats >> 64 as >> 0
+    result |= ValueFPR(VT,fmt_mdmx) >> (64 - s);
+  StoreFPR(VD,fmt_mdmx,result);
+}
+
+
+011110,5.RS,5.VT,5.VS,5.VD,0110,1.FMTOP,1:MDMX:64::ALNV.fmt
+"alnv.%s<FMTOP> v<VD>, v<VS>, v<VT>, r<RS>"
+*mdmx:
+{
+  unsigned64 result;
+  int s;
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  s = ((GPR[RS] & 0x7) << 3);
+  result = ValueFPR(VS,fmt_mdmx) << s;
+  if (s != 0)  // x86 gcc treats >> 64 as >> 0
+    result |= ValueFPR(VT,fmt_mdmx) >> (64 - s);
+  StoreFPR(VD,fmt_mdmx,result);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001100:MDMX:64::AND.fmt
+"and.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_And(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,000001:MDMX:64::C.EQ.fmt
+"c.eq.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_EQ,VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,000101:MDMX:64::C.LE.fmt
+"c.le.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_LT|MX_C_EQ,VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,000100:MDMX:64::C.LT.fmt
+"c.lt.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_LT,VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000111:MDMX:64::MAX.fmt
+"max.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Max(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000110:MDMX:64::MIN.fmt
+"min.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Min(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,5.VS,5.VD,000000:MDMX:64::MSGN.QH
+"msgn.qh v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_Msgn(ValueFPR(VS,fmt_mdmx),VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,110000:MDMX:64::MUL.fmt
+"mul.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Mul(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110011:MDMX:64::MULA.fmt
+"mula.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110011:MDMX:64::MULL.fmt
+"mull.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110010:MDMX:64::MULS.fmt
+"muls.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulS(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110010:MDMX:64::MULSL.fmt
+"mulsl.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulSL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001111:MDMX:64::NOR.fmt
+"nor.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Nor(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001110:MDMX:64::OR.fmt
+"or.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Or(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000010:MDMX:64::PICKF.fmt
+"pickf.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Pick(0,ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000011:MDMX:64::PICKT.fmt
+"pickt.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Pick(1,ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,1000,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACH.fmt
+"rach.%s<FMTOP> v<VD>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_H,FMTOP));
+}
+
+
+011110,0000,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACL.fmt
+"racl.%s<FMTOP> v<VD>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_L,FMTOP));
+}
+
+
+011110,0100,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACM.fmt
+"racm.%s<FMTOP> v<VD>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_M,FMTOP));
+}
+
+
+011110,3.SEL,01,5.VT,00000,5.VD,100101:MDMX:64::RNAS.QH
+"rnas.qh v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_RNAS(VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,00000,5.VD,100001:MDMX:64::RNAU.fmt
+"rnau.%s<FMTSEL> v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_RNAU(VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,00000,5.VD,100110:MDMX:64::RNES.QH
+"rnes.qh v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_RNES(VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,00000,5.VD,100010:MDMX:64::RNEU.fmt
+"rneu.%s<FMTSEL> v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_RNEU(VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,00000,5.VD,100100:MDMX:64::RZS.QH
+"rzs.qh v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_RZS(VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,00000,5.VD,100000:MDMX:64::RZU.fmt
+"rzu.%s<FMTSEL> v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_RZU(VT,FMTSEL));
+}
+
+
+011110,5.SHOP,5.VT,5.VS,5.VD,011111:MDMX:64::SHFL.op.fmt
+"shfl.%s<SHOP> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, SHOP))
+    StoreFPR(VD,fmt_mdmx,MX_SHFL(SHOP,ValueFPR(VS,fmt_mdmx),ValueFPR(VT,fmt_mdmx)));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,010000:MDMX:64::SLL.fmt
+"sll.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_ShiftLeftLogical(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,5.VS,5.VD,010011:MDMX:64::SRA.QH
+"sra.qh v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_ShiftRightArith(ValueFPR(VS,fmt_mdmx),VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,010010:MDMX:64::SRL.fmt
+"srl.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_ShiftRightLogical(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001010:MDMX:64::SUB.fmt
+"sub.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Sub(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110110:MDMX:64::SUBA.fmt
+"suba.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_SubA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110110:MDMX:64::SUBL.fmt
+"subl.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_SubL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,1000,1.FMTOP,00000,5.VS,00000,111110:MDMX:64::WACH.fmt
+"wach.%s<FMTOP> v<VS>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  MX_WACH(FMTOP,ValueFPR(VS,fmt_mdmx));
+}
+
+
+011110,0000,1.FMTOP,5.VT,5.VS,00000,111110:MDMX:64::WACL.fmt
+"wacl.%s<FMTOP> v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  MX_WACL(FMTOP,ValueFPR(VS,fmt_mdmx),ValueFPR(VT,fmt_mdmx));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001101:MDMX:64::XOR.fmt
+"xor.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Xor(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
index cd96766d88528164752dbdcba0012e51b2e6aee7..5416f068228a5fef20be12cb586eca87111710e7 100644 (file)
@@ -61,7 +61,9 @@
 //  MIPS Application Specific Extensions (ASEs)
 //
 //  Instructions for the ASEs are in separate .igen files.
+//  ASEs add instructions on to a base ISA.
 :model:::mips16:mips16:                        // m16.igen (and m16.dc)
+:model:::mdmx:mdmx:                    // mdmx.igen
 
 
 // Pseudo instructions known by IGEN
 
 \f
 :include:::m16.igen
+:include:::mdmx.igen
 :include:::tx.igen
 :include:::vr.igen
 \f
index bcdcd80e3fdcfc0a1ebf71c9d5b8bf2669f1f370..08d2e608b4e7d707aea75ffb7e6edbc6092e316c 100644 (file)
@@ -296,6 +296,24 @@ enum float_operation
   };
 
 
+/* The internal representation of an MDMX accumulator. 
+   Note that 24 and 48 bit accumulator elements are represented in
+   32 or 64 bits.  Since the accumulators are 2's complement with
+   overflow suppressed, high-order bits can be ignored in most contexts.  */
+
+typedef signed32 signed24;
+typedef signed64 signed48;
+
+typedef union { 
+  signed24  ob[8];
+  signed48  qh[4]; 
+} MDMX_accumulator;
+
+
+/* Conventional system arguments.  */ 
+#define SIM_STATE  sim_cpu *cpu, address_word cia
+#define SIM_ARGS   CPU, cia
+
 struct _sim_cpu {
 
 
@@ -439,6 +457,10 @@ struct _sim_cpu {
 
   pending_write_queue pending;
 
+  /* The MDMX accumulator (used only for MDMX ASE).  */
+  MDMX_accumulator acc; 
+#define ACC             ((CPU)->acc)
+
   /* LLBIT = Load-Linked bit. A bit of "virtual" state used by atomic
      read-write instructions. It is set when a linked load occurs. It
      is tested and cleared by the conditional store. It is cleared
@@ -707,6 +729,107 @@ decode_coproc (SD, CPU, cia, (instruction))
 int sim_monitor (SIM_DESC sd, sim_cpu *cpu, address_word cia, unsigned int arg);
   
 
+/* MDMX access.  */
+
+typedef unsigned int MX_fmtsel;   /* MDMX format select field (5 bits).  */
+#define ob_fmtsel(sel) (((sel)<<1)|0x0)
+#define qh_fmtsel(sel) (((sel)<<2)|0x1)
+
+#define fmt_mdmx fmt_uninterpreted
+
+#define MX_VECT_AND  (0)
+#define MX_VECT_NOR  (1)
+#define MX_VECT_OR   (2)
+#define MX_VECT_XOR  (3)
+#define MX_VECT_SLL  (4)
+#define MX_VECT_SRL  (5)
+
+#define MX_VECT_ADD  (6)
+#define MX_VECT_SUB  (7)
+#define MX_VECT_MIN  (8)
+#define MX_VECT_MAX  (9)
+#define MX_VECT_MUL  (10)
+#define MX_VECT_MSGN (11)
+#define MX_VECT_SRA  (12)
+
+unsigned64 mdmx_cpr_op (SIM_STATE, int op, unsigned64 op1, int vt, MX_fmtsel fmtsel);
+#define MX_Add(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_ADD, op1, vt, fmtsel)
+#define MX_And(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_AND, op1, vt, fmtsel)
+#define MX_Max(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MAX, op1, vt, fmtsel)
+#define MX_Min(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MIN, op1, vt, fmtsel)
+#define MX_Msgn(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MSGN, op1, vt, fmtsel)
+#define MX_Mul(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_MUL, op1, vt, fmtsel)
+#define MX_Nor(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_NOR, op1, vt, fmtsel)
+#define MX_Or(op1,vt,fmtsel)  mdmx_cpr_op(SIM_ARGS, MX_VECT_OR,  op1, vt, fmtsel)
+#define MX_ShiftLeftLogical(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SLL, op1, vt, fmtsel)
+#define MX_ShiftRightArith(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SRA, op1, vt, fmtsel)
+#define MX_ShiftRightLogical(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SRL, op1, vt, fmtsel)
+#define MX_Sub(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_SUB, op1, vt, fmtsel)
+#define MX_Xor(op1,vt,fmtsel) mdmx_cpr_op(SIM_ARGS, MX_VECT_XOR, op1, vt, fmtsel)
+
+#define MX_C_EQ  0x1
+#define MX_C_LT  0x4
+
+void mdmx_cc_op (SIM_STATE, int cond, unsigned64 op1, int vt, MX_fmtsel fmtsel);
+#define MX_Comp(op1,cond,vt,fmtsel) mdmx_cc_op(SIM_ARGS, cond, op1, vt, fmtsel)
+
+unsigned64 mdmx_pick_op (SIM_STATE, int tf, unsigned64 op1, int vt, MX_fmtsel fmtsel);
+#define MX_Pick(tf,op1,vt,fmtsel) mdmx_pick_op(SIM_ARGS, tf, op1, vt, fmtsel)
+
+#define MX_VECT_ADDA  (0)
+#define MX_VECT_ADDL  (1)
+#define MX_VECT_MULA  (2)
+#define MX_VECT_MULL  (3)
+#define MX_VECT_MULS  (4)
+#define MX_VECT_MULSL (5)
+#define MX_VECT_SUBA  (6)
+#define MX_VECT_SUBL  (7)
+
+void mdmx_acc_op (SIM_STATE, int op, unsigned64 op1, int vt, MX_fmtsel fmtsel);
+#define MX_AddA(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_ADDA, op1, vt, fmtsel)
+#define MX_AddL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_ADDL, op1, vt, fmtsel)
+#define MX_MulA(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULA, op1, vt, fmtsel)
+#define MX_MulL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULL, op1, vt, fmtsel)
+#define MX_MulS(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULS, op1, vt, fmtsel)
+#define MX_MulSL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_MULSL, op1, vt, fmtsel)
+#define MX_SubA(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_SUBA, op1, vt, fmtsel)
+#define MX_SubL(op1,vt,fmtsel) mdmx_acc_op(SIM_ARGS, MX_VECT_SUBL, op1, vt, fmtsel)
+
+#define MX_FMT_OB   (0)
+#define MX_FMT_QH   (1)
+
+/* The following codes chosen to indicate the units of shift.  */
+#define MX_RAC_L    (0)
+#define MX_RAC_M    (1)
+#define MX_RAC_H    (2)
+
+unsigned64 mdmx_rac_op (SIM_STATE, int, int);
+#define MX_RAC(op,fmt) mdmx_rac_op(SIM_ARGS, op, fmt)
+
+void mdmx_wacl (SIM_STATE, int, unsigned64, unsigned64);
+#define MX_WACL(fmt,vs,vt) mdmx_wacl(SIM_ARGS, fmt, vs, vt)
+void mdmx_wach (SIM_STATE, int, unsigned64);
+#define MX_WACH(fmt,vs) mdmx_wach(SIM_ARGS, fmt, vs)
+
+#define MX_RND_AS   (0)
+#define MX_RND_AU   (1)
+#define MX_RND_ES   (2)
+#define MX_RND_EU   (3)
+#define MX_RND_ZS   (4)
+#define MX_RND_ZU   (5)
+
+unsigned64 mdmx_round_op (SIM_STATE, int, int, MX_fmtsel);
+#define MX_RNAS(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_AS, vt, fmt)
+#define MX_RNAU(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_AU, vt, fmt)
+#define MX_RNES(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_ES, vt, fmt)
+#define MX_RNEU(vt,fmt) mdmx_round_op(SIM_ARGS, MX_RND_EU, vt, fmt)
+#define MX_RZS(vt,fmt)  mdmx_round_op(SIM_ARGS, MX_RND_ZS, vt, fmt)
+#define MX_RZU(vt,fmt)  mdmx_round_op(SIM_ARGS, MX_RND_ZU, vt, fmt)
+
+unsigned64 mdmx_shuffle (SIM_STATE, int, unsigned64, unsigned64);
+#define MX_SHFL(shop,op1,op2) mdmx_shuffle(SIM_ARGS, shop, op1, op2)
+
+
 
 /* Memory accesses */
 
@@ -774,6 +897,7 @@ prefetch (SD, CPU, cia, CCA, pAddr, vAddr, DATA, hint)
 void unpredictable_action (sim_cpu *cpu, address_word cia);
 #define NotWordValue(val)      not_word_value (SD_, (val))
 #define Unpredictable()                unpredictable (SD_)
+#define UnpredictableResult()  /* For now, do nothing.  */
 
 INLINE_SIM_MAIN (unsigned32) ifetch32 PARAMS ((SIM_DESC sd, sim_cpu *cpu, address_word cia, address_word vaddr));
 #define IMEM32(CIA) ifetch32 (SD, CPU, (CIA), (CIA))