From 059a638882562daa32f0e26ca7ba1fb8033c7ae6 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Thu, 19 Mar 1998 21:28:24 +0000 Subject: [PATCH] * 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. --- gas/ChangeLog | 10 ++ gas/config/tc-mips.c | 291 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 292 insertions(+), 9 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index cf864ab5492..9a916b25514 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -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 diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 739bcc9f517..ca8ac124f0d 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -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 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)) - *s++ = '\0'; + { + save_c = *s; + *s++ = '\0'; + } + + insn = (struct mips_opcode *) hash_find (op_hash, str); - if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL) + /* 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) { - insn_error = "unrecognized opcode"; - return; + /* 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': -- 2.30.2