(lookup_keyword_{value,name}): New functions.

(scan_symbol): New function.
	(issymchar,SKIP_BLANKS): New macros.
Plus more dma/gpuif support code.
This commit is contained in:
Doug Evans 1998-01-27 02:58:45 +00:00
parent dff6e4a297
commit 7b5c32cfa1
2 changed files with 271 additions and 2 deletions

View 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>

View File

@ -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;
}