📄 tc-mcore.c
字号:
for (i = 0; i < 2; i++) buf[i] = isascii (s[i]) ? tolower (s[i]) : 0; for (i = sizeof (psrmods) / sizeof (psrmods[0]); i--;) { if (! strncmp (psrmods[i].name, buf, 2)) { * reg = psrmods[i].value; return s + 2; } } as_bad (_("bad/missing psr specifier")); * reg = 0; return s;}static char *parse_exp (s, e) char * s; expressionS * e;{ char * save; char * new; /* Skip whitespace. */ while (isspace (* s)) ++ s; save = input_line_pointer; input_line_pointer = s; expression (e); if (e->X_op == O_absent) as_bad (_("missing operand")); new = input_line_pointer; input_line_pointer = save; return new;}static voidmake_name (s, p, n) char * s; char * p; int n;{ static const char hex[] = "0123456789ABCDEF"; s[0] = p[0]; s[1] = p[1]; s[2] = p[2]; s[3] = hex[(n >> 12) & 0xF]; s[4] = hex[(n >> 8) & 0xF]; s[5] = hex[(n >> 4) & 0xF]; s[6] = hex[(n) & 0xF]; s[7] = 0;}#define POOL_END_LABEL ".LE"#define POOL_START_LABEL ".LS"static voiddump_literals (isforce) int isforce;{ int i; struct literal * p; symbolS * brarsym; if (poolsize == 0) return; /* Must we branch around the literal table? */ if (isforce) { char * output; char brarname[8]; make_name (brarname, POOL_END_LABEL, poolnumber); brarsym = symbol_make (brarname); symbol_table_insert (brarsym); output = frag_var (rs_machine_dependent, md_relax_table[C (UNCD_JUMP, DISP32)].rlx_length, md_relax_table[C (UNCD_JUMP, DISP12)].rlx_length, C (UNCD_JUMP, 0), brarsym, 0, 0); output[0] = INST_BYTE0 (MCORE_INST_BR); /* br .+xxx */ output[1] = INST_BYTE1 (MCORE_INST_BR); } /* Make sure that the section is sufficiently aligned and that the literal table is aligned within it. */ record_alignment (now_seg, 2); frag_align (2, 0, 0); colon (S_GET_NAME (poolsym)); for (i = 0, p = litpool; i < poolsize; i++, p++) emit_expr (& p->e, 4); if (isforce) colon (S_GET_NAME (brarsym)); poolsize = 0;}static voidcheck_literals (kind, offset) int kind; int offset;{ poolspan += offset; /* SPANCLOSE and SPANEXIT are smaller numbers than SPANPANIC. SPANPANIC means that we must dump now. kind == 0 is any old instruction. kind > 0 means we just had a control transfer instruction. kind == 1 means within a function kind == 2 means we just left a function The dump_literals (1) call inserts a branch around the table, so we first look to see if its a situation where we won't have to insert a branch (e.g., the previous instruction was an unconditional branch). SPANPANIC is the point where we must dump a single-entry pool. it accounts for alignments and an inserted branch. the 'poolsize*2' accounts for the scenario where we do: lrw r1,lit1; lrw r2,lit2; lrw r3,lit3 Note that the 'lit2' reference is 2 bytes further along but the literal it references will be 4 bytes further along, so we must consider the poolsize into this equation. This is slightly over-cautious, but guarantees that we won't panic because a relocation is too distant. */ if (poolspan > SPANCLOSE && kind > 0) dump_literals (0); else if (poolspan > SPANEXIT && kind > 1) dump_literals (0); else if (poolspan >= (SPANPANIC - poolsize * 2)) dump_literals (1);}static intenter_literal (e, ispcrel) expressionS * e; int ispcrel;{ int i; struct literal * p; if (poolsize >= MAX_POOL_SIZE - 2) { /* The literal pool is as full as we can handle. We have to be 2 entries shy of the 1024/4=256 entries because we have to allow for the branch (2 bytes) and the alignment (2 bytes before the first insn referencing the pool and 2 bytes before the pool itself) == 6 bytes, rounds up to 2 entries. */ dump_literals (1); } if (poolsize == 0) { /* Create new literal pool. */ if (++ poolnumber > 0xFFFF) as_fatal (_("more than 65K literal pools")); make_name (poolname, POOL_START_LABEL, poolnumber); poolsym = symbol_make (poolname); symbol_table_insert (poolsym); poolspan = 0; } /* Search pool for value so we don't have duplicates. */ for (p = litpool, i = 0; i < poolsize; i++, p++) { if (e->X_op == p->e.X_op && e->X_add_symbol == p->e.X_add_symbol && e->X_add_number == p->e.X_add_number && ispcrel == p->ispcrel) { p->refcnt ++; return i; } } p->refcnt = 1; p->ispcrel = ispcrel; p->e = * e; poolsize ++; return i;}/* Parse a literal specification. -- either new or old syntax. old syntax: the user supplies the label and places the literal. new syntax: we put it into the literal pool. */static char *parse_rt (s, outputp, ispcrel, ep) char * s; char ** outputp; int ispcrel; expressionS * ep;{ expressionS e; int n; if (ep) /* Indicate nothing there. */ ep->X_op = O_absent; if (*s == '[') { s = parse_exp (s + 1, & e); if (*s == ']') s++; else as_bad (_("missing ']'")); } else { s = parse_exp (s, & e); n = enter_literal (& e, ispcrel); if (ep) *ep = e; /* Create a reference to pool entry. */ e.X_op = O_symbol; e.X_add_symbol = poolsym; e.X_add_number = n << 2; } * outputp = frag_more (2); fix_new_exp (frag_now, (*outputp) - frag_now->fr_literal, 2, & e, 1, BFD_RELOC_MCORE_PCREL_IMM8BY4); return s;}static char *parse_imm (s, val, min, max) char * s; unsigned * val; unsigned min; unsigned max;{ char * new; expressionS e; new = parse_exp (s, & e); if (e.X_op == O_absent) ; /* An error message has already been emitted. */ else if (e.X_op != O_constant) as_bad (_("operand must be a constant")); else if (e.X_add_number < min || e.X_add_number > max) as_bad (_("operand must be absolute in range %d..%d, not %d"), min, max, e.X_add_number); * val = e.X_add_number; return new;}static char *parse_mem (s, reg, off, siz) char * s; unsigned * reg; unsigned * off; unsigned siz;{ char * new; * off = 0; while (isspace (* s)) ++ s; if (* s == '(') { s = parse_reg (s + 1, reg); while (isspace (* s)) ++ s; if (* s == ',') { s = parse_imm (s + 1, off, 0, 63); if (siz > 1) { if (siz > 2) { if (* off & 0x3) as_bad (_("operand must be a multiple of 4")); * off >>= 2; } else { if (* off & 0x1) as_bad (_("operand must be a multiple of 2")); * off >>= 1; } } } while (isspace (* s)) ++ s; if (* s == ')') s ++; } else as_bad (_("base register expected")); return s;}/* This is the guts of the machine-dependent assembler. STR points to a machine dependent instruction. This function is supposed to emit the frags/bytes it assembles to. */voidmd_assemble (str) char * str;{ char * op_start; char * op_end; mcore_opcode_info * opcode; char * output; int nlen = 0; unsigned short inst; unsigned reg; unsigned off; unsigned isize; expressionS e; char name[20]; /* Drop leading whitespace. */ while (isspace (* str)) str ++; /* Find the op code end. */ for (op_start = op_end = str; nlen < 20 && !is_end_of_line [(unsigned char) *op_end] && *op_end != ' '; op_end++) { name[nlen] = op_start[nlen]; nlen++; } name [nlen] = 0; if (nlen == 0) { as_bad (_("can't find opcode ")); return; } opcode = (mcore_opcode_info *) hash_find (opcode_hash_control, name); if (opcode == NULL) { as_bad (_("unknown opcode \"%s\""), name); return; } inst = opcode->inst; isize = 2; switch (opcode->opclass) { case O0: output = frag_more (2); break; case OT: op_end = parse_imm (op_end + 1, & reg, 0, 3); inst |= reg; output = frag_more (2); break; case O1: op_end = parse_reg (op_end + 1, & reg); inst |= reg; output = frag_more (2); break; case JMP: op_end = parse_reg (op_end + 1, & reg); inst |= reg; output = frag_more (2); /* In a sifilter mode, we emit this insn 2 times, fixes problem of an interrupt during a jmp.. */ if (sifilter_mode) { output[0] = INST_BYTE0 (inst); output[1] = INST_BYTE1 (inst); output = frag_more (2); } break; case JSR: op_end = parse_reg (op_end + 1, & reg); if (reg == 15) as_bad (_("invalid register: r15 illegal")); inst |= reg; output = frag_more (2); if (sifilter_mode) { /* Replace with: bsr .+2 ; addi r15,6; jmp rx ; jmp rx */ inst = MCORE_INST_BSR; /* with 0 displacement */ output[0] = INST_BYTE0 (inst); output[1] = INST_BYTE1 (inst); output = frag_more (2); inst = MCORE_INST_ADDI; inst |= 15; /* addi r15,6 */ inst |= (6 - 1) << 4; /* over the jmp's */ output[0] = INST_BYTE0 (inst); output[1] = INST_BYTE1 (inst); output = frag_more (2); inst = MCORE_INST_JMP | reg; output[0] = INST_BYTE0 (inst); output[1] = INST_BYTE1 (inst); output = frag_more (2); /* 2nd emitted in fallthru */ } break; case OC: op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (*op_end == ',') { op_end = parse_creg (op_end + 1, & reg); inst |= reg << 4; } output = frag_more (2); break; case MULSH: if (cpu == M210) { as_bad (_("M340 specific opcode used when assembling for M210")); break; } /* drop through... */ case O2: op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') { op_end = parse_reg (op_end + 1, & reg); inst |= reg << 4; } else as_bad (_("second operand missing")); output = frag_more (2); break; case X1: /* Handle both syntax-> xtrb- r1,rx OR xtrb- rx */ op_end = parse_reg (op_end + 1, & reg); /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') /* xtrb- r1,rx */ { if (reg != 1) as_bad (_("destination register must be r1")); op_end = parse_reg (op_end + 1, & reg); } inst |= reg; output = frag_more (2); break; case O1R1: /* div- rx,r1 */ op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') { op_end = parse_reg (op_end + 1, & reg); if (reg != 1) as_bad (_("source register must be r1")); } else as_bad (_("second operand missing")); output = frag_more (2); break; case OI: op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') { op_end = parse_imm (op_end + 1, & reg, 1, 32); inst |= (reg - 1) << 4; } else as_bad (_("second operand missing")); output = frag_more (2); break; case OB: op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') { op_end = parse_imm (op_end + 1, & reg, 0, 31); inst |= reg << 4; } else as_bad (_("second operand missing")); output = frag_more (2); break; case OB2: /* like OB, but arg is 2^n instead of n */ op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') { op_end = parse_imm (op_end + 1, & reg, 1, 1 << 31); /* Further restrict the immediate to a power of two. */ if ((reg & (reg - 1)) == 0) reg = log2 (reg); else { reg = 0; as_bad (_("immediate is not a power of two")); } inst |= (reg) << 4; } else as_bad (_("second operand missing")); output = frag_more (2); break; case OBRa: /* Specific for bgeni: imm of 0->6 translate to movi. */ case OBRb: case OBRc: op_end = parse_reg (op_end + 1, & reg); inst |= reg; /* Skip whitespace. */ while (isspace (* op_end)) ++ op_end; if (* op_end == ',') { op_end = parse_imm (op_end + 1, & reg, 0, 31); /* immediate values of 0 -> 6 translate to movi */ if (reg <= 6) { inst = (inst & 0xF) | MCORE_INST_BGENI_ALT; reg = 0x1 << reg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -