📄 tc-i960.c
字号:
int arch; };static const struct tabentry arch_tab[] ={ {"KA", ARCH_KA}, {"KB", ARCH_KB}, {"SA", ARCH_KA}, /* Synonym for KA */ {"SB", ARCH_KB}, /* Synonym for KB */ {"KC", ARCH_MC}, /* Synonym for MC */ {"MC", ARCH_MC}, {"CA", ARCH_CA}, {"JX", ARCH_JX}, {"HX", ARCH_HX}, {NULL, 0}};intmd_parse_option (c, arg) int c; char *arg;{ switch (c) { case OPTION_LINKRELAX: linkrelax = 1; flag_keep_locals = 1; break; case OPTION_NORELAX: norelax = 1; break; case 'b': instrument_branches = 1; break; case 'A': { const struct tabentry *tp; char *p = arg; for (tp = arch_tab; tp->flag != NULL; tp++) if (!strcmp (p, tp->flag)) break; if (tp->flag == NULL) { as_bad (_("invalid architecture %s"), p); return 0; } else architecture = tp->arch; } break; default: return 0; } return 1;}voidmd_show_usage (stream) FILE *stream;{ int i; fprintf (stream, _("I960 options:\n")); for (i = 0; arch_tab[i].flag; i++) fprintf (stream, "%s-A%s", i ? " | " : "", arch_tab[i].flag); fprintf (stream, _("\n\ specify variant of 960 architecture\n\-b add code to collect statistics about branches taken\n\-link-relax preserve individual alignment directives so linker\n\ can do relaxing (b.out format only)\n\-no-relax don't alter compare-and-branch instructions for\n\ long displacements\n"));}/***************************************************************************** md_convert_frag: Called by base assembler after address relaxation is finished: modify variable fragments according to how much relaxation was done. If the fragment substate is still 1, a 13-bit displacement was enough to reach the symbol in question. Set up an address fixup, but otherwise leave the cobr instruction alone. If the fragment substate is 2, a 13-bit displacement was not enough. Replace the cobr with a two instructions (a compare and a branch). *************************************************************************** */#ifndef BFD_ASSEMBLERvoidmd_convert_frag (headers, seg, fragP) object_headers *headers; segT seg; fragS *fragP;#elsevoidmd_convert_frag (abfd, sec, fragP) bfd *abfd; segT sec; fragS *fragP;#endif{ fixS *fixP; /* Structure describing needed address fix */ switch (fragP->fr_subtype) { case 1: /* LEAVE SINGLE COBR INSTRUCTION */ fixP = fix_new (fragP, fragP->fr_opcode - fragP->fr_literal, 4, fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC); fixP->fx_bit_fixP = (bit_fixS *) 13; /* size of bit field */ break; case 2: /* REPLACE COBR WITH COMPARE/BRANCH INSTRUCTIONS */ relax_cobr (fragP); break; default: BAD_CASE (fragP->fr_subtype); break; }}/***************************************************************************** md_estimate_size_before_relax: How much does it look like *fragP will grow? Called by base assembler just before address relaxation. Return the amount by which the fragment will grow. Any symbol that is now undefined will not become defined; cobr's based on undefined symbols will have to be replaced with a compare instruction and a branch instruction, and the code fragment will grow by 4 bytes. *************************************************************************** */intmd_estimate_size_before_relax (fragP, segment_type) register fragS *fragP; register segT segment_type;{ /* If symbol is undefined in this segment, go to "relaxed" state (compare and branch instructions instead of cobr) right now. */ if (S_GET_SEGMENT (fragP->fr_symbol) != segment_type) { relax_cobr (fragP); return 4; } return 0;} /* md_estimate_size_before_relax() */#if defined(OBJ_AOUT) | defined(OBJ_BOUT)/***************************************************************************** md_ri_to_chars: This routine exists in order to overcome machine byte-order problems when dealing with bit-field entries in the relocation_info struct. But relocation info will be used on the host machine only (only executable code is actually downloaded to the i80960). Therefore, we leave it in host byte order. The above comment is no longer true. This routine now really does do the reordering (Ian Taylor 28 Aug 92). *************************************************************************** */static voidmd_ri_to_chars (where, ri) char *where; struct relocation_info *ri;{ md_number_to_chars (where, ri->r_address, sizeof (ri->r_address)); where[4] = ri->r_index & 0x0ff; where[5] = (ri->r_index >> 8) & 0x0ff; where[6] = (ri->r_index >> 16) & 0x0ff; where[7] = ((ri->r_pcrel << 0) | (ri->r_length << 1) | (ri->r_extern << 3) | (ri->r_bsr << 4) | (ri->r_disp << 5) | (ri->r_callj << 6));}#endif /* defined(OBJ_AOUT) | defined(OBJ_BOUT) *//* FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER *//***************************************************************************** brcnt_emit: Emit code to increment inline branch counter. See the comments above the declaration of 'br_cnt' for details on branch-prediction instrumentation. *************************************************************************** */static voidbrcnt_emit (){ ctrl_fmt (BR_CNT_FUNC, CALL, 1); /* Emit call to "increment" routine */ emit (0); /* Emit inline counter to be incremented */}/***************************************************************************** brlab_next: generate the next branch local label See the comments above the declaration of 'br_cnt' for details on branch-prediction instrumentation. *************************************************************************** */static char *brlab_next (){ static char buf[20]; sprintf (buf, "%s%d", BR_LABEL_BASE, br_cnt++); return buf;}/***************************************************************************** brtab_emit: generate the fetch-prediction branch table. See the comments above the declaration of 'br_cnt' for details on branch-prediction instrumentation. The code emitted here would be functionally equivalent to the following example assembler source. .data .align 2 BR_TAB_NAME: .word 0 # link to next table .word 3 # length of table .word LBRANCH0 # 1st entry in table proper .word LBRANCH1 .word LBRANCH2 **************************************************************************** */voidbrtab_emit (){ int i; char buf[20]; char *p; /* Where the binary was output to */ /* Pointer to description of deferred address fixup. */ fixS *fixP; if (!instrument_branches) { return; } subseg_set (data_section, 0); /* .data */ frag_align (2, 0, 0); /* .align 2 */ record_alignment (now_seg, 2); colon (BR_TAB_NAME); /* BR_TAB_NAME: */ emit (0); /* .word 0 #link to next table */ emit (br_cnt); /* .word n #length of table */ for (i = 0; i < br_cnt; i++) { sprintf (buf, "%s%d", BR_LABEL_BASE, i); p = emit (0); fixP = fix_new (frag_now, p - frag_now->fr_literal, 4, symbol_find (buf), 0, 0, NO_RELOC); }}/***************************************************************************** cobr_fmt: generate a COBR-format instruction *************************************************************************** */staticvoidcobr_fmt (arg, opcode, oP) /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */ char *arg[]; /* Opcode, with branch-prediction bits already set if necessary. */ long opcode; /* Pointer to description of instruction. */ struct i960_opcode *oP;{ long instr; /* 32-bit instruction */ struct regop regop; /* Description of register operand */ int n; /* Number of operands */ int var_frag; /* 1 if varying length code fragment should * be emitted; 0 if an address fix * should be emitted. */ instr = opcode; n = oP->num_ops; if (n >= 1) { /* First operand (if any) of a COBR is always a register operand. Parse it. */ parse_regop (®op, arg[1], oP->operand[0]); instr |= (regop.n << 19) | (regop.mode << 13); } if (n >= 2) { /* Second operand (if any) of a COBR is always a register operand. Parse it. */ parse_regop (®op, arg[2], oP->operand[1]); instr |= (regop.n << 14) | regop.special; } if (n < 3) { emit (instr); } else { if (instrument_branches) { brcnt_emit (); colon (brlab_next ()); } /* A third operand to a COBR is always a displacement. Parse it; if it's relaxable (a cobr "j" directive, or any cobr other than bbs/bbc when the "-norelax" option is not in use) set up a variable code fragment; otherwise set up an address fix. */ var_frag = !norelax || (oP->format == COJ); /* TRUE or FALSE */ get_cdisp (arg[3], "COBR", instr, 13, var_frag, 0); if (instrument_branches) { brcnt_emit (); } }} /* cobr_fmt() *//***************************************************************************** ctrl_fmt: generate a CTRL-format instruction *************************************************************************** */staticvoidctrl_fmt (targP, opcode, num_ops) char *targP; /* Pointer to text of lone operand (if any) */ long opcode; /* Template of instruction */ int num_ops; /* Number of operands */{ int instrument; /* TRUE iff we should add instrumentation to track * how often the branch is taken */ if (num_ops == 0) { emit (opcode); /* Output opcode */ } else { instrument = instrument_branches && (opcode != CALL) && (opcode != B) && (opcode != RET) && (opcode != BAL); if (instrument) { brcnt_emit (); colon (brlab_next ()); } /* The operand MUST be an ip-relative displacment. Parse it * and set up address fix for the instruction we just output. */ get_cdisp (targP, "CTRL", opcode, 24, 0, 0); if (instrument) { brcnt_emit (); } }}/***************************************************************************** emit: output instruction binary Output instruction binary, in target byte order, 4 bytes at a time. Return pointer to where it was placed. *************************************************************************** */staticchar *emit (instr) long instr; /* Word to be output, host byte order */{ char *toP; /* Where to output it */ toP = frag_more (4); /* Allocate storage */ md_number_to_chars (toP, instr, 4); /* Convert to target byte order */ return toP;}/***************************************************************************** get_args: break individual arguments out of comma-separated list Input assumptions: - all comments and labels have been removed - all strings of whitespace have been collapsed to a single blank. - all character constants ('x') have been replaced with decimal Output: args[0] is untouched. args[1] points to first operand, etc. All args: - are NULL-terminated - contain no whitespace Return value: Number of operands (0,1,2, or 3) or -1 on error. *************************************************************************** */static intget_args (p, args) /* Pointer to comma-separated operands; MUCKED BY US */ register char *p; /* Output arg: pointers to operands placed in args[1-3]. MUST ACCOMMODATE 4 ENTRIES (args[0-3]). */ char *args[];{ register int n; /* Number of operands */ register char *to; /* Skip lead white space */ while (*p == ' ') { p++; } if (*p == '\0') { return 0; } n = 1; args[1] = p; /* Squeze blanks out by moving non-blanks toward start of string. * Isolate operands, whenever comma is found. */ to = p; while (*p != '\0') { if (*p == ' ' && (! isalnum ((unsigned char) p[1]) || ! isalnum ((unsigned char) p[-1]))) { p++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -