From 7b5c32cfa187f012ab3f906762f25a2737424b6e Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Tue, 27 Jan 1998 02:58:45 +0000 Subject: [PATCH] (lookup_keyword_{value,name}): New functions. (scan_symbol): New function. (issymchar,SKIP_BLANKS): New macros. Plus more dma/gpuif support code. --- opcodes/ChangeLog | 3 + opcodes/txvu-opc.c | 270 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 271 insertions(+), 2 deletions(-) diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 89eba09f8ef..7fb718b191d 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -6,6 +6,9 @@ Mon Jan 26 16:25:51 1998 Doug Evans * 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 diff --git a/opcodes/txvu-opc.c b/opcodes/txvu-opc.c index 2eab05fbdac..f7ee3066c90 100644 --- a/opcodes/txvu-opc.c +++ b/opcodes/txvu-opc.c @@ -30,6 +30,22 @@ #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]); @@ -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]; } + +/* 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; +} -- 2.30.2