snapshot, upper opcode table done, modulo testing
authorDoug Evans <dje@google.com>
Wed, 14 Jan 1998 20:13:07 +0000 (20:13 +0000)
committerDoug Evans <dje@google.com>
Wed, 14 Jan 1998 20:13:07 +0000 (20:13 +0000)
opcodes/txvu-opc.c

index 8a7e12eabb7baa29193519538cf4a5bec134709b..bd64df53f643f980a69696fce2cbf4797b1aa476 100644 (file)
@@ -57,7 +57,18 @@ PRINT_FN (dotdest);
 PARSE_FN (vfreg);
 PRINT_FN (vfreg);
 
-/* Various types of ARC operands, including insn suffixes.
+PARSE_FN (bc);
+PRINT_FN (bc);
+
+PARSE_FN (ftregbc);
+PRINT_FN (ftregbc);
+
+PARSE_FN (accdest);
+PRINT_FN (accdest);
+
+PARSE_FN (xyz);
+
+/* Various types of TXVU operands, including insn suffixes.
 
    Fields are:
 
@@ -68,37 +79,95 @@ PRINT_FN (vfreg);
 
 const struct txvu_operand txvu_operands[] =
 {
-/* place holder (??? not sure if needed) */
+  /* place holder (??? not sure if needed) */
 #define UNUSED 128
   { 0 },
 
-/* Destination indicator, with leading '.'.  */
+  /* Destination indicator, with leading '.'.  */
 #define DOTDEST (UNUSED + 1)
   { 4, TXVU_SHIFT_DEST, TXVU_OPERAND_SUFFIX,
       parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest },
 
-/* ft reg */
+  /* ft reg */
 #define FTREG (DOTDEST + 1)
   { 5, TXVU_SHIFT_FTREG, 0, parse_vfreg, 0, 0, print_vfreg },
 
-/* fs reg */
+  /* fs reg */
 #define FSREG (FTREG + 1)
   { 5, TXVU_SHIFT_FSREG, 0, parse_vfreg, 0, 0, print_vfreg },
 
-/* fd reg */
+  /* fd reg */
 #define FDREG (FSREG + 1)
   { 5, TXVU_SHIFT_FDREG, 0, parse_vfreg, 0, 0, print_vfreg },
 
+  /* broadcast */
+#define BC (FDREG + 1)
+  { 2, 0, 0, parse_bc, 0, 0, print_bc },
+
+  /* ftreg in broadcast case */
+#define FTREGBC (BC + 1)
+  { 5, TXVU_SHIFT_FTREG, 0, parse_ftregbc, 0, 0, print_ftregbc },
+
+  /* accumulator dest */
+#define ACCDEST (FTREGBC + 1)
+  { 0, 0, TXVU_OPERAND_FAKE, parse_accdest, 0, 0, print_accdest },
+
+  /* The XYZ operand is a fake one that is used to ensure only "xyz" is
+     specified.  It simplifies the opmula and opmsub entries.  */
+#define XYZ (FDREG + 1)
+  { 0, 0, TXVU_OPERAND_FAKE, parse_xyz, 0, 0, 0 },
+
 /* end of list place holder */
   { 0 }
 };
 \f
 /* Macros to put a field's value into the right place.  */
-#define FT(x) (((x) & TXVU_MASK_VFREG) << TXVU_SHIFT_FTREG)
-#define FS(x) (((x) & TXVU_MASK_VFREG) << TXVU_SHIFT_FSREG)
-#define FD(x) (((x) & TXVU_MASK_VFREG) << TXVU_SHIFT_FDREG)
+/* FIXME: If assembler needs these, move to opcode/txvu.h.  */
+
 #define R(x,b,m) (((x) & (m)) << (b))  /* value X, mask M, at bit B */
 
+/* Upper Flag bits.  */
+#define UF(x) R ((x), 27, 31)
+/* Upper REServed two bits next to flag bits.  */
+#define URES(x) R ((x), 25, 3)
+/* The DEST field.  */
+#define UDEST(x) R ((x), 21, 15)
+/* The FT reg field.  */
+#define UFT(x) R ((x), TXVU_SHIFT_FTREG, TXVU_MASK_VFREG)
+/* The FS reg field.  */
+#define UFS(x) R ((x), TXVU_SHIFT_FSREG, TXVU_MASK_VFREG)
+/* The FD reg field.  */
+#define UFD(x) R ((x), TXVU_SHIFT_FDREG, TXVU_MASK_VFREG)
+/* The 4 bit opcode field.  */
+#define UOP4(x) R ((x), 2, 15)
+/* The 6 bit opcode field.  */
+#define UOP6(x) R ((x), 0, 63)
+/* The 9 bit opcode field.  */
+#define UOP9(x) R ((x), 2, 0x1ff)
+/* The 11 bit opcode field.  */
+#define UOP11(x) R ((x), 0, 0x7ff)
+/* The BroadCast field.  */
+#define UBC(x) R ((x), 0, 3)
+
+/* Macros for special field values.  */
+/* The upper 7 bits of the upper word.  */
+#define UUBITS (UF (0) + URES (0))
+/* Mask for UBITS.  */
+#define MUUBITS (UF (~0) + URES (~0))
+/* Mask for URES.  */
+#define MURES URES (~0)
+/* Mask for OP4.  */
+#define MUOP4 UOP4 (~0)
+/* Mask for OP6.  */
+#define MUOP6 UOP6 (~0)
+/* Mask for OP9.  */
+#define MUOP9 UOP9 (~0)
+/* Mask for OP11.  */
+#define MUOP11 UOP11 (~0)
+
+/* A space, separates instruction name (mnemonic + mnemonic operands) from operands.  */
+#define SP ' '
+
 /* TXVU instructions.
    [??? some of these comments are left over from the ARC port from which
    this code is borrowed, delete in time]
@@ -128,10 +197,67 @@ struct txvu_opcode txvu_upper_opcodes[] = {
   /* Macros appear first.  */
   /* ??? Any aliases?  */
 
-  /* The rest of these needn't be sorted, but it helps to find them if they
-     are.  */
-  { "abs", { DOTDEST, ' ', FTREG, FSREG }, 0xfe0001ff, 0x1fd, 0 },
-  { "add", { DOTDEST, ' ', FDREG, FSREG, FTREG }, 0xfe00003f, 0x28, 0 },
+  /* The rest of these needn't be sorted, but it helps to find them if they are.  */
+  { "abs", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x1fd) },
+  { "add", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x28) },
+  { "addi", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x22) },
+  { "addq", { DOTDEST, SP, FDREG, FSREG, 'q' }, MURES + UFT (~0) + MUOP6, UOP6 (0x20) },
+  { "add", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + UOP4 (~0), UOP4 (0) },
+  { "adda", { DOTDEST, SP, ACCDEST, FSREG, FTREG }, MURES + MUOP11, UOP11 (0x2bc) },
+  { "addai", { DOTDEST, SP, ACCDEST, FSREG, 'i' }, MURES + UFT (~0) + MUOP11, UOP11 (0x23e) },
+  { "addaq", { DOTDEST, SP, ACCDEST, FSREG, 'q' }, MURES + UFT (~0) + MUOP11, UOP11 (0x23c) },
+  { "adda", { BC, DOTDEST, SP, ACCDEST, FSREG, FTREGBC }, MURES + MUOP9, UOP9 (0xf) },
+  { "clip", { DOTDEST, SP, FSREG }, MURES + UDEST (~0) + UFT (~0) + MUOP11, UDEST (0xf) + UOP11 (0x1ff) },
+  { "ftoi0", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x17c) },
+  { "ftoi4", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x17d) },
+  { "ftoi12", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x17e) },
+  { "ftoi15", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x17f) },
+  { "itof0", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x13c) },
+  { "itof4", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x13d) },
+  { "itof12", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x13e) },
+  { "itof15", { DOTDEST, SP, FTREG, FSREG }, MURES + MUOP11, UOP11 (0x13f) },
+  { "madd", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x29) },
+  { "maddi", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x23) },
+  { "maddq", { DOTDEST, SP, FDREG, FSREG, 'q' }, MURES + UFT (~0) + MUOP6, UOP6 (0x21) },
+  { "madd", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + MUOP4, UOP4 (0x2) },
+  { "madda", { DOTDEST, SP, ACCDEST, FSREG, FTREG }, MURES + MUOP11, UOP11 (0x2bd) },
+  { "maddai", { DOTDEST, SP, ACCDEST, FSREG, 'i' }, MURES + UFT (~0) + MUOP11, UOP11 (0x23f) },
+  { "maddaq", { DOTDEST, SP, ACCDEST, FSREG, 'q' }, MURES + UFT (~0) + MUOP11, UOP11 (0x23d) },
+  { "madda", { BC, DOTDEST, SP, ACCDEST, FSREG, FTREGBC }, MURES + MUOP9, UOP9 (0x2f) },
+  { "max", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x2b) },
+  { "maxi", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x2d) },
+  { "max", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + MUOP4, UOP4 (0x4) },
+  /* FIXME: mini or min? */
+  { "mini", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x2f) },
+  { "mini", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x1f) },
+  { "mini", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + MUOP4, UOP4 (0x5) },
+  { "msub", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x2d) },
+  { "msubi", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x27) },
+  { "msubq", { DOTDEST, SP, FDREG, FSREG, 'q' }, MURES + UFT (~0) + MUOP6, UOP6 (0x25) },
+  { "msub", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + MUOP4, UOP4 (0x3) },
+  { "msuba", { DOTDEST, SP, ACCDEST, FSREG, FTREG }, MURES + MUOP11, UOP11 (0x2fd) },
+  { "msubai", { DOTDEST, SP, ACCDEST, FSREG, 'i' }, MURES + UFT (~0) + MUOP11, UOP11 (0x27f) },
+  { "msubaq", { DOTDEST, SP, ACCDEST, FSREG, 'q' }, MURES + UFT (~0) + MUOP11, UOP11 (0x27d) },
+  { "msuba", { BC, DOTDEST, SP, ACCDEST, FSREG, FTREGBC }, MURES + MUOP9, UOP9 (0x3f) },
+  { "mul", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x2a) },
+  { "muli", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x1e) },
+  { "mulq", { DOTDEST, SP, FDREG, FSREG, 'q' }, MURES + UFT (~0) + MUOP6, UOP6 (0x1c) },
+  { "mul", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + UOP4 (~0), UOP4 (6) },
+  { "mula", { DOTDEST, SP, ACCDEST, FSREG, FTREG }, MURES + MUOP11, UOP11 (0x2be) },
+  { "mulai", { DOTDEST, SP, ACCDEST, FSREG, 'i' }, MURES + UFT (~0) + MUOP11, UOP11 (0x1fe) },
+  { "mulaq", { DOTDEST, SP, ACCDEST, FSREG, 'q' }, MURES + UFT (~0) + MUOP11, UOP11 (0x1fc) },
+  { "mula", { BC, DOTDEST, SP, ACCDEST, FSREG, FTREGBC }, MURES + MUOP9, UOP9 (0x6f) },
+  { "nop", { 0 }, MURES + UDEST (~0) + UFT (~0) + UFS (~0) + MUOP11, UOP11 (0x2ff) },
+  { "opmula", { DOTDEST, SP, ACCDEST, FSREG, FTREG, XYZ }, MURES + MUOP11, UOP11 (0x2fe) },
+  { "opmsub", { DOTDEST, SP, FDREG, FSREG, FTREG, XYZ }, MURES + MUOP6, UOP6 (0x2e) },
+  { "sub", { DOTDEST, SP, FDREG, FSREG, FTREG }, MURES + MUOP6, UOP6 (0x2c) },
+  { "subi", { DOTDEST, SP, FDREG, FSREG, 'i' }, MURES + UFT (~0) + MUOP6, UOP6 (0x26) },
+  { "subq", { DOTDEST, SP, FDREG, FSREG, 'q' }, MURES + UFT (~0) + MUOP6, UOP6 (0x24) },
+  { "sub", { BC, DOTDEST, SP, FDREG, FSREG, FTREGBC }, MURES + UOP4 (~0), UOP4 (1) },
+  { "suba", { DOTDEST, SP, ACCDEST, FSREG, FTREG }, MURES + MUOP11, UOP11 (0x2fc) },
+  { "subai", { DOTDEST, SP, ACCDEST, FSREG, 'i' }, MURES + UFT (~0) + MUOP11, UOP11 (0x27e) },
+  { "subaq", { DOTDEST, SP, ACCDEST, FSREG, 'q' }, MURES + UFT (~0) + MUOP11, UOP11 (0x27c) },
+  { "suba", { BC, DOTDEST, SP, ACCDEST, FSREG, FTREGBC }, MURES + MUOP9, UOP9 (0x1f) }
 };
 const int txvu_upper_opcodes_count = sizeof (txvu_upper_opcodes) / sizeof (txvu_opcodes[0]);
 
@@ -253,6 +379,11 @@ txvu_lower_opcode_lookup_dis (insn)
    Each of the registers must specify the same value as the opcode.
    ??? Perhaps remove the duplication?  */
 static int dest;
+
+/* Value of BC to use.
+   The register specified for the ftreg must match the broadcast register
+   specified in the opcode.  */
+static int bc;
 \f
 /* Init fns.
    These are called before doing each of the respective activities.  */
@@ -263,6 +394,7 @@ void
 txvu_opcode_init_parse ()
 {
   dest = -1;
+  bc = -1;
 }
 
 /* Called by the disassembler before printing an instruction.  */
@@ -271,6 +403,7 @@ void
 txvu_opcode_init_print ()
 {
   dest = -1;
+  bc = -1;
 }
 \f
 /* Destination choice support.
@@ -428,3 +561,152 @@ print_vfreg (info, insn, value)
   (*info->fprintf_func) (info->stream, "vf%ld", value);
   print_dest (info, insn, dest);
 }
+\f
+/* Broadcast handling.  */
+
+static long
+parse_bc (pstr, errmsg)
+     char **pstr;
+     const char **errmsg;
+{
+  long dest = 0;
+
+  switch (**pstr)
+    {
+    case 'x' : case 'X' : dest = TXVU_BC_X; break;
+    case 'y' : case 'Y' : dest = TXVU_BC_Y; break;
+    case 'z' : case 'Z' : dest = TXVU_BC_Z; break;
+    case 'w' : case 'W' : dest = TXVU_BC_W; break;
+    default : *errmsg = "invalid `bc'"; return 0;
+    }
+  ++*pstr;
+
+  *errmsg = NULL;
+  return dest;
+}
+
+static void
+print_bc (info, insn, value)
+     disassemble_info *info;
+     TXVU_INSN insn;
+     long value;
+{
+  char c;
+
+  switch (value)
+    {
+    case TXVU_BC_X : c = 'x' ; break;
+    case TXVU_BC_Y : c = 'y' ; break;
+    case TXVU_BC_Z : c = 'z' ; break;
+    case TXVU_BC_W : c = 'w' ; break;
+    }
+
+  (*info->fprintf_func) (info->stream, "%c", c);
+}
+\f
+/* FT register in broadcast case.  */
+
+static long
+parse_ftregbc (pstr, errmsg)
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long reg;
+  int reg_bc;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'f')
+    {
+      *errmsg = "unknown register";
+      return 0;
+    }
+
+  /* FIXME: quick hack until the framework works.  */
+  start = str = str + 2;
+  while (*str && isdigit (*str))
+    ++str;
+  reg = atoi (start);
+  reg_bc = parse_bc (&str, errmsg);
+  if (*errmsg)
+    return 0;
+  if (reg_bc != bc)
+    {
+      *errmsg = "register `bc' does not match instruction `bc'";
+      return 0;
+    }
+  *pstr = str;
+  *errmsg = NULL;
+  return reg;
+}
+
+static void
+print_ftregbc (info, insn, value)
+     disassemble_info *info;
+     TXVU_INSN insn;
+     long value;
+{
+  (*info->fprintf_func) (info->stream, "vf%ld", value);
+  print_bc (info, insn, bc);
+}
+\f
+/* ACC handling.  */
+
+static long
+parse_accdest (pstr, errmsg)
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  long acc_dest = 0;
+
+  if (strncasecmp (str, "acc", 3) != 0)
+    {
+      *errmsg = "expecting `acc'";
+      return 0;
+    }
+  str += 3;
+  acc_dest = parse_dest (&str);
+  if (acc_dest == 0 || isalnum (*str))
+    {
+      *errmsg = "invalid `dest'";
+      return 0;
+    }
+  if (acc_dest != dest)
+    {
+      *errmsg = "acc `dest' does not match instruction `dest'";
+      return 0;
+    }
+  *pstr = str;
+  *errmsg = NULL;
+  /* Value isn't used, but we must return something.  */
+  return 0;
+}
+
+static void
+print_accdest (info, insn, value)
+     disassemble_info *info;
+     TXVU_INSN insn;
+     long value;
+{
+  (*info->fprintf_func) (info->stream, "acc");
+  print_dest (info, insn, value);
+}
+\f
+/* XYZ operand handling.
+   This simplifies the opmula,opmsub entries by keeping them equivalent to
+   the others.  */
+
+static long
+parse_xyz (pstr, errmsg)
+     char **pstr;
+     const char **errmsg;
+{
+  if (dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
+    {
+      *errmsg = "expecting `xyz' for `dest' value";
+      return 0;
+    }
+  return 0;
+}