📄 tc-mn10300.c
字号:
if (strcasecmp (start, "usp") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_SSP) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcasecmp (start, "ssp") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_MSP) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcasecmp (start, "msp") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_PC) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcasecmp (start, "pc") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_EPSW) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcasecmp (start, "epsw") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_PLUS) { if (*input_line_pointer != '+') { input_line_pointer = hold; str = hold; goto error; } input_line_pointer++; goto keep_going; } else if (operand->flags & MN10300_OPERAND_PSW) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcasecmp (start, "psw") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_MDR) { char *start = input_line_pointer; char c = get_symbol_end (); if (strcasecmp (start, "mdr") != 0) { *input_line_pointer = c; input_line_pointer = hold; str = hold; goto error; } *input_line_pointer = c; goto keep_going; } else if (operand->flags & MN10300_OPERAND_REG_LIST) { unsigned int value = 0; if (*input_line_pointer != '[') { input_line_pointer = hold; str = hold; goto error; } /* Eat the '['. */ input_line_pointer++; /* We used to reject a null register list here; however, we accept it now so the compiler can emit "call" instructions for all calls to named functions. The linker can then fill in the appropriate bits for the register list and stack size or change the instruction into a "calls" if using "call" is not profitable. */ while (*input_line_pointer != ']') { char *start; char c; if (*input_line_pointer == ',') input_line_pointer++; start = input_line_pointer; c = get_symbol_end (); if (strcasecmp (start, "d2") == 0) { value |= 0x80; *input_line_pointer = c; } else if (strcasecmp (start, "d3") == 0) { value |= 0x40; *input_line_pointer = c; } else if (strcasecmp (start, "a2") == 0) { value |= 0x20; *input_line_pointer = c; } else if (strcasecmp (start, "a3") == 0) { value |= 0x10; *input_line_pointer = c; } else if (strcasecmp (start, "other") == 0) { value |= 0x08; *input_line_pointer = c; } else if (HAVE_AM33 && strcasecmp (start, "exreg0") == 0) { value |= 0x04; *input_line_pointer = c; } else if (HAVE_AM33 && strcasecmp (start, "exreg1") == 0) { value |= 0x02; *input_line_pointer = c; } else if (HAVE_AM33 && strcasecmp (start, "exother") == 0) { value |= 0x01; *input_line_pointer = c; } else if (HAVE_AM33 && strcasecmp (start, "all") == 0) { value |= 0xff; *input_line_pointer = c; } else { input_line_pointer = hold; str = hold; goto error; } } input_line_pointer++; mn10300_insert_operand (&insn, &extension, operand, value, (char *) NULL, 0, 0); goto keep_going; } else if (data_register_name (&ex)) { input_line_pointer = hold; str = hold; goto error; } else if (address_register_name (&ex)) { input_line_pointer = hold; str = hold; goto error; } else if (other_register_name (&ex)) { input_line_pointer = hold; str = hold; goto error; } else if (HAVE_AM33 && r_register_name (&ex)) { input_line_pointer = hold; str = hold; goto error; } else if (HAVE_AM33 && xr_register_name (&ex)) { input_line_pointer = hold; str = hold; goto error; } else if (*str == ')' || *str == '(') { input_line_pointer = hold; str = hold; goto error; } else { expression (&ex); } switch (ex.X_op) { case O_illegal: errmsg = _("illegal operand"); goto error; case O_absent: errmsg = _("missing operand"); goto error; case O_register: { int mask; mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG; if (HAVE_AM33) mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG; if ((operand->flags & mask) == 0) { input_line_pointer = hold; str = hold; goto error; } if (opcode->format == FMT_D1 || opcode->format == FMT_S1) extra_shift = 8; else if (opcode->format == FMT_D2 || opcode->format == FMT_D4 || opcode->format == FMT_S2 || opcode->format == FMT_S4 || opcode->format == FMT_S6 || opcode->format == FMT_D5) extra_shift = 16; else if (opcode->format == FMT_D7) extra_shift = 8; else if (opcode->format == FMT_D8 || opcode->format == FMT_D9) extra_shift = 8; else extra_shift = 0; mn10300_insert_operand (&insn, &extension, operand, ex.X_add_number, (char *) NULL, 0, extra_shift); /* And note the register number in the register array. */ mn10300_reg_operands[op_idx - 1] = ex.X_add_number; break; } case O_constant: /* If this operand can be promoted, and it doesn't fit into the allocated bitfield for this insn, then promote it (ie this opcode does not match). */ if (operand->flags & (MN10300_OPERAND_PROMOTE | MN10300_OPERAND_RELAX) && !check_operand (insn, operand, ex.X_add_number)) { input_line_pointer = hold; str = hold; goto error; } mn10300_insert_operand (&insn, &extension, operand, ex.X_add_number, (char *) NULL, 0, 0); break; default: /* If this operand can be promoted, then this opcode didn't match since we can't know if it needed promotion! */ if (operand->flags & MN10300_OPERAND_PROMOTE) { input_line_pointer = hold; str = hold; goto error; } /* We need to generate a fixup for this expression. */ if (fc >= MAX_INSN_FIXUPS) as_fatal (_("too many fixups")); fixups[fc].exp = ex; fixups[fc].opindex = *opindex_ptr; fixups[fc].reloc = BFD_RELOC_UNUSED; ++fc; break; }keep_going: str = input_line_pointer; input_line_pointer = hold; while (*str == ' ' || *str == ',') ++str; } /* Make sure we used all the operands! */ if (*str != ',') match = 1; /* If this instruction has registers that must not match, verify that they do indeed not match. */ if (opcode->no_match_operands) { int i; /* Look at each operand to see if it's marked. */ for (i = 0; i < MN10300_MAX_OPERANDS; i++) { if ((1 << i) & opcode->no_match_operands) { int j; /* operand I is marked. Check that it does not match any operands > I which are marked. */ for (j = i + 1; j < MN10300_MAX_OPERANDS; j++) { if (((1 << j) & opcode->no_match_operands) && mn10300_reg_operands[i] == mn10300_reg_operands[j]) { errmsg = _("Invalid register specification."); match = 0; goto error; } } } } } error: if (match == 0) { next_opcode = opcode + 1; if (!strcmp (next_opcode->name, opcode->name)) { opcode = next_opcode; continue; } as_bad ("%s", errmsg); return; } break; } while (isspace (*str)) ++str; if (*str != '\0') as_bad (_("junk at end of line: `%s'"), str); input_line_pointer = str; /* Determine the size of the instruction. */ if (opcode->format == FMT_S0) size = 1; if (opcode->format == FMT_S1 || opcode->format == FMT_D0) size = 2; if (opcode->format == FMT_S2 || opcode->format == FMT_D1) size = 3; if (opcode->format == FMT_D6) size = 3; if (opcode->format == FMT_D7 || opcode->format == FMT_D10) size = 4; if (opcode->format == FMT_D8) size = 6; if (opcode->format == FMT_D9) size = 7; if (opcode->format == FMT_S4) size = 5; if (opcode->format == FMT_S6 || opcode->format == FMT_D5) size = 7; if (opcode->format == FMT_D2) size = 4; if (opcode->format == FMT_D4) size = 6; if (relaxable && fc > 0) { int type; /* We want to anchor the line info to the previous frag (if there isn't one, create it), so that, when the insn is resized, we still get the right address for the beginning of the region. */ f = frag_more (0); dwarf2_emit_insn (0); /* bCC */ if (size == 2) { /* Handle bra specially. Basically treat it like jmp so that we automatically handle 8, 16 and 32 bit offsets correctly as well as jumps to an undefined address. It is also important to not treat it like other bCC instructions since the long forms of bra is different from other bCC instructions. */ if (opcode->opcode == 0xca00) type = 10; else type = 0; } /* call */ else if (size == 5) type = 6; /* calls */ else if (size == 4) type = 8; /* jmp */ else if (size == 3 && opcode->opcode == 0xcc0000) type = 10; /* bCC (uncommon cases) */ else type = 3; f = frag_var (rs_machine_dependent, 8, 8 - size, type, fixups[0].exp.X_add_symbol, fixups[0].exp.X_add_number, (char *)fixups[0].opindex); /* This is pretty hokey. We basically just care about the opcode, so we have to write out the first word big endian. The exception is "call", which has two operands that we care about. The first operand (the register list) happens to be in the first instruction word, and will be in the right place if we output the first word in big endian mode. The second operand (stack size) is in the extension word, and we want it to appear as the first character in the extension word (as it appears in memory). Luckily, writing the extension word in big endian format will do what we want. */ number_to_chars_bigendian (f, insn, size > 4 ? 4 : size); if (size > 8) { number_to_chars_bigendian (f + 4, extension, 4); number_to_chars_bigendian (f + 8, 0, size - 8); } else if (size > 4) number_to_chars_bigendian (f + 4, extension, size - 4); } else { /* Allocate space for the instruction. */ f = frag_more (size); /* Fill in bytes for the instruction. Note that opcode fields are written big-endian, 16 & 32bit immediates are written little endian. Egad. */ if (opcode->format == FMT_S0 || opcode->format == FMT_S1 || opcode->format == FMT_D0 || opcode->format == FMT_D6 || opcode->format == FMT_D7 || opcode->format == FMT_D10 || opcode->format == FMT_D1) { number_to_chars_bigendian (f, insn, size); } else if (opcode->format == FMT_S2 && opcode->opcode != 0xdf0000 && opcode->opcode != 0xde0000) { /* A format S2 instruction that is _not_ "ret" and "retf". */ number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1); number_to_chars_littleendian (f + 1, insn & 0xffff, 2); } else if (opcode->format == FMT_S2) { /* This must be a ret or retf, which is written entirely in big-endian format. */ number_to_chars_bigendian (f, insn, 3); } else if (opcode->format == FMT_S4 && opcode->opcode != 0xdc000000) { /* This must be a format S4 "call" instruction. What a pain. */ unsigned long temp = (insn >> 8) & 0xffff; number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1); number_to_chars_littleendian (f + 1, temp, 2); number_to_chars_bigendian (f + 3, insn & 0xff, 1); number_to_chars_bigendian (f + 4, extension & 0xff, 1); } else if (opcode->format == FMT_S4) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -