mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-24 12:23:31 +08:00
* 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:
@ -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
|
start-sanitize-sky
|
||||||
Wed Mar 18 13:54:04 1998 Frank Ch. Eigler <fche@cygnus.com>
|
Wed Mar 18 13:54:04 1998 Frank Ch. Eigler <fche@cygnus.com>
|
||||||
|
|
||||||
|
@ -954,7 +954,7 @@ md_begin ()
|
|||||||
|| mips_cpu == 4300
|
|| mips_cpu == 4300
|
||||||
/* start-sanitize-vr4320 */
|
/* start-sanitize-vr4320 */
|
||||||
|| mips_cpu == 4320
|
|| mips_cpu == 4320
|
||||||
/* end-sanitize-4320 */
|
/* end-sanitize-vr4320 */
|
||||||
|| mips_cpu == 4600
|
|| mips_cpu == 4600
|
||||||
/* start-sanitize-tx49 */
|
/* start-sanitize-tx49 */
|
||||||
|| mips_cpu == 4900
|
|| mips_cpu == 4900
|
||||||
@ -6962,19 +6962,56 @@ mips_ip (str, ip)
|
|||||||
unsigned int regno;
|
unsigned int regno;
|
||||||
unsigned int lastregno = 0;
|
unsigned int lastregno = 0;
|
||||||
char *s_reset;
|
char *s_reset;
|
||||||
|
char save_c = 0;
|
||||||
|
|
||||||
insn_error = NULL;
|
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)
|
for (s = str; *s != '\0' && !isspace(*s); ++s)
|
||||||
continue;
|
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";
|
save_c = *s;
|
||||||
return;
|
*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;
|
argsStart = s;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -7085,12 +7122,13 @@ mips_ip (str, ip)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '(':
|
case '(':
|
||||||
/* handle optional base register.
|
/* Handle optional base register.
|
||||||
Either the base register is omitted or
|
Either the base register is omitted or
|
||||||
we must have a left paren. */
|
we must have a left paren. */
|
||||||
/* this is dependent on the next operand specifier
|
/* This is dependent on the next operand specifier
|
||||||
is a 'b' for base register */
|
is a base register specification. */
|
||||||
assert (args[1] == 'b');
|
assert (args[1] == 'b' || args[1] == '5'
|
||||||
|
|| args[1] == '-' || args[1] == '4');
|
||||||
if (*s == '\0')
|
if (*s == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -7099,6 +7137,10 @@ mips_ip (str, ip)
|
|||||||
case '[':
|
case '[':
|
||||||
case ']':
|
case ']':
|
||||||
/* end-sanitize-vr5400 */
|
/* end-sanitize-vr5400 */
|
||||||
|
/* start-sanitize-r5900 */
|
||||||
|
case '-':
|
||||||
|
case '+':
|
||||||
|
/* end-sanitize-r5900 */
|
||||||
if (*s++ == *args)
|
if (*s++ == *args)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
@ -7134,6 +7176,141 @@ mips_ip (str, ip)
|
|||||||
s = expr_end;
|
s = expr_end;
|
||||||
continue;
|
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 'k': /* cache code */
|
||||||
case 'h': /* prefx code */
|
case 'h': /* prefx code */
|
||||||
my_getExpression (&imm_expr, s);
|
my_getExpression (&imm_expr, s);
|
||||||
@ -7376,6 +7553,16 @@ mips_ip (str, ip)
|
|||||||
case 'R': /* floating point source register */
|
case 'R': /* floating point source register */
|
||||||
case 'V':
|
case 'V':
|
||||||
case 'W':
|
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;
|
s_reset = s;
|
||||||
if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
|
if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
|
||||||
{
|
{
|
||||||
@ -7435,6 +7622,92 @@ mips_ip (str, ip)
|
|||||||
lastregno = regno;
|
lastregno = regno;
|
||||||
continue;
|
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++)
|
switch (*args++)
|
||||||
{
|
{
|
||||||
case 'V':
|
case 'V':
|
||||||
|
Reference in New Issue
Block a user