📄 tc-hppa.c
字号:
/* Output the opcode. */ md_number_to_chars (to, the_insn.opcode, 4); /* If necessary output more stuff. */ if (the_insn.reloc != R_HPPA_NONE) fix_new_hppa (frag_now, (to - frag_now->fr_literal), 4, NULL, (offsetT) 0, &the_insn.exp, the_insn.pcrel, the_insn.reloc, the_insn.field_selector, the_insn.format, the_insn.arg_reloc, 0);#ifdef OBJ_ELF dwarf2_emit_insn (4);#endif}/* Do the real work for assembling a single instruction. Store results into the global "the_insn" variable. */static voidpa_ip (str) char *str;{ char *error_message = ""; char *s, c, *argstart, *name, *save_s; const char *args; int match = FALSE; int comma = 0; int cmpltr, nullif, flag, cond, num; unsigned long opcode; struct pa_opcode *insn;#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace ();#endif /* Convert everything up to the first whitespace character into lower case. */ for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++) if (isupper (*s)) *s = tolower (*s); /* Skip to something interesting. */ for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s) ; switch (*s) { case '\0': break; case ',': comma = 1; /*FALLTHROUGH */ case ' ': *s++ = '\0'; break; default: as_fatal (_("Unknown opcode: `%s'"), str); } save_s = str; /* Look up the opcode in the has table. */ if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL) { as_bad ("Unknown opcode: `%s'", str); return; } if (comma) { *--s = ','; } /* Mark the location where arguments for the instruction start, then start processing them. */ argstart = s; for (;;) { /* Do some initialization. */ opcode = insn->match; strict = (insn->flags & FLAG_STRICT); memset (&the_insn, 0, sizeof (the_insn)); the_insn.reloc = R_HPPA_NONE; /* If this instruction is specific to a particular architecture, then set a new architecture. */ /* But do not automatically promote to pa2.0. The automatic promotion crud is for compatability with HP's old assemblers only. */ if (insn->arch < 20 && bfd_get_mach (stdoutput) < insn->arch) { if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch)) as_warn (_("could not update architecture and machine")); } else if (bfd_get_mach (stdoutput) < insn->arch) { match = FALSE; goto failed; } /* Build the opcode, checking as we go to make sure that the operands match. */ for (args = insn->args;; ++args) { /* Absorb white space in instruction. */ while (*s == ' ' || *s == '\t') s++; switch (*args) { /* End of arguments. */ case '\0': if (*s == '\0') match = TRUE; break; case '+': if (*s == '+') { ++s; continue; } if (*s == '-') continue; break; /* These must match exactly. */ case '(': case ')': case ',': case ' ': if (*s++ == *args) continue; break; /* Handle a 5 bit register or control register field at 10. */ case 'b': case '^': if (!pa_parse_number (&s, 0)) break; num = pa_number; 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': if (!pa_parse_number (&s, 0)) break; num = pa_number; CHECK_FIELD (num, 31, 0, 0); INSERT_FIELD_AND_CONTINUE (opcode, num, 16); /* Handle a 5 bit register field at 31. */ case 't': if (!pa_parse_number (&s, 0)) break; num = pa_number; 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': if (!pa_parse_number (&s, 0)) break; num = pa_number; 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; /* 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); num = low_sign_unext (num, 5); 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; /* 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); num = low_sign_unext (num, 5); 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, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); /* 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, 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': if (!pa_parse_number (&s, 0)) break; num = pa_number; CHECK_FIELD (num, 3, 0, 1); INSERT_FIELD_AND_CONTINUE (opcode, num, 14); /* Handle a 3 bit space identifier at 18. */ case 'S': if (!pa_parse_number (&s, 0)) break; num = pa_number; CHECK_FIELD (num, 7, 0, 1); opcode |= re_assemble_3 (num); continue; /* Handle all completers. */ case 'c': switch (*++args) { /* Handle a completer for an indexing load or store. */ case 'x': { int uu = 0; int m = 0; int i = 0; while (*s == ',' && i < 2) { 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 ", 2) == 0) || (strncasecmp (s, "s,", 2) == 0)) uu = 1; /* When in strict mode this is a match failure. */ else if (strict) { s--; break; } 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); } /* Handle a short load/store completer. */ case 'm': case 'q': case 'J': case 'e': { int a = 0; int m = 0; if (*s == ',') { int found = 0; s++; if (strncasecmp (s, "ma", 2) == 0) { a = 0; m = 1; found = 1; } else if (strncasecmp (s, "mb", 2) == 0) { a = 1; m = 1; found = 1; } /* When in strict mode, pass through for cache op. */ if (!found && strict) s--; else { if (!found) as_bad (_("Invalid Short Load/Store Completer.")); s += 2; } } /* If we did not get a ma/mb completer, then we do not consider this a positive match for 'ce'. */ else if (*args == 'e') break; /* 'J', 'm' and 'q' are the same, except for where they encode the before/after field. */ if (*args == 'm') { opcode |= m << 5; INSERT_FIELD_AND_CONTINUE (opcode, a, 13); } else if (*args == 'q') { opcode |= m << 3; INSERT_FIELD_AND_CONTINUE (opcode, a, 2); } else if (*args == 'J') { /* M bit is explicit in the major opcode. */ INSERT_FIELD_AND_CONTINUE (opcode, a, 2); } else if (*args == 'e') { /* Stash the ma/mb flag temporarily in the instruction. We will use (and remove it) later when handling 'J', 'K', '<' & '>'. */ opcode |= a; continue; } } /* Handle a stbys completer. */ case 's': { 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 ", 2) == 0) || (strncasecmp (s, "b,", 2) == 0)) a = 0; else if (strncasecmp (s, "e", 1) == 0) a = 1; /* When in strict mode this is a match failure. */ else if (strict) { s--; break; } else as_bad (_("Invalid Store Bytes Short Completer")); s++; i++; } if (i > 2) as_bad (_("Invalid Store Bytes Short Completer")); opcode |= m << 5; INSERT_FIELD_AND_CONTINUE (opcode, a, 13); } /* Handle load cache hint completer. */ case 'c': cmpltr = 0; if (!strncmp(s, ",sl", 3)) { s += 3; cmpltr = 2; } INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10); /* Handle store cache hint completer. */ case 'C': cmpltr = 0; if (!strncmp(s, ",sl", 3)) { s += 3; cmpltr = 2; } else if (!strncmp(s, ",bc", 3)) { s += 3; cmpltr = 1; } INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10); /* Handle load and clear cache hint completer. */ case 'd': cmpltr = 0; if (!strncmp(s, ",co", 3)) { s += 3; cmpltr = 1; } INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10); /* Handle load ordering completer. */ case 'o': if (strncmp(s, ",o", 2) != 0) break; s += 2; continue; /* Handle a branch gate completer. */ case 'g': if (strncasecmp (s, ",gate", 5) != 0) break; s += 5; continue; /* Handle a branch link and push completer. */ case 'p': if (strncasecmp (s, ",l,push", 7) != 0) break; s += 7; continue; /* Handle a branch link completer. */ case 'l': if (strncasecmp (s, ",l", 2) != 0) break; s += 2; continue; /* Handle a branch pop completer. */ case 'P': if (strncasecmp (s, ",pop", 4) != 0) break; s += 4; continue; /* Handle a local processor completer. */ case 'L': if (strncasecmp (s, ",l", 2) != 0) break; s += 2; continue; /* Handle a PROBE read/write completer. */ case 'w': flag = 0; if (!strncasecmp (s, ",w", 2)) { flag = 1; s += 2; } else if (!strncasecmp (s, ",r", 2)) { flag = 0; s += 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -