PRINT_FN (dotdest);
PARSE_FN (dotdest1);
+PARSE_FN (dest1);
PARSE_FN (bc);
EXTRACT_FN (bc);
INSERT_FN (luimm12);
EXTRACT_FN (luimm12);
+INSERT_FN (luimm12up6);
+
INSERT_FN (luimm15);
EXTRACT_FN (luimm15);
in both upper and lower instructions. These don't have a U or L prefix.
Operands specific to the upper or lower instruction are so prefixed. */
- /* Destination indicator attached to mnemonic, with leading '.'.
+ /* Destination indicator attached to mnemonic, with leading '.' or '/'.
After parsing this, the value is stored in global `dest' so that the
register parser can verify the same choice of xyzw is used. */
#define DOTDEST (UNUSED + 1)
#define LUIMM12 (LUIMM24 + 1)
{ 12, 0, 0, 0, insert_luimm12, extract_luimm12, 0 },
+ /* upper 6 bits of 12 bit unsigned immediate */
+#define LUIMM12UP6 (LUIMM12 + 1)
+ { 12, 0, 0, 0, insert_luimm12up6, extract_luimm12, 0 },
+
/* 11 bit pc-relative signed immediate. */
-#define LPCREL11 (LUIMM12 + 1)
+#define LPCREL11 (LUIMM12UP6 + 1)
{ 11, 0, TXVU_OPERAND_SIGNED + TXVU_OPERAND_RELATIVE_BRANCH, 0, 0, 0, 0 },
/* Destination indicator, single letter only, with leading '.'. */
vector case. */
parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest },
+ /* Destination indicator, single letter only, no leading '.'. */
+#define LDEST1 (LDOTDEST1 + 1)
+ { 0, 0, 0, parse_dest1, 0, 0, print_dotdest },
+
/* end of list place holder */
{ 0 }
};
{ "fceq", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x10) },
{ "fcget", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x1c) },
{ "fcor", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x13) },
- { "fcset", { SP, LVI01, C, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) },
+ { "fcset", { SP, LUIMM24 }, MLOP7 + MLB24, VLOP7 (0x11) },
{ "fmand", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1a) },
{ "fmeq", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x18) },
{ "fmor", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x1b) },
{ "fsand", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x16) },
{ "fseq", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x14) },
{ "fsor", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x17) },
- { "fsset", { SP, LITREG, C, LUIMM12 }, MLOP7 + MLUIMM12UNUSED + MS, VLOP7 (0x15) },
+ { "fsset", { SP, LUIMM12UP6 }, MLOP7 + MLUIMM12UNUSED + V (~0, 6, 0) + MS + MT, VLOP7 (0x15) },
{ "iadd", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x30) },
{ "iaddi", { SP, LITREG, C, LISREG, C, LIMM5 }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x32) },
{ "iaddiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x08) },
{ "iand", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
{ "ibeq", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x28) },
{ "ibgez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2f) },
+ { "ibgtz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2d) },
{ "iblez", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2e) },
{ "ibltz", { SP, LISREG, C, LPCREL11 }, MLOP7 + MDEST + MT, VLOP7 (0x2c) },
{ "ibne", { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST, VLOP7 (0x29) },
- /* FIXME: Need to not require commas around parens. */
- { "ilw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x04) },
- { "ilwr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3fe) },
+ { "ilw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x04) },
+ { "ilwr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3fe) },
{ "ior", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x34) },
{ "isub", { SP, LIDREG, C, LISREG, C, LITREG }, MLOP7 + MDEST + MLOP6, VLOP7 (0x40) + VLOP6 (0x31) },
{ "isubiu", { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7, VLOP7 (0x09) },
- { "isw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x05) },
- { "iswr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3ff) },
+ { "isw", { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x05) },
+ { "iswr", { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x3ff) },
{ "jalr", { SP, LITREG, C, LISREG }, MLOP7 + MDEST + MLIMM11, VLOP7 (0x25) },
{ "jr", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x24) },
{ "lq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x00) },
- /* FIXME: No commas around -/+. */
- { "lqd", { DOTDEST, SP, VFTREG, C, LIMM11, '(', '-', '-', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37e) },
- { "lqi", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, '+', '+', ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37c) },
+ { "lqd", { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37e) },
+ { "lqi", { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37c) },
/* Only a single VF reg is allowed here. We can use VFTREG because LDOTDEST1
handles verifying only a single choice of xyzw is present. */
{ "mfir", { LDOTDEST1, SP, VFTREG, C, LISREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fc) },
{ "mfp", { DOTDEST, SP, VFTREG, C, P }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x67c) },
{ "move", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33c) },
{ "mr32", { DOTDEST, SP, VFTREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x33d) },
- { "mtir", { LDOTDEST1, SP, LITREG, C, LFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fd) },
+ { "mtir", { LDOTDEST1, SP, LITREG, C, VFSREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fd) },
{ "rget", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43d) },
{ "rinit", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43e) },
{ "rnext", { DOTDEST, SP, VFTREG, C, R }, MLOP7 + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43c) },
{ "rsqrt", { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3be) },
- { "rxor", { R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) },
+ { "rxor", { SP, R, C, LFSFFSREG }, MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) },
{ "sq", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7, VLOP7 (0x01) },
- /* FIXME: No commas around -/+. */
- { "sqd", { DOTDEST, SP, VFTREG, C, LIMM11, '(', '-', '-', LISREG, ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37f) },
- { "sqi", { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, '+', '+', ')' }, MLOP7, VLOP7 (0x40) + VLIMM11 (0x37d) },
+ { "sqd", { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37f) },
+ { "sqi", { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37d) },
{ "sqrt", { SP, Q, C, LFTFFTREG }, MLOP7 + VLFSF (~0) + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3bd) },
{ "waitp", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x7bf) },
{ "waitq", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x3bf) },
- { "xgkick", { LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6fc) },
- { "xitop", { LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bd) },
- { "xtop", { LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bc) }
+ { "xgkick", { SP, LISREG }, MLOP7 + MDEST + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6fc) },
+ { "xitop", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bd) },
+ { "xtop", { SP, LITREG }, MLOP7 + MDEST + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x6bc) }
};
const int txvu_lower_opcodes_count = sizeof (txvu_lower_opcodes) / sizeof (txvu_lower_opcodes[0]);
\f
/* Value of DEST in use.
Each of the registers must specify the same value as the opcode.
??? Perhaps remove the duplication? */
-static int dest;
+static int mnemonic_dest;
/* Value of BC to use.
The register specified for the ftreg must match the broadcast register
specified in the opcode. */
-static int bc;
+static int mnemonic_bc;
\f
/* Init fns.
These are called before doing each of the respective activities. */
void
txvu_opcode_init_parse ()
{
- dest = -1;
- bc = -1;
+ mnemonic_dest = -1;
+ mnemonic_bc = -1;
}
/* Called by the disassembler before printing an instruction. */
void
txvu_opcode_init_print ()
{
- dest = -1;
- bc = -1;
+ mnemonic_dest = -1;
+ mnemonic_bc = -1;
}
\f
/* Multiple destination choice support.
++*pstr;
switch (**pstr)
{
- case 'x' : case 'X' : dest |= TXVU_DEST_X; break;
- case 'y' : case 'Y' : dest |= TXVU_DEST_Y; break;
- case 'z' : case 'Z' : dest |= TXVU_DEST_Z; break;
- case 'w' : case 'W' : dest |= TXVU_DEST_W; break;
+ case 'x' : case 'X' : dest = TXVU_DEST_X; break;
+ case 'y' : case 'Y' : dest = TXVU_DEST_Y; break;
+ case 'z' : case 'Z' : dest = TXVU_DEST_Z; break;
+ case 'w' : case 'W' : dest = TXVU_DEST_W; break;
default : *errmsg = "invalid `dest'"; return 0;
}
++*pstr;
- c == tolower (**pstr);
+ c = tolower (**pstr);
if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
{
*errmsg = "only one of x,y,z,w can be specified";
return dest;
}
+/* Parse a `dest' spec with no leading '.', where only a single letter is
+ allowed, but the encoding handles all four. The parsed value must match
+ that recorded in `dest'. */
+
+static long
+parse_dest1 (pstr, errmsg)
+ char **pstr;
+ const char **errmsg;
+{
+ char c;
+ long dest;
+
+ dest = _parse_dest (pstr);
+ if (dest != TXVU_DEST_X
+ && dest != TXVU_DEST_Y
+ && dest != TXVU_DEST_Z
+ && dest != TXVU_DEST_W)
+ {
+ *errmsg = "expecting one of x,y,z,w";
+ return 0;
+ }
+
+ if (dest != mnemonic_dest)
+ {
+ *errmsg = "`dest' suffix does not match instruction `dest'";
+ return 0;
+ }
+
+ *errmsg = NULL;
+ return dest;
+}
+
static TXVU_INSN
insert_dotdest (insn, operand, mods, value, errmsg)
TXVU_INSN insn;
const char **errmsg;
{
/* Record the DEST value in use so the register parser can use it. */
- dest = value;
- if (errmsg)
- *errmsg = NULL;
+ mnemonic_dest = value;
return insn |= value << operand->shift;
}
int *pinvalid;
{
/* Record the DEST value in use so the register printer can use it. */
- dest = (insn >> operand->shift) & ((1 << operand->bits) - 1);
- return dest;
+ mnemonic_dest = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+ return mnemonic_dest;
}
/* Utility to print a multiple dest spec. */
default : *errmsg = "only one of x,y,z,w can be specified"; return 0;
}
++*pstr;
- c == tolower (**pstr);
+ c = tolower (**pstr);
if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
{
*errmsg = "only one of x,y,z,w can be specified";
if (*errmsg)
return 0;
/* Save value for later verification in register parsing. */
- bc = value;
+ mnemonic_bc = value;
return value;
}
int mods;
int *pinvalid;
{
- bc = insn & 3;
- return bc;
+ mnemonic_bc = insn & 3;
+ return mnemonic_bc;
}
\f
static long
*errmsg = "invalid `dest'";
return 0;
}
- if (reg_dest != dest)
+ if (reg_dest != mnemonic_dest)
{
*errmsg = "register `dest' does not match instruction `dest'";
return 0;
long value;
{
(*info->fprintf_func) (info->stream, "vf%02ld", value);
- _print_dest (info, insn, dest);
+ _print_dest (info, insn, mnemonic_dest);
}
\f
/* FT register in broadcast case. */
reg_bc = _parse_sdest (&str, errmsg);
if (*errmsg)
return 0;
- if (reg_bc != bc)
+ if (reg_bc != mnemonic_bc)
{
*errmsg = "register `bc' does not match instruction `bc'";
return 0;
long value;
{
(*info->fprintf_func) (info->stream, "vf%02ld", value);
- print_sdest (info, insn, bc);
+ print_sdest (info, insn, mnemonic_bc);
}
\f
/* ACC handling. */
*errmsg = "invalid `dest'";
return 0;
}
- if (acc_dest != dest)
+ if (acc_dest != mnemonic_dest)
{
*errmsg = "acc `dest' does not match instruction `dest'";
return 0;
long value;
{
(*info->fprintf_func) (info->stream, "acc");
- _print_dest (info, insn, dest);
+ _print_dest (info, insn, mnemonic_dest);
}
\f
/* XYZ operand handling.
long value;
const char **errmsg;
{
- if (dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
+ if (mnemonic_dest != (TXVU_DEST_X | TXVU_DEST_Y | TXVU_DEST_Z))
{
*errmsg = "expecting `xyz' for `dest' value";
return insn;
char *str = *pstr;
char *start;
long reg;
- int reg_bc;
if (tolower (str[0]) != 'v'
|| tolower (str[1]) != 'f')
char *str = *pstr;
char *start;
long reg;
- int reg_bc;
if (tolower (str[0]) != 'v'
|| tolower (str[1]) != 'i')
char *str = *pstr;
char *start;
long reg;
- int reg_bc;
if (tolower (str[0]) != 'v'
|| tolower (str[1]) != 'i')
{
return (((insn & MLUIMM12TOP) != 0) << 11) | VLIMM11 (insn);
}
+
+/* Lower instruction 12 bit unsigned immediate, upper 6 bits. */
+
+static TXVU_INSN
+insert_luimm12up6 (insn, operand, mods, value, errmsg)
+ TXVU_INSN insn;
+ const struct txvu_operand *operand;
+ int mods;
+ long value;
+ const char **errmsg;
+{
+ return insn | VLUIMM12TOP ((value & (1 << 11)) != 0) | (value & 0x7c0);
+}
\f
/* Lower instruction 15 bit unsigned immediate. */