(lookup_keyword_{value,name}): New functions.
authorDoug Evans <dje@google.com>
Tue, 27 Jan 1998 02:58:45 +0000 (02:58 +0000)
committerDoug Evans <dje@google.com>
Tue, 27 Jan 1998 02:58:45 +0000 (02:58 +0000)
(scan_symbol): New function.
(issymchar,SKIP_BLANKS): New macros.
Plus more dma/gpuif support code.

opcodes/ChangeLog
opcodes/txvu-opc.c

index 89eba09f8ef6fa0645125d4824b2ce9dc03007e7..7fb718b191d59658f67141f01bb990c986d0576c 100644 (file)
@@ -6,6 +6,9 @@ Mon Jan 26 16:25:51 1998  Doug Evans  <devans@seba.cygnus.com>
        * txvu-opc.c: insert/extract/print fns take pointer to
        insn now and not insn itself.  Add initial dma,pke,gpuif support.
        Parse fn no longer needs to set errmsg = NULL for success.
+       (lookup_keyword_{value,name}): New functions.
+       (scan_symbol): New function.
+       (issymchar,SKIP_BLANKS): New macros.
 
 Fri Jan 23 01:49:24 1998  Doug Evans  <devans@seba.cygnus.com>
 
index 2eab05fbdac76b2a73a61855ed0ddd697e9eed13..f7ee3066c903bd084c357d062b06070053de3db9 100644 (file)
 #endif
 #define CONCAT2(a,b)   XCONCAT2(a,b)
 
+typedef struct {
+  int value;
+  const char *name;
+} keyword;
+
+static int lookup_keyword_value PARAMS ((const keyword *, const char *, int));
+static const char *lookup_keyword_name PARAMS ((const keyword *table, int));
+
+static char *scan_symbol PARAMS ((char *));
+
+/* Return non-zero if CH is a character that may appear in a symbol.  */
+/* FIXME: This will need revisiting.  */
+#define issymchar(ch) (isalnum (ch) || ch == '_')
+
+#define SKIP_BLANKS(var) while (isspace (*(var))) ++(var)
+
 /* ??? One can argue it's preferable to have the PARSE_FN support in tc-vxvu.c
    and the PRINT_FN support in txvu-dis.c.  For this project I like having
    them all in one place.  */
@@ -1470,12 +1486,15 @@ const struct txvu_operand dma_operands[] =
 
 struct txvu_opcode dma_opcodes[] =
 {
+  /* ??? Some of these may take optional arguments.
+     The way to handle that is to have multiple table entries, those with and
+     those without the optional arguments.  */
   { "dmacnt", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 1 },
   { "dmanext", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 2 },
   { "dmaref", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 3 },
   { "dmarefs", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 4 },
   { "dmacall", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 5 },
-  { "dmareg", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 6 },
+  { "dmaret", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 6 },
   { "dmaend", { DMA_FLAGS, SP, DMA_DATA, C, DMA_NEXT }, 0, 7 }
 };
 const int dma_opcodes_count = sizeof (dma_opcodes) / sizeof (dma_opcodes[0]);
@@ -1505,7 +1524,6 @@ parse_dma_flags (pstr, errmsg)
        }
     }
 
-  *errmsg = NULL;
   *pstr = str + 1;
   return flags;
 }
@@ -1551,11 +1569,41 @@ print_dma_flags (info, insn, value)
     }
 }
 
+/* Parse a DMA data spec which can be either of '*' or a quad word count.  */
+
 static long
 parse_dma_data (pstr, errmsg)
      char **pstr;
      const char **errmsg;
 {
+  char *str = *pstr;
+  long count;
+
+  if (*str == '*')
+    {
+      ++*pstr;
+      /* -1 is a special marker to caller to tell it the count is to be
+        computed from the data.  */
+      return -1;
+    }
+
+  if (isdigit (*str))
+    {
+      char *start = str;
+      while (*str && *str != ',')
+       ++str;
+      if (*str != ',')
+       {
+         *errmsg = "invalid dma count";
+         return 0;
+       }
+      count = atoi (start);
+      *pstr = str;
+      return count;
+    }
+
+  *errmsg = "invalid dma count";
+  return 0;
 }
 
 static void
@@ -1592,6 +1640,17 @@ parse_dma_next (pstr, errmsg)
      char **pstr;
      const char **errmsg;
 {
+  char *start = *pstr;
+  char *end = scan_symbol (start);
+
+  if (end == start)
+    {
+      *errmsg = "invalid dma next tag";
+      return 0;
+    }
+  /* FIXME: unfinished */
+  *pstr = end;
+  return 0;
 }
 
 static void
@@ -1673,9 +1732,26 @@ const struct txvu_operand gpuif_operands[] =
 
 struct txvu_opcode gpuif_opcodes[] =
 {
+  /* Some of these may take optional arguments.
+     The way this is handled is to have multiple table entries, those with and
+     those without the optional arguments.  */
+
   { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_EOP }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_EOP }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_PRIM, C, GPUIF_REGS }, 0, 1 },
+  { "gpuifpacked", { SP, GPUIF_REGS }, 0, 1 },
+
   { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_NLOOP, C, GPUIF_EOP }, 0, 2 },
+  { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_EOP }, 0, 2 },
+  { "gpuifreglist", { SP, GPUIF_REGS, C, GPUIF_NLOOP }, 0, 2 },
+  { "gpuifreglist", { SP, GPUIF_REGS }, 0, 2 },
+
   { "gpuifimage", { SP, GPUIF_NLOOP }, 0, 3 },
+  { "gpuifimage", { 0 }, 0, 3 },
 };
 const int gpuif_opcodes_count = sizeof (gpuif_opcodes) / sizeof (gpuif_opcodes[0]);
 \f
@@ -1686,6 +1762,27 @@ parse_gpuif_prim (pstr, errmsg)
      char **pstr;
      const char **errmsg;
 {
+  char *str = *pstr;
+  char *start;
+  long prim;
+
+  if (strncasecmp (str, "prim=", 5) != 0)
+    {
+      *errmsg = "missing PRIM spec";
+      return 0;
+    }
+  str += 5;
+  for (start = str; isalnum (*str); ++str)
+    continue;
+  if (str == start)
+    {
+      *errmsg = "missing PRIM spec";
+      return 0;
+    }
+  /* FIXME: Yes, atoi doesn't do error checking.  Later.  */
+  prim = atoi (start);
+  *pstr = str;
+  return prim;
 }
 
 static void
@@ -1717,11 +1814,95 @@ print_gpuif_prim (info, insn, value)
   (*info->fprintf_func) (info->stream, "???");
 }
 
+static const keyword gpuif_regs[] = {
+  { GPUIF_REG_PRIM,      "prim" },
+  { GPUIF_REG_RGBAQ,     "rgbaq" },
+  { GPUIF_REG_ST,        "st" },
+  { GPUIF_REG_UV,        "uv" },
+  { GPUIF_REG_XYZF2,     "xyzf2" },
+  { GPUIF_REG_TEXCLUT_1, "texclut_1" },
+  { GPUIF_REG_TEXCLUT_2, "texclut_2" },
+  { GPUIF_REG_TEX0_1,    "tex0_1" },
+  { GPUIF_REG_TEX0_2,    "tex0_2" },
+  { GPUIF_REG_TEX1_1,    "tex1_1" },
+  { GPUIF_REG_TEX1_2,    "tex1_2" },
+  { GPUIF_REG_XYZF3,     "xyzf3" },
+  { GPUIF_REG_PRMODE,    "prmode" },
+  { GPUIF_REG_A_D,       "a_d" },
+  { GPUIF_REG_NOP,       "nop" },
+  { 0, 0 }
+};
+
+/* Parse a REGS= spec.
+   The result is ???.  */
+
 static long
 parse_gpuif_regs (pstr, errmsg)
      char **pstr;
      const char **errmsg;
 {
+  char *str = *pstr;
+  char *start;
+  char c;
+  int reg;
+
+  if (strncasecmp (str, "regs=", 5) != 0)
+    {
+      *errmsg = "missing REGS spec";
+      return 0;
+    }
+  str += 5;
+  SKIP_BLANKS (str);
+  if (*str != '{')
+    {
+      *errmsg = "missing '{' in REGS spec";
+      return 0;
+    }
+  ++str;
+
+  while (*str && *str != '}')
+    {
+      /* Pick out the register name.  */
+
+      SKIP_BLANKS (str);
+      start = str;
+      str = scan_symbol (str);
+      if (str == start)
+       {
+         *errmsg = "invalid REG";
+         return 0;
+       }
+
+      /* Look it up in the table.  */
+
+      c = *str;
+      *str = 0;
+      reg = lookup_keyword_value (gpuif_regs, start, 0);
+      *str = c;
+      if (reg == -1)
+       {
+         *errmsg = "invalid REG";
+         return 0;
+       }
+
+      /* FIXME: save `reg' away somewhere */
+
+      /* Prepare for the next one.  */
+
+      SKIP_BLANKS (str);
+      if (*str == ',')
+       ++str;
+      else if (*str != '}')
+       break;
+    }
+  if (*str != '}')
+    {
+      *errmsg = "missing '{' in REGS spec";
+      return 0;
+    }
+
+  *pstr = str + 1;
+  return 0; /* FIXME */
 }
 
 static void
@@ -1758,6 +1939,29 @@ parse_gpuif_nloop (pstr, errmsg)
      char **pstr;
      const char **errmsg;
 {
+  char *str = *pstr;
+  char *start;
+  char c;
+  int nloop;
+
+  if (strncasecmp (str, "nloop=", 6) != 0)
+    {
+      *errmsg = "missing NLOOP spec";
+      return 0;
+    }
+  str += 6;
+  SKIP_BLANKS (str);
+  start = str;
+  str = scan_symbol (str);
+  if (str == start)
+    {
+      *errmsg = "invalid NOOP spec";
+      return 0;
+    }
+  /* FIXME: error checking */
+  nloop = atoi (start);
+  *pstr = str;
+  return nloop;
 }
 
 static void
@@ -1794,6 +1998,13 @@ parse_gpuif_eop (pstr, errmsg)
      char **pstr;
      const char **errmsg;
 {
+  if (strncasecmp (*pstr, "eop", 3) == 0)
+    {
+      *pstr += 3;
+      return 1;
+    }
+  *errmsg = "missing `EOP'";
+  return 0;
 }
 
 static void
@@ -2027,3 +2238,58 @@ gpuif_opcode_lookup_dis (insn)
 {
   return &gpuif_opcodes[0];
 }
+\f
+/* Misc. utilities.  */
+
+/* Scan a symbol and return a pointer to one past the end.  */
+
+static char *
+scan_symbol (sym)
+     char *sym;
+{
+  while (*sym && issymchar (*sym))
+    ++sym;
+  return sym;
+}
+
+/* Given a keyword, look up its value, or -1 if not found.  */
+
+static int
+lookup_keyword_value (table, name, case_sensitive_p)
+     const keyword *table;
+     const char *name;
+     int case_sensitive_p;
+{
+  const keyword *p;
+
+  if (case_sensitive_p)
+    {
+      for (p = table; p->name; ++p)
+       if (strcmp (name, p->name) == 0)
+         return p->value;
+    }
+  else
+    {
+      for (p = table; p->name; ++p)
+       if (strcasecmp (name, p->name) == 0)
+         return p->value;
+    }
+
+  return -1;
+}
+
+/* Given a keyword's value, look up its name, or NULL if not found.  */
+
+static const char *
+lookup_keyword_name (table, value)
+     const keyword *table;
+     int value;
+{
+  const keyword *p;
+
+  for (p = table; p->name; ++p)
+    if (value == p->value)
+      return p->name;
+
+  return NULL;
+}