* config/tc-mips.c (mips_ip): Handle opcodes which have the form

"name.completer" where only the name is actually in the opcode
        table.  Allow various operands for base register in load/store
        instructions.  Handle various new argument characters for the
        cop2/vu0 co-processor.
This commit is contained in:
Jeff Law
1998-03-19 21:28:24 +00:00
parent b44cac60e4
commit 059a638882
2 changed files with 293 additions and 10 deletions

View File

@ -1,3 +1,13 @@
start-sanitize-r5900
Thu Mar 19 14:19:27 1998 Jeffrey A Law (law@cygnus.com)
* config/tc-mips.c (mips_ip): Handle opcodes which have the form
"name.completer" where only the name is actually in the opcode
table. Allow various operands for base register in load/store
instructions. Handle various new argument characters for the
cop2/vu0 co-processor.
end-sanitize-r5900
start-sanitize-sky
Wed Mar 18 13:54:04 1998 Frank Ch. Eigler <fche@cygnus.com>

View File

@ -954,7 +954,7 @@ md_begin ()
|| mips_cpu == 4300
/* start-sanitize-vr4320 */
|| mips_cpu == 4320
/* end-sanitize-4320 */
/* end-sanitize-vr4320 */
|| mips_cpu == 4600
/* start-sanitize-tx49 */
|| mips_cpu == 4900
@ -6962,19 +6962,56 @@ mips_ip (str, ip)
unsigned int regno;
unsigned int lastregno = 0;
char *s_reset;
char save_c = 0;
insn_error = NULL;
/* If the instruction contains a '.', we first try to match an instruction
including the '.'. Then we try again without the '.'. */
insn = NULL;
for (s = str; *s != '\0' && !isspace(*s); ++s)
continue;
if (isspace (*s))
*s++ = '\0';
if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
/* If we stopped on whitespace, then replace the whitespace with null for
the call to hash_find. Save the character we replaced just in case we
have to re-parse the instruction. */
if (isspace (*s))
{
insn_error = "unrecognized opcode";
return;
save_c = *s;
*s++ = '\0';
}
insn = (struct mips_opcode *) hash_find (op_hash, str);
/* If we didn't find the instruction in the opcode table, try again, but
this time with just the instruction up to, but not including the
first '.'. */
if (insn == NULL)
{
/* Restore the character we overwrite above (if any). */
if (save_c)
*(--s) = save_c;
/* Scan up to the first '.' or whitespace. */
for (s = str; *s != '\0' && *s != '.' && !isspace (*s); ++s)
continue;
/* If we did not find a '.', then we can quit now. */
if (*s != '.')
{
insn_error = "unrecognized opcode";
return;
}
/* Lookup the instruction in the hash table. */
*s++ = '\0';
if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
{
insn_error = "unrecognized opcode";
return;
}
}
argsStart = s;
for (;;)
{
@ -7085,12 +7122,13 @@ mips_ip (str, ip)
break;
case '(':
/* handle optional base register.
/* Handle optional base register.
Either the base register is omitted or
we must have a left paren. */
/* this is dependent on the next operand specifier
is a 'b' for base register */
assert (args[1] == 'b');
/* This is dependent on the next operand specifier
is a base register specification. */
assert (args[1] == 'b' || args[1] == '5'
|| args[1] == '-' || args[1] == '4');
if (*s == '\0')
return;
@ -7099,6 +7137,10 @@ mips_ip (str, ip)
case '[':
case ']':
/* end-sanitize-vr5400 */
/* start-sanitize-r5900 */
case '-':
case '+':
/* end-sanitize-r5900 */
if (*s++ == *args)
continue;
break;
@ -7134,6 +7176,141 @@ mips_ip (str, ip)
s = expr_end;
continue;
/* start-sanitize-r5900 */
case '0': /* 5 bit signed immediate at 6 */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((c == '\0' && imm_expr.X_op != O_constant)
|| ((imm_expr.X_add_number < -16
|| imm_expr.X_add_number >= 16)
&& imm_expr.X_op == O_constant))
{
if (imm_expr.X_op != O_constant
&& imm_expr.X_op != O_big)
insn_error = "absolute expression required";
else
as_bad ("5 bit expression not in range -16..15");
}
ip->insn_opcode |= (imm_expr.X_add_number) << 6;
imm_expr.X_op = O_absent;
s = expr_end;
continue;
case '9': /* vi19 for vcallmsr */
if (strncmp (s, "vi19", 4) == 0)
s += 4;
else
as_bad ("expected vi19");
continue;
case '%': /* escape character */
/* '%' specifies that we've got an optional suffix to this
operand that must match exactly (if it exists). */
if (*s != '\0' && *s != ','
&& *s != ' ' && *s != '\t' && *s != '\n')
{
if (*s == *(args + 1))
{
s++;
args++;
continue;
}
break;
}
args++;
continue;
case 'K': /* DEST operand completer (optional), must
match previous dest if specified. */
case '&': /* DEST instruction completer */
{
int w,x,y,z;
static int last_h;
w = x = y = z = 0;
/* Parse the completer. */
s_reset = s;
while (*s != '\0' && *s != ' ' && *s != ',')
{
if (*s == 'w')
w++;
else if (*s == 'x')
x++;
else if (*s == 'y')
y++;
else if (*s == 'z')
z++;
else
{
insn_error = "Invalid dest specification";
continue;
}
s++;
}
/* Each completer can only appear once. */
if (w > 1 || x > 1 || y > 1 || z > 1)
{
insn_error = "Invalid dest specification";
continue;
}
/* If this is the opcode completer, then we must insert
the appropriate value into the insn. */
if (*args == '&')
{
ip->insn_opcode |= ((w << 21) | (x << 24)
| (y << 23) | (z << 22));
last_h = (w << 3) | (x << 0) | (y << 1) | (z << 2);
}
else
{
int temp;
/* This is the operand completer, make sure it matches
the previous opcode completer. */
temp = (w << 3) | (x << 0) | (y << 1) | (z << 2);
if (temp && temp != last_h)
{
insn_error = "DEST field in operand does not match DEST field in instruction";
continue;
}
}
continue;
}
case 'J': /* vu0 I register */
if (s[0] == 'I')
s += 1;
else
insn_error = "operand `I' expected";
continue;
case 'Q': /* vu0 Q register */
if (s[0] == 'Q')
s += 1;
else
insn_error = "operand `Q' expected";
continue;
case 'X': /* vu0 R register */
if (s[0] == 'R')
s += 1;
else
insn_error = "operand `R' expected";
continue;
case 'U': /* vu0 ACC register */
if (s[0] == 'A' && s[1] == 'C' && s[2] == 'C')
s += 3;
else
insn_error = "operand `ACC' expected";
continue;
/* end-sanitize-r5900 */
case 'k': /* cache code */
case 'h': /* prefx code */
my_getExpression (&imm_expr, s);
@ -7376,6 +7553,16 @@ mips_ip (str, ip)
case 'R': /* floating point source register */
case 'V':
case 'W':
/* start-sanitize-r5900 */
case '1': /* vu0 fp reg position 1 */
case '2': /* vu0 fp reg position 2 */
case '3': /* vu0 fp reg position 3 */
case '4': /* vu0 int reg position 1 */
case '5': /* vu0 int reg position 2 */
case '6': /* vu0 int reg position 3 */
case '7': /* vu0 fp reg with ftf modifier */
case '8': /* vu0 fp reg with fsf modifier */
/* end-sanitize-r5900 */
s_reset = s;
if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
{
@ -7435,6 +7622,92 @@ mips_ip (str, ip)
lastregno = regno;
continue;
}
/* start-sanitize-r5900 */
/* Handle vf and vi regsiters for vu0. */
if (s[0] == 'v'
&& (s[1] == 'f' || s[1] == 'i')
&& isdigit (s[2]))
{
s += 2;
regno = 0;
do
{
regno *= 10;
regno += *s - '0';
++s;
}
while (isdigit (*s));
if (regno > 31)
as_bad ("Invalid vu0 register number (%d)", regno);
c = *args;
if (c == '7' || c == '8')
{
int value;
switch (*s)
{
case 'w':
value = 3;
s++;
ip->insn_opcode |= value << (c == '7' ? 23 : 21);
break;
case 'x':
value = 0;
s++;
ip->insn_opcode |= value << (c == '7' ? 23 : 21);
break;
case 'y':
value = 1;
s++;
ip->insn_opcode |= value << (c == '7' ? 23 : 21);
break;
case 'z':
value = 2;
s++;
ip->insn_opcode |= value << (c == '7' ? 23 : 21);
break;
default:
as_bad ("Invalid FSF/FTF specification");
}
}
if (*s == ' ')
s++;
if (args[1] != *s)
{
if (c == 'V' || c == 'W')
{
regno = lastregno;
s = s_reset;
args++;
}
}
switch (c)
{
case '1':
case '4':
case '7':
ip->insn_opcode |= regno << 16;
break;
case '2':
case '5':
case '8':
ip->insn_opcode |= regno << 11;
break;
case '3':
case '6':
ip->insn_opcode |= regno << 6;
break;
}
lastregno = regno;
continue;
}
/* end-sanitize-r5900 */
switch (*args++)
{
case 'V':