error only one of OBJ_ELF and OBJ_SOM can be defined
#endif
+/* If we are using ELF, then we probably can support dwarf2 debug
+ records. Furthermore, if we are supporting dwarf2 debug records,
+ then we want to use the assembler support for compact line numbers. */
+#ifdef OBJ_ELF
+#include "dwarf2dbg.h"
+struct dwarf2_line_info debug_line;
+#endif
+
/* A "convient" place to put object file dependencies which do
not need to be seen outside of tc-hppa.c. */
#ifdef OBJ_ELF
to store a copyright string. */
#define obj_version obj_elf_version
#define obj_copyright obj_elf_version
+
+#define UNWIND_SECTION_NAME ".PARISC.unwind"
#endif
#ifdef OBJ_SOM
{"equ", pa_equ, 0},
{"exit", pa_exit, 0},
{"export", pa_export, 0},
+#ifdef OBJ_ELF
+ { "file", dwarf2_directive_file },
+#endif
{"fill", pa_fill, 0},
{"float", pa_float_cons, 'f'},
{"half", pa_cons, 2},
{"lcomm", pa_lcomm, 0},
{"leave", pa_leave, 0},
{"level", pa_level, 0},
+#ifdef OBJ_ELF
+ { "loc", dwarf2_directive_loc },
+#endif
{"long", pa_cons, 4},
{"lsym", pa_lsym, 0},
#ifdef OBJ_SOM
/* Holds the last field selector. */
static int hppa_field_selector;
+/* Nonzero when strict syntax checking is enabled. Zero otherwise.
+
+ Each opcode in the table has a flag which indicates whether or not
+ strict syntax checking should be enabled for that instruction. */
+static int strict = 0;
+
#ifdef OBJ_SOM
/* A dummy bfd symbol so that all relocations have symbols of some kind. */
static symbolS *dummy_symbol;
{"lr", e_lrsel},
{"ls", e_lssel},
{"lt", e_ltsel},
+ {"ltp", e_ltpsel},
{"n", e_nsel},
{"nl", e_nlsel},
{"nlr", e_nlrsel},
{"rr", e_rrsel},
{"rs", e_rssel},
{"rt", e_rtsel},
+ {"rtp", e_rtpsel},
{"t", e_tsel},
};
(offsetT) 0, &the_insn.exp, the_insn.pcrel,
the_insn.reloc, the_insn.field_selector,
the_insn.format, the_insn.arg_reloc, NULL);
+
+#ifdef OBJ_ELF
+ if (debug_type == DEBUG_DWARF2)
+ {
+ bfd_vma addr;
+
+ /* First update the notion of the current source line. */
+ dwarf2_where (&debug_line);
+
+ /* We want the offset of the start of this instruction within the
+ the current frag. */
+ addr = frag_now->fr_address + frag_now_fix () - 4;
+
+ /* And record the information. */
+ dwarf2_gen_line_info (addr, &debug_line);
+ }
+#endif
}
/* Do the real work for assembling a single instruction. Store results
{
/* Do some initialization. */
opcode = insn->match;
+ strict = (insn->flags & FLAG_STRICT);
memset (&the_insn, 0, sizeof (the_insn));
the_insn.reloc = R_HPPA_NONE;
sure that the operands match. */
for (args = insn->args;; ++args)
{
+ /* Absorb white space in instruction. */
+ while (*s == ' ' || *s == '\t')
+ s++;
+
switch (*args)
{
/* Handle a 5 bit register or control register field at 10. */
case 'b':
case '^':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
num = pa_parse_number (&s, 0);
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+ /* Handle %sar or %cr11. No bits get set, we just verify that it
+ is there. */
+ case '!':
+ /* Skip whitespace before register. */
+ while (*s == ' ' || *s == '\t')
+ s = s + 1;
+
+ if (!strncasecmp(s, "%sar", 4))
+ {
+ s += 4;
+ continue;
+ }
+ else if (!strncasecmp(s, "%cr11", 5))
+ {
+ s += 5;
+ continue;
+ }
+ break;
+
/* Handle a 5 bit register field at 15. */
case 'x':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
num = pa_parse_number (&s, 0);
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
/* Handle a 5 bit register field at 31. */
- case 'y':
case 't':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
num = pa_parse_number (&s, 0);
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+ /* Handle a 5 bit register field at 10 and 15. */
+ case 'a':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ num = pa_parse_number (&s, 0);
+ CHECK_FIELD (num, 31, 0, 0);
+ opcode |= num << 16;
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+
/* Handle a 5 bit field length at 31. */
case 'T':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
CHECK_FIELD (num, 32, 1, 0);
INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
/* Handle a 5 bit immediate at 15. */
case '5':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 15, -16, 0);
+ /* When in strict mode, we want to just reject this
+ match instead of giving an out of range error. */
+ CHECK_FIELD (num, 15, -16, strict);
low_sign_unext (num, 5, &num);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
/* Handle a 5 bit immediate at 31. */
case 'V':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 15, -16, 0)
+ /* When in strict mode, we want to just reject this
+ match instead of giving an out of range error. */
+ CHECK_FIELD (num, 15, -16, strict)
low_sign_unext (num, 5, &num);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
/* Handle an unsigned 5 bit immediate at 31. */
case 'r':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
CHECK_FIELD (num, 31, 0, 0);
- INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, strict);
/* Handle an unsigned 5 bit immediate at 15. */
case 'R':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 31, 0, 0);
+ CHECK_FIELD (num, 31, 0, strict);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
+
+ /* Handle an unsigned 10 bit immediate at 15. */
+ case 'U':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 1023, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
/* Handle a 2 bit space identifier at 17. */
case 's':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
num = pa_parse_number (&s, 0);
CHECK_FIELD (num, 3, 0, 1);
INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
/* Handle a 3 bit space identifier at 18. */
case 'S':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
num = pa_parse_number (&s, 0);
CHECK_FIELD (num, 7, 0, 1);
dis_assemble_3 (num, &num);
INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
- /* Handle a completer for an indexing load or store. */
+ /* Handle all completers. */
case 'c':
- {
- int uu = 0;
- int m = 0;
- int i = 0;
- while (*s == ',' && i < 2)
+ switch (*++args)
+ {
+
+ /* Handle a completer for an indexing load or store. */
+ case 'x':
{
- s++;
- if (strncasecmp (s, "sm", 2) == 0)
+ int uu = 0;
+ int m = 0;
+ int i = 0;
+ while (*s == ',' && i < 2)
{
- uu = 1;
- m = 1;
+ s++;
+ if (strncasecmp (s, "sm", 2) == 0)
+ {
+ uu = 1;
+ m = 1;
+ s++;
+ i++;
+ }
+ else if (strncasecmp (s, "m", 1) == 0)
+ m = 1;
+ else if (strncasecmp (s, "s", 1) == 0)
+ uu = 1;
+ /* When in strict mode this is a match failure. */
+ else if (strict)
+ break;
+ else
+ as_bad (_("Invalid Indexed Load Completer."));
s++;
i++;
}
- else if (strncasecmp (s, "m", 1) == 0)
- m = 1;
- else if (strncasecmp (s, "s", 1) == 0)
- uu = 1;
- else
- as_bad (_("Invalid Indexed Load Completer."));
- s++;
- i++;
+ if (i > 2)
+ as_bad (_("Invalid Indexed Load Completer Syntax."));
+ opcode |= m << 5;
+ INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
}
- if (i > 2)
- as_bad (_("Invalid Indexed Load Completer Syntax."));
- opcode |= m << 5;
- INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
- }
- /* Handle a short load/store completer. */
- case 'C':
- {
- int a = 0;
- int m = 0;
- if (*s == ',')
+ /* Handle a short load/store completer. */
+ case 'm':
{
- s++;
- if (strncasecmp (s, "ma", 2) == 0)
- {
- a = 0;
- m = 1;
- }
- else if (strncasecmp (s, "mb", 2) == 0)
+ int a = 0;
+ int m = 0;
+ if (*s == ',')
{
- a = 1;
- m = 1;
+ s++;
+ if (strncasecmp (s, "ma", 2) == 0)
+ {
+ a = 0;
+ m = 1;
+ }
+ else if (strncasecmp (s, "mb", 2) == 0)
+ {
+ a = 1;
+ m = 1;
+ }
+ /* When in strict mode this is a match failure. */
+ else if (strict)
+ break;
+ else
+ as_bad (_("Invalid Short Load/Store Completer."));
+ s += 2;
}
- else
- as_bad (_("Invalid Short Load/Store Completer."));
- s += 2;
- }
- if (*args == 'C')
- {
opcode |= m << 5;
INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
}
- }
- /* Handle a stbys completer. */
- case 'Y':
- {
- int a = 0;
- int m = 0;
- int i = 0;
- while (*s == ',' && i < 2)
+ /* Handle a stbys completer. */
+ case 's':
{
- s++;
- if (strncasecmp (s, "m", 1) == 0)
- m = 1;
- else if (strncasecmp (s, "b", 1) == 0)
- a = 0;
- else if (strncasecmp (s, "e", 1) == 0)
- a = 1;
- else
+ int a = 0;
+ int m = 0;
+ int i = 0;
+ while (*s == ',' && i < 2)
+ {
+ s++;
+ if (strncasecmp (s, "m", 1) == 0)
+ m = 1;
+ else if (strncasecmp (s, "b", 1) == 0)
+ a = 0;
+ else if (strncasecmp (s, "e", 1) == 0)
+ a = 1;
+ /* When in strict mode this is a match failure. */
+ else if (strict)
+ break;
+ else
+ as_bad (_("Invalid Store Bytes Short Completer"));
+ s++;
+ i++;
+ }
+ if (i > 2)
as_bad (_("Invalid Store Bytes Short Completer"));
- s++;
- i++;
+ opcode |= m << 5;
+ INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
}
- if (i > 2)
- as_bad (_("Invalid Store Bytes Short Completer"));
- opcode |= m << 5;
- INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
- }
- /* Handle a non-negated compare/stubtract condition. */
- case '<':
- cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
- if (cmpltr < 0)
- {
- as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
- cmpltr = 0;
- }
- INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+ /* Handle a local processor completer. */
+ case 'L':
+ if (strncasecmp (s, ",l", 2) != 0)
+ break;
+ s += 2;
+ continue;
- /* Handle a negated or non-negated compare/subtract condition. */
- case '?':
- save_s = s;
- cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
- if (cmpltr < 0)
- {
- s = save_s;
- cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1);
- if (cmpltr < 0)
+ /* Handle a PROBE read/write completer. */
+ case 'w':
+ flag = 0;
+ if (!strncasecmp (s, ",w", 2))
{
- as_bad (_("Invalid Compare/Subtract Condition."));
- cmpltr = 0;
+ flag = 1;
+ s += 2;
}
- else
+ else if (!strncasecmp (s, ",r", 2))
{
- /* Negated condition requires an opcode change. */
- opcode |= 1 << 27;
+ flag = 0;
+ s += 2;
}
- }
-
- INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
- /* Handle non-negated add condition. */
- case '!':
- cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
- if (cmpltr < 0)
- {
- as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
- cmpltr = 0;
- }
- INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
- /* Handle a negated or non-negated add condition. */
- case '@':
- save_s = s;
- cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
- if (cmpltr < 0)
- {
- s = save_s;
- cmpltr = pa_parse_neg_add_cmpltr (&s, 1);
- if (cmpltr < 0)
- {
- as_bad (_("Invalid Compare/Subtract Condition"));
- cmpltr = 0;
- }
- else
- {
- /* Negated condition requires an opcode change. */
- opcode |= 1 << 27;
- }
- }
- INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+ /* Handle MFCTL wide completer. */
+ case 'W':
+ if (strncasecmp (s, ",w", 2) != 0)
+ break;
+ s += 2;
+ continue;
- /* Handle a compare/subtract condition. */
- case 'a':
- cmpltr = 0;
- flag = 0;
- if (*s == ',')
- {
- s++;
- name = s;
- while (*s != ',' && *s != ' ' && *s != '\t')
- s += 1;
- c = *s;
- *s = 0x00;
- if (strcmp (name, "=") == 0)
- cmpltr = 1;
- else if (strcmp (name, "<") == 0)
- cmpltr = 2;
- else if (strcmp (name, "<=") == 0)
- cmpltr = 3;
- else if (strcasecmp (name, "<<") == 0)
- cmpltr = 4;
- else if (strcasecmp (name, "<<=") == 0)
- cmpltr = 5;
- else if (strcasecmp (name, "sv") == 0)
- cmpltr = 6;
- else if (strcasecmp (name, "od") == 0)
- cmpltr = 7;
- else if (strcasecmp (name, "tr") == 0)
- {
- cmpltr = 0;
- flag = 1;
- }
- else if (strcmp (name, "<>") == 0)
+ /* Handle an RFI restore completer. */
+ case 'r':
+ flag = 0;
+ if (!strncasecmp (s, ",r", 2))
{
- cmpltr = 1;
- flag = 1;
- }
- else if (strcmp (name, ">=") == 0)
- {
- cmpltr = 2;
- flag = 1;
- }
- else if (strcmp (name, ">") == 0)
- {
- cmpltr = 3;
- flag = 1;
- }
- else if (strcasecmp (name, ">>=") == 0)
- {
- cmpltr = 4;
- flag = 1;
- }
- else if (strcasecmp (name, ">>") == 0)
- {
- cmpltr = 5;
- flag = 1;
- }
- else if (strcasecmp (name, "nsv") == 0)
- {
- cmpltr = 6;
- flag = 1;
+ flag = 5;
+ s += 2;
}
- else if (strcasecmp (name, "ev") == 0)
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+
+ /* Handle a system control completer. */
+ case 'Z':
+ if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
{
- cmpltr = 7;
flag = 1;
+ s += 2;
}
else
- as_bad (_("Invalid Add Condition: %s"), name);
- *s = c;
- }
- opcode |= cmpltr << 13;
- INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+ flag = 0;
- /* Handle a non-negated add condition. */
- case 'd':
- cmpltr = 0;
- flag = 0;
- if (*s == ',')
- {
- s++;
- name = s;
- while (*s != ',' && *s != ' ' && *s != '\t')
- s += 1;
- c = *s;
- *s = 0x00;
- if (strcmp (name, "=") == 0)
- cmpltr = 1;
- else if (strcmp (name, "<") == 0)
- cmpltr = 2;
- else if (strcmp (name, "<=") == 0)
- cmpltr = 3;
- else if (strcasecmp (name, "nuv") == 0)
- cmpltr = 4;
- else if (strcasecmp (name, "znv") == 0)
- cmpltr = 5;
- else if (strcasecmp (name, "sv") == 0)
- cmpltr = 6;
- else if (strcasecmp (name, "od") == 0)
- cmpltr = 7;
- else if (strcasecmp (name, "tr") == 0)
- {
- cmpltr = 0;
- flag = 1;
- }
- else if (strcmp (name, "<>") == 0)
- {
- cmpltr = 1;
- flag = 1;
- }
- else if (strcmp (name, ">=") == 0)
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+
+ /* Handle intermediate/final completer for DCOR. */
+ case 'i':
+ flag = 0;
+ if (!strncasecmp (s, ",i", 2))
{
- cmpltr = 2;
flag = 1;
+ s += 2;
}
- else if (strcmp (name, ">") == 0)
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+
+ /* Handle zero/sign extension completer. */
+ case 'z':
+ flag = 1;
+ if (!strncasecmp (s, ",z", 2))
{
- cmpltr = 3;
- flag = 1;
+ flag = 0;
+ s += 2;
}
- else if (strcasecmp (name, "uv") == 0)
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
+
+ /* Handle add completer. */
+ case 'a':
+ flag = 1;
+ if (!strncasecmp (s, ",l", 2))
{
- cmpltr = 4;
- flag = 1;
+ flag = 2;
+ s += 2;
}
- else if (strcasecmp (name, "vnz") == 0)
+ else if (!strncasecmp (s, ",tsv", 4))
{
- cmpltr = 5;
- flag = 1;
+ flag = 3;
+ s += 4;
}
- else if (strcasecmp (name, "nsv") == 0)
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
+
+ /* Handle 64 bit carry for ADD. */
+ case 'Y':
+ flag = 0;
+ if (!strncasecmp (s, ",dc,tsv", 7) ||
+ !strncasecmp (s, ",tsv,dc", 7))
{
- cmpltr = 6;
flag = 1;
+ s += 7;
}
- else if (strcasecmp (name, "ev") == 0)
+ else if (!strncasecmp (s, ",dc", 3))
{
- cmpltr = 7;
- flag = 1;
+ flag = 0;
+ s += 3;
}
else
- as_bad (_("Invalid Add Condition: %s"), name);
- *s = c;
- }
- opcode |= cmpltr << 13;
- INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+ break;
- /* HANDLE a logical instruction condition. */
- case '&':
- cmpltr = 0;
- flag = 0;
- if (*s == ',')
- {
- s++;
- name = s;
- while (*s != ',' && *s != ' ' && *s != '\t')
- s += 1;
- c = *s;
- *s = 0x00;
-
-
- if (strcmp (name, "=") == 0)
- cmpltr = 1;
- else if (strcmp (name, "<") == 0)
- cmpltr = 2;
- else if (strcmp (name, "<=") == 0)
- cmpltr = 3;
- else if (strcasecmp (name, "od") == 0)
- cmpltr = 7;
- else if (strcasecmp (name, "tr") == 0)
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+ /* Handle 32 bit carry for ADD. */
+ case 'y':
+ flag = 0;
+ if (!strncasecmp (s, ",c,tsv", 6) ||
+ !strncasecmp (s, ",tsv,c", 6))
{
- cmpltr = 0;
flag = 1;
+ s += 6;
}
- else if (strcmp (name, "<>") == 0)
+ else if (!strncasecmp (s, ",c", 2))
{
- cmpltr = 1;
- flag = 1;
+ flag = 0;
+ s += 2;
}
- else if (strcmp (name, ">=") == 0)
+ else
+ break;
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+ /* Handle trap on signed overflow. */
+ case 'v':
+ flag = 0;
+ if (!strncasecmp (s, ",tsv", 4))
{
- cmpltr = 2;
flag = 1;
+ s += 4;
}
- else if (strcmp (name, ">") == 0)
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+ /* Handle trap on condition and overflow. */
+ case 't':
+ flag = 0;
+ if (!strncasecmp (s, ",tc,tsv", 7) ||
+ !strncasecmp (s, ",tsv,tc", 7))
{
- cmpltr = 3;
flag = 1;
+ s += 7;
}
- else if (strcasecmp (name, "ev") == 0)
+ else if (!strncasecmp (s, ",tc", 3))
{
- cmpltr = 7;
- flag = 1;
+ flag = 0;
+ s += 3;
}
else
- as_bad (_("Invalid Logical Instruction Condition."));
- *s = c;
- }
- opcode |= cmpltr << 13;
- INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+ break;
- /* Handle a unit instruction condition. */
- case 'U':
- cmpltr = 0;
- flag = 0;
- if (*s == ',')
- {
- s++;
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
-
- if (strncasecmp (s, "sbz", 3) == 0)
- {
- cmpltr = 2;
- s += 3;
- }
- else if (strncasecmp (s, "shz", 3) == 0)
- {
- cmpltr = 3;
- s += 3;
- }
- else if (strncasecmp (s, "sdc", 3) == 0)
- {
- cmpltr = 4;
- s += 3;
- }
- else if (strncasecmp (s, "sbc", 3) == 0)
+ /* Handle 64 bit borrow for SUB. */
+ case 'B':
+ flag = 0;
+ if (!strncasecmp (s, ",db,tsv", 7) ||
+ !strncasecmp (s, ",tsv,db", 7))
{
- cmpltr = 6;
- s += 3;
- }
- else if (strncasecmp (s, "shc", 3) == 0)
- {
- cmpltr = 7;
- s += 3;
- }
- else if (strncasecmp (s, "tr", 2) == 0)
- {
- cmpltr = 0;
flag = 1;
- s += 2;
+ s += 7;
}
- else if (strncasecmp (s, "nbz", 3) == 0)
+ else if (!strncasecmp (s, ",db", 3))
{
- cmpltr = 2;
- flag = 1;
+ flag = 0;
s += 3;
}
- else if (strncasecmp (s, "nhz", 3) == 0)
+ else
+ break;
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+ /* Handle 32 bit borrow for SUB. */
+ case 'b':
+ flag = 0;
+ if (!strncasecmp (s, ",b,tsv", 6) ||
+ !strncasecmp (s, ",tsv,b", 6))
{
- cmpltr = 3;
flag = 1;
- s += 3;
+ s += 6;
}
- else if (strncasecmp (s, "ndc", 3) == 0)
+ else if (!strncasecmp (s, ",b", 2))
{
- cmpltr = 4;
- flag = 1;
- s += 3;
+ flag = 0;
+ s += 2;
}
- else if (strncasecmp (s, "nbc", 3) == 0)
+ else
+ break;
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
+
+ /* Handle trap condition completer for UADDCM. */
+ case 'T':
+ flag = 0;
+ if (!strncasecmp (s, ",tc", 3))
{
- cmpltr = 6;
flag = 1;
s += 3;
}
- else if (strncasecmp (s, "nhc", 3) == 0)
+
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
+
+ /* Handle signed/unsigned at 21. */
+ case 'S':
+ {
+ int sign = 1;
+ if (strncasecmp (s, ",s", 2) == 0)
+ {
+ sign = 1;
+ s += 2;
+ }
+ else if (strncasecmp (s, ",u", 2) == 0)
+ {
+ sign = 0;
+ s += 2;
+ }
+
+ INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
+ }
+
+ /* Handle left/right combination at 17:18. */
+ case 'h':
+ if (*s++ == ',')
{
- cmpltr = 7;
- flag = 1;
- s += 3;
+ int lr = 0;
+ if (*s == 'r')
+ lr = 2;
+ else if (*s == 'l')
+ lr = 0;
+ else
+ as_bad(_("Invalid left/right combination completer"));
+
+ s++;
+ INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
}
else
- as_bad (_("Invalid Logical Instruction Condition."));
- }
- opcode |= cmpltr << 13;
- INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+ as_bad(_("Invalid left/right combination completer"));
+ break;
- /* Handle a shift/extract/deposit condition. */
- case '|':
- case '>':
- cmpltr = 0;
- if (*s == ',')
- {
- save_s = s++;
-
-
- name = s;
- while (*s != ',' && *s != ' ' && *s != '\t')
- s += 1;
- c = *s;
- *s = 0x00;
- if (strcmp (name, "=") == 0)
- cmpltr = 1;
- else if (strcmp (name, "<") == 0)
- cmpltr = 2;
- else if (strcasecmp (name, "od") == 0)
- cmpltr = 3;
- else if (strcasecmp (name, "tr") == 0)
- cmpltr = 4;
- else if (strcmp (name, "<>") == 0)
- cmpltr = 5;
- else if (strcmp (name, ">=") == 0)
- cmpltr = 6;
- else if (strcasecmp (name, "ev") == 0)
- cmpltr = 7;
- /* Handle movb,n. Put things back the way they were.
- This includes moving s back to where it started. */
- else if (strcasecmp (name, "n") == 0 && *args == '|')
+ /* Handle saturation at 24:25. */
+ case 'H':
+ {
+ int sat = 3;
+ if (strncasecmp (s, ",ss", 3) == 0)
+ {
+ sat = 1;
+ s += 3;
+ }
+ else if (strncasecmp (s, ",us", 3) == 0)
+ {
+ sat = 0;
+ s += 3;
+ }
+
+ INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
+ }
+
+ /* Handle permutation completer. */
+ case '*':
+ if (*s++ == ',')
{
- *s = c;
- s = save_s;
+ int permloc[4] = {13,10,8,6};
+ int perm = 0;
+ int i = 0;
+ for (; i < 4; i++)
+ {
+ switch (*s++)
+ {
+ case '0':
+ perm = 0;
+ break;
+ case '1':
+ perm = 1;
+ break;
+ case '2':
+ perm = 2;
+ break;
+ case '3':
+ perm = 3;
+ break;
+ default:
+ as_bad(_("Invalid permutation completer"));
+ }
+ opcode |= perm << permloc[i];
+ }
continue;
}
else
- as_bad (_("Invalid Shift/Extract/Deposit Condition."));
- *s = c;
- }
- INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+ as_bad(_("Invalid permutation completer"));
+ break;
- /* Handle bvb and bb conditions. */
- case '~':
- cmpltr = 0;
- if (*s == ',')
- {
- s++;
- if (strncmp (s, "<", 1) == 0)
- {
- cmpltr = 0;
- s++;
- }
- else if (strncmp (s, ">=", 2) == 0)
- {
- cmpltr = 1;
- s += 2;
- }
- else
- as_bad (_("Invalid Bit Branch Condition: %c"), *s);
+ default:
+ abort ();
}
- INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
+ break;
+
+ /* Handle all conditions. */
+ case '?':
+ {
+ args++;
+ switch (*args)
+ {
+ /* Handle FP compare conditions. */
+ case 'f':
+ cond = pa_parse_fp_cmp_cond (&s);
+ INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+
+ /* Handle an add condition. */
+ case 'A':
+ case 'a':
+ cmpltr = 0;
+ flag = 0;
+ if (*s == ',')
+ {
+ s++;
+
+ /* 64 bit conditions. */
+ if (*args == 'A')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+ name = s;
+
+ name = s;
+ while (*s != ',' && *s != ' ' && *s != '\t')
+ s += 1;
+ c = *s;
+ *s = 0x00;
+ if (strcmp (name, "=") == 0)
+ cmpltr = 1;
+ else if (strcmp (name, "<") == 0)
+ cmpltr = 2;
+ else if (strcmp (name, "<=") == 0)
+ cmpltr = 3;
+ else if (strcasecmp (name, "nuv") == 0)
+ cmpltr = 4;
+ else if (strcasecmp (name, "znv") == 0)
+ cmpltr = 5;
+ else if (strcasecmp (name, "sv") == 0)
+ cmpltr = 6;
+ else if (strcasecmp (name, "od") == 0)
+ cmpltr = 7;
+ else if (strcasecmp (name, "tr") == 0)
+ {
+ cmpltr = 0;
+ flag = 1;
+ }
+ else if (strcmp (name, "<>") == 0)
+ {
+ cmpltr = 1;
+ flag = 1;
+ }
+ else if (strcmp (name, ">=") == 0)
+ {
+ cmpltr = 2;
+ flag = 1;
+ }
+ else if (strcmp (name, ">") == 0)
+ {
+ cmpltr = 3;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "uv") == 0)
+ {
+ cmpltr = 4;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "vnz") == 0)
+ {
+ cmpltr = 5;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "nsv") == 0)
+ {
+ cmpltr = 6;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "ev") == 0)
+ {
+ cmpltr = 7;
+ flag = 1;
+ }
+ /* ",*" is a valid condition. */
+ else if (*args == 'a')
+ as_bad (_("Invalid Add Condition: %s"), name);
+ *s = c;
+ }
+ opcode |= cmpltr << 13;
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+ /* Handle non-negated add and branch condition. */
+ case 'd':
+ cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
+ if (cmpltr < 0)
+ {
+ as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
+ cmpltr = 0;
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle negated add and branch condition. */
+ case 'D':
+ abort ();
+
+ /* Handle wide-mode non-negated add and branch condition. */
+ case 'w':
+ abort ();
+
+ /* Handle wide-mode negated add and branch condition. */
+ case 'W':
+ abort();
+
+ /* Handle a negated or non-negated add and branch
+ condition. */
+ case '@':
+ save_s = s;
+ cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1);
+ if (cmpltr < 0)
+ {
+ s = save_s;
+ cmpltr = pa_parse_neg_add_cmpltr (&s, 1);
+ if (cmpltr < 0)
+ {
+ as_bad (_("Invalid Compare/Subtract Condition"));
+ cmpltr = 0;
+ }
+ else
+ {
+ /* Negated condition requires an opcode change. */
+ opcode |= 1 << 27;
+ }
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle branch on bit conditions. */
+ case 'B':
+ case 'b':
+ cmpltr = 0;
+ if (*s == ',')
+ {
+ s++;
+
+ if (*args == 'B')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+
+ if (strncmp (s, "<", 1) == 0)
+ {
+ cmpltr = 0;
+ s++;
+ }
+ else if (strncmp (s, ">=", 2) == 0)
+ {
+ cmpltr = 1;
+ s += 2;
+ }
+ else
+ as_bad (_("Invalid Bit Branch Condition: %c"), *s);
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
+
+ /* Handle a compare/subtract condition. */
+ case 'S':
+ case 's':
+ cmpltr = 0;
+ flag = 0;
+ if (*s == ',')
+ {
+ s++;
+
+ /* 64 bit conditions. */
+ if (*args == 'S')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+ name = s;
+
+ name = s;
+ while (*s != ',' && *s != ' ' && *s != '\t')
+ s += 1;
+ c = *s;
+ *s = 0x00;
+ if (strcmp (name, "=") == 0)
+ cmpltr = 1;
+ else if (strcmp (name, "<") == 0)
+ cmpltr = 2;
+ else if (strcmp (name, "<=") == 0)
+ cmpltr = 3;
+ else if (strcasecmp (name, "<<") == 0)
+ cmpltr = 4;
+ else if (strcasecmp (name, "<<=") == 0)
+ cmpltr = 5;
+ else if (strcasecmp (name, "sv") == 0)
+ cmpltr = 6;
+ else if (strcasecmp (name, "od") == 0)
+ cmpltr = 7;
+ else if (strcasecmp (name, "tr") == 0)
+ {
+ cmpltr = 0;
+ flag = 1;
+ }
+ else if (strcmp (name, "<>") == 0)
+ {
+ cmpltr = 1;
+ flag = 1;
+ }
+ else if (strcmp (name, ">=") == 0)
+ {
+ cmpltr = 2;
+ flag = 1;
+ }
+ else if (strcmp (name, ">") == 0)
+ {
+ cmpltr = 3;
+ flag = 1;
+ }
+ else if (strcasecmp (name, ">>=") == 0)
+ {
+ cmpltr = 4;
+ flag = 1;
+ }
+ else if (strcasecmp (name, ">>") == 0)
+ {
+ cmpltr = 5;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "nsv") == 0)
+ {
+ cmpltr = 6;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "ev") == 0)
+ {
+ cmpltr = 7;
+ flag = 1;
+ }
+ /* ",*" is a valid condition. */
+ else if (*args != 'S')
+ as_bad (_("Invalid Compare/Subtract Condition: %s"),
+ name);
+ *s = c;
+ }
+ opcode |= cmpltr << 13;
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+ /* Handle a non-negated compare condition. */
+ case 't':
+ cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
+ if (cmpltr < 0)
+ {
+ as_bad (_("Invalid Compare/Subtract Condition: %c"), *s);
+ cmpltr = 0;
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle a negated compare condition. */
+ case 'T':
+ abort ();
+
+ /* Handle a 64 bit non-negated compare condition. */
+ case 'r':
+ abort ();
+
+ /* Handle a 64 bit negated compare condition. */
+ case 'R':
+ abort ();
+
+ /* Handle a 64 bit cmpib condition. */
+ case 'Q':
+ abort ();
+
+ /* Handle a negated or non-negated compare/subtract
+ condition. */
+ case 'n':
+ save_s = s;
+ cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1);
+ if (cmpltr < 0)
+ {
+ s = save_s;
+ cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1);
+ if (cmpltr < 0)
+ {
+ as_bad (_("Invalid Compare/Subtract Condition."));
+ cmpltr = 0;
+ }
+ else
+ {
+ /* Negated condition requires an opcode change. */
+ opcode |= 1 << 27;
+ }
+ }
+
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle a logical instruction condition. */
+ case 'L':
+ case 'l':
+ cmpltr = 0;
+ flag = 0;
+ if (*s == ',')
+ {
+ s++;
- /* Handle a system control completer. */
- case 'Z':
- if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
- {
- flag = 1;
- s += 2;
- }
- else
- flag = 0;
+ /* 64 bit conditions. */
+ if (*args == 'L')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+ name = s;
+
+ name = s;
+ while (*s != ',' && *s != ' ' && *s != '\t')
+ s += 1;
+ c = *s;
+ *s = 0x00;
+
+
+ if (strcmp (name, "=") == 0)
+ cmpltr = 1;
+ else if (strcmp (name, "<") == 0)
+ cmpltr = 2;
+ else if (strcmp (name, "<=") == 0)
+ cmpltr = 3;
+ else if (strcasecmp (name, "od") == 0)
+ cmpltr = 7;
+ else if (strcasecmp (name, "tr") == 0)
+ {
+ cmpltr = 0;
+ flag = 1;
+ }
+ else if (strcmp (name, "<>") == 0)
+ {
+ cmpltr = 1;
+ flag = 1;
+ }
+ else if (strcmp (name, ">=") == 0)
+ {
+ cmpltr = 2;
+ flag = 1;
+ }
+ else if (strcmp (name, ">") == 0)
+ {
+ cmpltr = 3;
+ flag = 1;
+ }
+ else if (strcasecmp (name, "ev") == 0)
+ {
+ cmpltr = 7;
+ flag = 1;
+ }
+ /* ",*" is a valid condition. */
+ else if (*args != 'L')
+ as_bad (_("Invalid Logical Instruction Condition."));
+ *s = c;
+ }
+ opcode |= cmpltr << 13;
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
+
+ /* Handle a shift/extract/deposit condition. */
+ case 'X':
+ case 'x':
+ case 'y':
+ cmpltr = 0;
+ if (*s == ',')
+ {
+ save_s = s++;
+
+ /* 64 bit conditions. */
+ if (*args == 'X')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+ name = s;
+
+ name = s;
+ while (*s != ',' && *s != ' ' && *s != '\t')
+ s += 1;
+ c = *s;
+ *s = 0x00;
+ if (strcmp (name, "=") == 0)
+ cmpltr = 1;
+ else if (strcmp (name, "<") == 0)
+ cmpltr = 2;
+ else if (strcasecmp (name, "od") == 0)
+ cmpltr = 3;
+ else if (strcasecmp (name, "tr") == 0)
+ cmpltr = 4;
+ else if (strcmp (name, "<>") == 0)
+ cmpltr = 5;
+ else if (strcmp (name, ">=") == 0)
+ cmpltr = 6;
+ else if (strcasecmp (name, "ev") == 0)
+ cmpltr = 7;
+ /* Handle movb,n. Put things back the way they were.
+ This includes moving s back to where it started. */
+ else if (strcasecmp (name, "n") == 0 && *args == 'y')
+ {
+ *s = c;
+ s = save_s;
+ continue;
+ }
+ /* ",*" is a valid condition. */
+ else if (*args != 'X')
+ as_bad (_("Invalid Shift/Extract/Deposit Condition."));
+ *s = c;
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle a unit instruction condition. */
+ case 'U':
+ case 'u':
+ cmpltr = 0;
+ flag = 0;
+ if (*s == ',')
+ {
+ s++;
+
+ /* 64 bit conditions. */
+ if (*args == 'U')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+
+ if (strncasecmp (s, "sbz", 3) == 0)
+ {
+ cmpltr = 2;
+ s += 3;
+ }
+ else if (strncasecmp (s, "shz", 3) == 0)
+ {
+ cmpltr = 3;
+ s += 3;
+ }
+ else if (strncasecmp (s, "sdc", 3) == 0)
+ {
+ cmpltr = 4;
+ s += 3;
+ }
+ else if (strncasecmp (s, "sbc", 3) == 0)
+ {
+ cmpltr = 6;
+ s += 3;
+ }
+ else if (strncasecmp (s, "shc", 3) == 0)
+ {
+ cmpltr = 7;
+ s += 3;
+ }
+ else if (strncasecmp (s, "tr", 2) == 0)
+ {
+ cmpltr = 0;
+ flag = 1;
+ s += 2;
+ }
+ else if (strncasecmp (s, "nbz", 3) == 0)
+ {
+ cmpltr = 2;
+ flag = 1;
+ s += 3;
+ }
+ else if (strncasecmp (s, "nhz", 3) == 0)
+ {
+ cmpltr = 3;
+ flag = 1;
+ s += 3;
+ }
+ else if (strncasecmp (s, "ndc", 3) == 0)
+ {
+ cmpltr = 4;
+ flag = 1;
+ s += 3;
+ }
+ else if (strncasecmp (s, "nbc", 3) == 0)
+ {
+ cmpltr = 6;
+ flag = 1;
+ s += 3;
+ }
+ else if (strncasecmp (s, "nhc", 3) == 0)
+ {
+ cmpltr = 7;
+ flag = 1;
+ s += 3;
+ }
+ /* ",*" is a valid condition. */
+ else if (*args != 'U')
+ as_bad (_("Invalid Unit Instruction Condition."));
+ }
+ opcode |= cmpltr << 13;
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
- INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
+ default:
+ abort ();
+ }
+ break;
+ }
/* Handle a nullification completer for branch instructions. */
case 'n':
continue;
}
+ /* Handle '%r1' implicit operand of addil instruction. */
+ case 'Z':
+ if (*s == ',' && *(s + 1) == '%' && *(s + 3) == '1'
+ && (*(s + 2) == 'r' || *(s + 2) == 'R'))
+ {
+ s += 4;
+ continue;
+ }
+ else
+ break;
+
+ /* Handle a 2 bit shift count at 25. */
+ case '.':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 3, 1, strict);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+
+ /* Handle a 4 bit shift count at 25. */
+ case '*':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 15, 0, strict);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
+
/* Handle a 5 bit shift count at 26. */
case 'p':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 31, 0, 0);
+ CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
+ /* Handle a 6 bit shift count at 20,22:26. */
+ case '~':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 63, 0, strict);
+ num = 63 - num;
+ opcode |= (num & 0x20) << 6;
+ INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
+
+ /* Handle a 6 bit field length at 23,27:31. */
+ case '%':
+ flag = 0;
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 64, 1, strict);
+ num--;
+ opcode |= (num & 0x20) << 3;
+ num = 31 - (num & 0x1f);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+
+ /* Handle a 6 bit field length at 19,27:31. */
+ case '|':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 64, 1, strict);
+ num--;
+ opcode |= (num & 0x20) << 7;
+ num = 31 - (num & 0x1f);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+
/* Handle a 5 bit bit position at 26. */
case 'P':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 31, 0, 0);
+ CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
+ /* Handle a 6 bit bit position at 20,22:26. */
+ case 'q':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 63, 0, strict);
+ opcode |= (num & 0x20) << 6;
+ INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
+
/* Handle a 5 bit immediate at 10. */
case 'Q':
-
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
if (the_insn.exp.X_op != O_constant)
break;
s = expr_end;
- CHECK_FIELD (num, 31, 0, 0);
+ CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
+ /* Handle a 9 bit immediate at 28. */
+ case '$':
+ num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
+ s = expr_end;
+ CHECK_FIELD (num, 511, 1, strict);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
+
/* Handle a 13 bit immediate at 18. */
case 'A':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 8191, 0, 0);
+ CHECK_FIELD (num, 8191, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
/* Handle a 26 bit immediate at 31. */
case 'D':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 671108864, 0, 0);
+ CHECK_FIELD (num, 671108864, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
/* Handle a 3 bit SFU identifier at 25. */
- case 'f':
+ case 'v':
if (*s++ != ',')
as_bad (_("Invalid SFU identifier"));
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 7, 0, 0);
+ CHECK_FIELD (num, 7, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
/* Handle a 20 bit SOP field for spop0. */
case 'O':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 1048575, 0, 0);
+ CHECK_FIELD (num, 1048575, 0, strict);
num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
/* Handle a 15bit SOP field for spop1. */
case 'o':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 32767, 0, 0);
+ CHECK_FIELD (num, 32767, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
/* Handle a 10bit SOP field for spop3. */
case '0':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 1023, 0, 0);
+ CHECK_FIELD (num, 1023, 0, strict);
num = (num & 0x1f) | ((num & 0x000003e0) << 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
/* Handle a 15 bit SOP field for spop2. */
case '1':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 32767, 0, 0);
+ CHECK_FIELD (num, 32767, 0, strict);
num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
if (*s++ != ',')
as_bad (_("Invalid COPR identifier"));
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 7, 0, 0);
+ CHECK_FIELD (num, 7, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
/* Handle a 22bit SOP field for copr. */
case '2':
num = pa_get_absolute_expression (&the_insn, &s);
+ if (strict && the_insn.exp.X_op != O_constant)
+ break;
s = expr_end;
- CHECK_FIELD (num, 4194303, 0, 0);
+ CHECK_FIELD (num, 4194303, 0, strict);
num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
the_insn.fpof2 = flag;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
- /* Handle FP compare conditions. */
- case 'M':
- cond = pa_parse_fp_cmp_cond (&s);
- INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+ /* Handle a source FP operand format completer at 20. */
+ case 'I':
+ flag = pa_parse_fp_format (&s);
+ the_insn.fpof1 = flag;
+ INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
- /* Handle L/R register halves like 't'. */
- case 'v':
- {
- struct pa_11_fp_reg_struct result;
+ /* Handle a floating point operand format at 26.
+ Only allows single and double precision. */
+ case 'H':
+ flag = pa_parse_fp_format (&s);
+ switch (flag)
+ {
+ case SGL:
+ opcode |= 0x20;
+ case DBL:
+ the_insn.fpof1 = flag;
+ continue;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- opcode |= result.number_part;
+ case QUAD:
+ case ILLEGAL_FMT:
+ default:
+ as_bad (_("Invalid Floating Point Operand Format."));
+ }
+ break;
- /* 0x30 opcodes are FP arithmetic operation opcodes
- and need to be turned into 0x38 opcodes. This
- is not necessary for loads/stores. */
- if (need_pa11_opcode (&the_insn, &result)
- && ((opcode & 0xfc000000) == 0x30000000))
- opcode |= 1 << 27;
+ /* Handle all floating point registers. */
+ case 'f':
+ switch (*++args)
+ {
+ /* Float target register. */
+ case 't':
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ num = pa_parse_number (&s, 0);
+ CHECK_FIELD (num, 31, 0, 0);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
- INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6);
- }
+ /* Float target register with L/R selection. */
+ case 'T':
+ {
+ struct pa_11_fp_reg_struct result;
- /* Handle L/R register halves like 'b'. */
- case 'E':
- {
- struct pa_11_fp_reg_struct result;
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ opcode |= result.number_part;
+
+ /* 0x30 opcodes are FP arithmetic operation opcodes
+ and need to be turned into 0x38 opcodes. This
+ is not necessary for loads/stores. */
+ if (need_pa11_opcode (&the_insn, &result)
+ && ((opcode & 0xfc000000) == 0x30000000))
+ opcode |= 1 << 27;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- opcode |= result.number_part << 21;
- if (need_pa11_opcode (&the_insn, &result))
- {
- opcode |= (result.l_r_select & 1) << 7;
- opcode |= 1 << 27;
+ INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6);
}
- continue;
- }
-
- /* Handle L/R register halves like 'b'. */
- case '3':
- {
- struct pa_11_fp_reg_struct result;
- int regnum;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- opcode |= (result.number_part & 0x1c) << 11;
- opcode |= (result.number_part & 0x3) << 9;
- opcode |= (result.l_r_select & 1) << 8;
- continue;
- }
+ /* Float operand 1. */
+ case 'a':
+ {
+ struct pa_11_fp_reg_struct result;
- /* Handle L/R register halves like 'x'. */
- case 'e':
- {
- struct pa_11_fp_reg_struct result;
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ opcode |= result.number_part << 21;
+ if (need_pa11_opcode (&the_insn, &result))
+ {
+ opcode |= (result.l_r_select & 1) << 7;
+ opcode |= 1 << 27;
+ }
+ continue;
+ }
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- opcode |= (result.number_part & 0x1f) << 16;
- if (need_pa11_opcode (&the_insn, &result))
+ /* Float operand 1 with L/R selection. */
+ case 'X':
+ case 'A':
{
- opcode |= (result.l_r_select & 1) << 1;
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ opcode |= result.number_part << 21;
+ opcode |= (result.l_r_select & 1) << 7;
+ continue;
}
- continue;
- }
- /* Handle L/R register halves like 'x'. */
- case 'X':
- {
- struct pa_11_fp_reg_struct result;
+ /* Float operand 2. */
+ case 'b':
+ {
+ struct pa_11_fp_reg_struct result;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- opcode |= (result.number_part & 0x1f) << 16;
- if (need_pa11_opcode (&the_insn, &result))
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ opcode |= (result.number_part & 0x1f) << 16;
+ if (need_pa11_opcode (&the_insn, &result))
+ {
+ opcode |= (result.l_r_select & 1) << 12;
+ opcode |= 1 << 27;
+ }
+ continue;
+ }
+
+ /* Float operand 2 with L/R selection. */
+ case 'B':
{
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ opcode |= (result.number_part & 0x1f) << 16;
opcode |= (result.l_r_select & 1) << 12;
- opcode |= 1 << 27;
+ continue;
}
- continue;
- }
- /* Handle a 5 bit register field at 10. */
- case '4':
- {
- struct pa_11_fp_reg_struct result;
+ /* Float operand 3 for fmpyfadd, fmpynfadd. */
+ case 'C':
+ {
+ struct pa_11_fp_reg_struct result;
+ int regnum;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- if (the_insn.fpof1 == SGL)
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ opcode |= (result.number_part & 0x1c) << 11;
+ opcode |= (result.number_part & 0x3) << 9;
+ opcode |= (result.l_r_select & 1) << 8;
+ continue;
+ }
+
+ /* Float mult operand 1 for fmpyadd, fmpysub */
+ case 'i':
{
- if (result.number_part < 16)
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ if (the_insn.fpof1 == SGL)
{
- as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
- break;
+ if (result.number_part < 16)
+ {
+ as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
+ break;
+ }
+
+ result.number_part &= 0xF;
+ result.number_part |= (result.l_r_select & 1) << 4;
}
-
- result.number_part &= 0xF;
- result.number_part |= (result.l_r_select & 1) << 4;
+ INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21);
}
- INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21);
- }
-
- /* Handle a 5 bit register field at 15. */
- case '6':
- {
- struct pa_11_fp_reg_struct result;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- if (the_insn.fpof1 == SGL)
+ /* Float mult operand 2 for fmpyadd, fmpysub */
+ case 'j':
{
- if (result.number_part < 16)
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ if (the_insn.fpof1 == SGL)
{
- as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
- break;
+ if (result.number_part < 16)
+ {
+ as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
+ break;
+ }
+ result.number_part &= 0xF;
+ result.number_part |= (result.l_r_select & 1) << 4;
}
- result.number_part &= 0xF;
- result.number_part |= (result.l_r_select & 1) << 4;
+ INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16);
}
- INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16);
- }
-
- /* Handle a 5 bit register field at 31. */
- case '7':
- {
- struct pa_11_fp_reg_struct result;
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- if (the_insn.fpof1 == SGL)
+ /* Float mult target for fmpyadd, fmpysub */
+ case 'k':
{
- if (result.number_part < 16)
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ if (the_insn.fpof1 == SGL)
{
- as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
- break;
+ if (result.number_part < 16)
+ {
+ as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
+ break;
+ }
+ result.number_part &= 0xF;
+ result.number_part |= (result.l_r_select & 1) << 4;
}
- result.number_part &= 0xF;
- result.number_part |= (result.l_r_select & 1) << 4;
+ INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0);
}
- INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0);
- }
- /* Handle a 5 bit register field at 20. */
- case '8':
- {
- struct pa_11_fp_reg_struct result;
+ /* Float add operand 1 for fmpyadd, fmpysub */
+ case 'l':
+ {
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ if (the_insn.fpof1 == SGL)
+ {
+ if (result.number_part < 16)
+ {
+ as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
+ break;
+ }
+ result.number_part &= 0xF;
+ result.number_part |= (result.l_r_select & 1) << 4;
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6);
+ }
- pa_parse_number (&s, &result);
- CHECK_FIELD (result.number_part, 31, 0, 0);
- if (the_insn.fpof1 == SGL)
+ /* Float add target for fmpyadd, fmpysub */
+ case 'm':
{
- if (result.number_part < 16)
+ struct pa_11_fp_reg_struct result;
+
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
+ pa_parse_number (&s, &result);
+ CHECK_FIELD (result.number_part, 31, 0, 0);
+ if (the_insn.fpof1 == SGL)
{
- as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
- break;
+ if (result.number_part < 16)
+ {
+ as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
+ break;
+ }
+ result.number_part &= 0xF;
+ result.number_part |= (result.l_r_select & 1) << 4;
}
- result.number_part &= 0xF;
- result.number_part |= (result.l_r_select & 1) << 4;
+ INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11);
}
- INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11);
- }
- /* Handle a 5 bit register field at 25. */
- case '9':
+ default:
+ abort ();
+ }
+ break;
+
+ /* Handle L/R register halves like 'x'. */
+ case 'e':
{
struct pa_11_fp_reg_struct result;
+ /* This should be more strict. Small steps. */
+ if (strict && *s != '%')
+ break;
pa_parse_number (&s, &result);
CHECK_FIELD (result.number_part, 31, 0, 0);
- if (the_insn.fpof1 == SGL)
+ opcode |= (result.number_part & 0x1f) << 16;
+ if (need_pa11_opcode (&the_insn, &result))
{
- if (result.number_part < 16)
- {
- as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
- break;
- }
- result.number_part &= 0xF;
- result.number_part |= (result.l_r_select & 1) << 4;
+ opcode |= (result.l_r_select & 1) << 1;
}
- INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6);
+ continue;
}
- /* Handle a floating point operand format at 26.
- Only allows single and double precision. */
- case 'H':
- flag = pa_parse_fp_format (&s);
- switch (flag)
- {
- case SGL:
- opcode |= 0x20;
- case DBL:
- the_insn.fpof1 = flag;
- continue;
-
- case QUAD:
- case ILLEGAL_FMT:
- default:
- as_bad (_("Invalid Floating Point Operand Format."));
- }
- break;
-
default:
abort ();
}
name[0] = tolower ((*str)[0]),
name[1] = tolower ((*str)[1]),
name[2] = 0;
-#ifdef OBJ_SOM
else if ((*str)[3] == '\'' || (*str)[3] == '%')
name[0] = tolower ((*str)[0]),
name[1] = tolower ((*str)[1]),
name[2] = tolower ((*str)[2]),
name[3] = 0;
-#endif
else
return e_fsel;
*s = c;
return evaluate_absolute (insn);
}
+ /* When in strict mode we have a non-match, fix up the pointers
+ and return to our caller. */
+ if (insn->exp.X_op != O_constant && strict)
+ {
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+ return 0;
+ }
if (insn->exp.X_op != O_constant)
{
as_bad (_("Bad segment (should be absolute)."));
pa_build_unwind_subspace (call_info)
struct call_info *call_info;
{
-#if 0
char *unwind;
asection *seg, *save_seg;
+ asymbol *sym;
subsegT subseg, save_subseg;
- int i;
+ int i, reloc;
char c, *p;
+ if (now_seg != text_section)
+ return;
+
+ if (bfd_get_arch_info (stdoutput)->bits_per_address == 32)
+ reloc = R_PARISC_DIR32;
+ else
+ reloc = R_PARISC_SEGREL32;
+
/* Get into the right seg/subseg. This may involve creating
the seg the first time through. Make sure to have the
old seg/subseg so that we can reset things when we are done. */
- subseg = SUBSEG_UNWIND;
seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
if (seg == ASEC_NULL)
{
seg = bfd_make_section_old_way (stdoutput, UNWIND_SECTION_NAME);
bfd_set_section_flags (stdoutput, seg,
SEC_READONLY | SEC_HAS_CONTENTS
- | SEC_LOAD | SEC_RELOC);
+ | SEC_LOAD | SEC_RELOC | SEC_ALLOC | SEC_DATA);
+ bfd_set_section_alignment (stdoutput, seg, 2);
}
save_seg = now_seg;
save_subseg = now_subseg;
- subseg_set (seg, subseg);
+ subseg_set (seg, 0);
/* Get some space to hold relocation information for the unwind
/* Relocation info. for start offset of the function. */
fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
call_info->start_symbol, (offsetT) 0,
- (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL);
+ (expressionS *) NULL, 0, reloc,
+ e_fsel, 32, 0, NULL);
p = frag_more (4);
md_number_to_chars (p, 0, 4);
fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
call_info->end_symbol, (offsetT) 0,
- (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL);
+ (expressionS *) NULL, 0, reloc,
+ e_fsel, 32, 0, NULL);
/* Dump it. */
unwind = (char *) &call_info->ci_unwind;
/* Return back to the original segment/subsegment. */
subseg_set (save_seg, save_subseg);
-#endif
}
#endif
{
input_line_pointer += 4;
symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION;
+ symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
type = SYMBOL_TYPE_DATA;
}
else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 11))
as_warn (_("could not set architecture and machine"));
}
+ else if (strncmp (level, "2.0w", 4) == 0)
+ {
+ input_line_pointer += 4;
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 25))
+ as_warn (_("could not set architecture and machine"));
+ }
else if (strncmp (level, "2.0", 3) == 0)
{
input_line_pointer += 3;
}
}
#endif
+
+#ifdef OBJ_ELF
+pa_end_of_source ()
+{
+ if (debug_type == DEBUG_DWARF2)
+ dwarf2_finish ();
+}
+#endif