+ /* 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 Add and Branch Condition: %c"), *s);
+ cmpltr = 0;
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle 64 bit wide-mode add and branch condition. */
+ case 'W':
+ cmpltr = pa_parse_addb_64_cmpltr (&s);
+ if (cmpltr < 0)
+ {
+ as_bad (_("Invalid Add and Branch Condition: %c"), *s);
+ cmpltr = 0;
+ }
+ else
+ {
+ /* Negated condition requires an opcode change. */
+ opcode |= (cmpltr & 8) << 24;
+ }
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
+
+ /* 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 32 bit compare and branch 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 and Branch Condition."));
+ cmpltr = 0;
+ }
+ else
+ {
+ /* Negated condition requires an opcode change. */
+ opcode |= 1 << 27;
+ }
+ }
+
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle a 64 bit compare and branch condition. */
+ case 'N':
+ cmpltr = pa_parse_cmpb_64_cmpltr (&s);
+ if (cmpltr >= 0)
+ {
+ /* Negated condition requires an opcode change. */
+ opcode |= (cmpltr & 8) << 26;
+ }
+ else
+ /* Not a 64 bit cond. Give 32 bit a chance. */
+ break;
+
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
+
+ /* Handle a 64 bit cmpib condition. */
+ case 'Q':
+ cmpltr = pa_parse_cmpib_64_cmpltr (&s);
+ if (cmpltr < 0)
+ /* Not a 64 bit cond. Give 32 bit a chance. */
+ break;
+
+ INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
+
+ /* Handle a logical instruction condition. */
+ case 'L':
+ case 'l':
+ cmpltr = 0;
+ flag = 0;
+ if (*s == ',')
+ {
+ s++;
+
+ /* 64 bit conditions. */
+ if (*args == 'L')
+ {
+ if (*s == '*')
+ s++;
+ else
+ break;
+ }
+ else if (*s == '*')
+ break;
+
+ 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;
+ 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;
+ }
+ else if (strncasecmp (s, "swz", 3) == 0)
+ {
+ cmpltr = 1;
+ flag = 0;
+ s += 3;
+ }
+ else if (strncasecmp (s, "swc", 3) == 0)
+ {
+ cmpltr = 5;
+ flag = 0;
+ s += 3;
+ }
+ else if (strncasecmp (s, "nwz", 3) == 0)
+ {
+ cmpltr = 1;
+ flag = 1;
+ s += 3;
+ }
+ else if (strncasecmp (s, "nwc", 3) == 0)
+ {
+ cmpltr = 5;
+ 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);
+
+ default:
+ abort ();
+ }
+ break;
+ }
+
+ /* Handle a nullification completer for branch instructions. */
+ case 'n':
+ nullif = pa_parse_nullif (&s);
+ INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
+
+ /* Handle a nullification completer for copr and spop insns. */
+ case 'N':
+ nullif = pa_parse_nullif (&s);
+ INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
+
+ /* Handle ,%r2 completer for new syntax branches. */
+ case 'L':
+ if (*s == ',' && strncasecmp (s + 1, "%r2", 3) == 0)
+ s += 4;
+ else if (*s == ',' && strncasecmp (s + 1, "%rp", 3) == 0)
+ s += 4;
+ else
+ break;
+ continue;
+
+ /* Handle 3 bit entry into the fp compare array. Valid values
+ are 0..6 inclusive. */
+ case 'h':
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)
+ {
+ num = evaluate_absolute (&the_insn);
+ CHECK_FIELD (num, 6, 0, 0);
+ num++;
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
+ }
+ else
+ break;
+
+ /* Handle 3 bit entry into the fp compare array. Valid values
+ are 0..6 inclusive. */
+ case 'm':
+ get_expression (s);
+ if (the_insn.exp.X_op == O_constant)
+ {
+ s = expr_end;
+ num = evaluate_absolute (&the_insn);
+ CHECK_FIELD (num, 6, 0, 0);
+ num = (num + 1) ^ 1;
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
+ }
+ else
+ break;
+
+ /* Handle graphics test completers for ftest */
+ case '=':
+ {
+ num = pa_parse_ftest_gfx_completer (&s);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+ }
+
+ /* Handle a 11 bit immediate at 31. */
+ case 'i':
+ the_insn.field_selector = pa_chk_field_selector (&s);
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)
+ {
+ num = evaluate_absolute (&the_insn);
+ CHECK_FIELD (num, 1023, -1024, 0);
+ num = low_sign_unext (num, 11);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+ }
+ else
+ {
+ if (is_DP_relative (the_insn.exp))
+ the_insn.reloc = R_HPPA_GOTOFF;
+ else if (is_PC_relative (the_insn.exp))
+ the_insn.reloc = R_HPPA_PCREL_CALL;
+ else
+ the_insn.reloc = R_HPPA;
+ the_insn.format = 11;
+ continue;
+ }
+
+ /* Handle a 14 bit immediate at 31. */
+ case 'J':
+ the_insn.field_selector = pa_chk_field_selector (&s);
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)
+ {
+ int a, m;
+
+ /* XXX the completer stored away tibits of information
+ for us to extract. We need a cleaner way to do this.
+ Now that we have lots of letters again, it would be
+ good to rethink this. */
+ m = (opcode & (1 << 8)) != 0;
+ a = (opcode & (1 << 9)) != 0;
+ opcode &= ~ (3 << 8);
+ num = evaluate_absolute (&the_insn);
+ if ((a == 1 && num >= 0) || (a == 0 && num < 0))
+ break;
+ CHECK_FIELD (num, 8191, -8192, 0);
+ num = low_sign_unext (num, 14);
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
+ }
+ else
+ {
+ break;
+ }
+
+ /* Handle a 14 bit immediate at 31. */
+ case 'K':
+ the_insn.field_selector = pa_chk_field_selector (&s);
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)
+ {
+ int a, m;
+
+ /* XXX the completer stored away tibits of information
+ for us to extract. We need a cleaner way to do this.
+ Now that we have lots of letters again, it would be
+ good to rethink this. */
+ m = (opcode & (1 << 8)) != 0;
+ a = (opcode & (1 << 9)) != 0;
+ opcode &= ~ (3 << 8);
+ num = evaluate_absolute (&the_insn);
+ if ((a == 1 && num < 0) || (a == 0 && num > 0))
+ break;
+ if (num % 4)
+ break;
+ CHECK_FIELD (num, 8191, -8192, 0);
+ if (num < 0)
+ opcode |= 1;
+ num &= 0x1fff;
+ num >>= 2;
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
+ }
+ else
+ {
+ break;
+ }
+
+ /* Handle 14 bit immediate, shifted left three times. */
+ case '#':
+ the_insn.field_selector = pa_chk_field_selector (&s);
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)
+ {
+ num = evaluate_absolute (&the_insn);
+ if (num & 0x7)
+ break;
+ CHECK_FIELD (num, 8191, -8192, 0);
+ if (num < 0)
+ opcode |= 1;
+ num &= 0x1fff;
+ num >>= 3;
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 4);
+ }
+ else
+ {
+ if (is_DP_relative (the_insn.exp))
+ the_insn.reloc = R_HPPA_GOTOFF;
+ else if (is_PC_relative (the_insn.exp))
+ the_insn.reloc = R_HPPA_PCREL_CALL;
+ else
+ the_insn.reloc = R_HPPA;
+ the_insn.format = 14;
+ continue;
+ }
+ break;
+
+ /* Handle 14 bit immediate, shifted left twice. */
+ case 'd':
+ the_insn.field_selector = pa_chk_field_selector (&s);
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)
+ {
+ num = evaluate_absolute (&the_insn);
+ if (num & 0x3)
+ break;
+ CHECK_FIELD (num, 8191, -8192, 0);
+ if (num < 0)
+ opcode |= 1;
+ num &= 0x1fff;
+ num >>= 2;
+ INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
+ }
+ else
+ {
+ if (is_DP_relative (the_insn.exp))
+ the_insn.reloc = R_HPPA_GOTOFF;
+ else if (is_PC_relative (the_insn.exp))
+ the_insn.reloc = R_HPPA_PCREL_CALL;
+ else
+ the_insn.reloc = R_HPPA;
+ the_insn.format = 14;
+ continue;
+ }
+
+ /* Handle a 14 bit immediate at 31. */
+ case 'j':
+ the_insn.field_selector = pa_chk_field_selector (&s);
+ get_expression (s);
+ s = expr_end;
+ if (the_insn.exp.X_op == O_constant)