📄 tc-m68hc11.c
字号:
input_line_pointer = p; oper->reg2 = reg; return 1; } return 1; } /* In MRI mode, isolate the operand because we can't distinguish operands from comments. */ if (flag_mri) { char c = 0; p = skip_whites (p); while (*p && *p != ' ' && *p != '\t') p++; if (*p) { c = *p; *p = 0; } /* Parse as an expression. */ expression (&oper->exp); if (c) { *p = c; } } else { expression (&oper->exp); } if (oper->exp.X_op == O_illegal) { as_bad (_("Illegal operand.")); return -1; } else if (oper->exp.X_op == O_absent) { as_bad (_("Missing operand.")); return -1; } p = input_line_pointer; if (mode == M6811_OP_NONE || mode == M6811_OP_DIRECT || mode == M6812_OP_IDX_2) { p = skip_whites (input_line_pointer); if (*p == ',') { int possible_mode = M6811_OP_NONE; char *old_input_line; p++; /* 68HC12 pre increment or decrement. */ if (mode == M6811_OP_NONE) { if (*p == '-') { possible_mode = M6812_PRE_DEC; p++; } else if (*p == '+') { possible_mode = M6812_PRE_INC; p++; } p = skip_whites (p); } old_input_line = input_line_pointer; input_line_pointer = p; reg = register_name (); /* Backtrack if we have a valid constant expression and it does not correspond to the offset of the 68HC12 indexed addressing mode (as in N,x). */ if (reg == REG_NONE && mode == M6811_OP_NONE && possible_mode != M6811_OP_NONE) { oper->mode = M6811_OP_IND16 | M6811_OP_JUMP_REL; input_line_pointer = skip_whites (old_input_line); return 1; } if (possible_mode != M6811_OP_NONE) mode = possible_mode; if ((current_architecture & cpu6811) && possible_mode != M6811_OP_NONE) as_bad (_("Pre-increment mode is not valid for 68HC11")); /* Backtrack. */ if (which == 0 && opmode & M6812_OP_IDX_P2 && reg != REG_X && reg != REG_Y && reg != REG_PC && reg != REG_SP) { reg = REG_NONE; input_line_pointer = p; } if (reg == REG_NONE && mode != M6811_OP_DIRECT && !(mode == M6811_OP_NONE && opmode & M6811_OP_IND16)) { as_bad (_("Wrong register in register indirect mode.")); return -1; } if (mode == M6812_OP_IDX_2) { p = skip_whites (input_line_pointer); if (*p++ != ']') { as_bad (_("Missing `]' to close register indirect operand.")); return -1; } input_line_pointer = p; } if (reg != REG_NONE) { oper->reg1 = reg; if (mode == M6811_OP_NONE) { p = input_line_pointer; if (*p == '-') { mode = M6812_POST_DEC; p++; if (current_architecture & cpu6811) as_bad (_("Post-decrement mode is not valid for 68HC11.")); } else if (*p == '+') { mode = M6812_POST_INC; p++; if (current_architecture & cpu6811) as_bad (_("Post-increment mode is not valid for 68HC11.")); } else mode = M6812_OP_IDX; input_line_pointer = p; } else mode |= M6812_OP_IDX; oper->mode = mode; return 1; } } if (mode == M6812_OP_D_IDX_2) { as_bad (_("Invalid indexed indirect mode.")); return -1; } } /* If the mode is not known until now, this is either a label or an indirect address. */ if (mode == M6811_OP_NONE) mode = M6811_OP_IND16 | M6811_OP_JUMP_REL; p = input_line_pointer; while (*p == ' ' || *p == '\t') p++; input_line_pointer = p; oper->mode = mode; return 1;}#define M6812_AUTO_INC_DEC (M6812_PRE_INC | M6812_PRE_DEC \ | M6812_POST_INC | M6812_POST_DEC)/* Checks that the number 'num' fits for a given mode. */static intcheck_range (num, mode) long num; int mode;{ /* Auto increment and decrement are ok for [-8..8] without 0. */ if (mode & M6812_AUTO_INC_DEC) return (num != 0 && num <= 8 && num >= -8); /* The 68HC12 supports 5, 9 and 16-bit offsets. */ if (mode & (M6812_INDEXED_IND | M6812_INDEXED | M6812_OP_IDX)) mode = M6811_OP_IND16; if (mode & M6812_OP_JUMP_REL16) mode = M6811_OP_IND16; switch (mode) { case M6811_OP_IX: case M6811_OP_IY: case M6811_OP_DIRECT: return (num >= 0 && num <= 255) ? 1 : 0; case M6811_OP_BITMASK: case M6811_OP_IMM8: return (((num & 0xFFFFFF00) == 0) || ((num & 0xFFFFFF00) == 0xFFFFFF00)) ? 1 : 0; case M6811_OP_JUMP_REL: return (num >= -128 && num <= 127) ? 1 : 0; case M6811_OP_IND16: case M6811_OP_IMM16: return (((num & 0xFFFF0000) == 0) || ((num & 0xFFFF0000) == 0xFFFF0000)) ? 1 : 0; case M6812_OP_IBCC_MARKER: case M6812_OP_TBCC_MARKER: case M6812_OP_DBCC_MARKER: return (num >= -256 && num <= 255) ? 1 : 0; case M6812_OP_TRAP_ID: return ((num >= 0x30 && num <= 0x39) || (num >= 0x40 && num <= 0x0ff)) ? 1 : 0; default: return 0; }}/* Gas fixup generation. *//* Put a 1 byte expression described by 'oper'. If this expression contains unresolved symbols, generate an 8-bit fixup. */static voidfixup8 (oper, mode, opmode) expressionS *oper; int mode; int opmode;{ char *f; f = frag_more (1); if (oper->X_op == O_constant) { if (mode & M6812_OP_TRAP_ID && !check_range (oper->X_add_number, M6812_OP_TRAP_ID)) { static char trap_id_warn_once = 0; as_bad (_("Trap id `%ld' is out of range."), oper->X_add_number); if (trap_id_warn_once == 0) { trap_id_warn_once = 1; as_bad (_("Trap id must be within [0x30..0x39] or [0x40..0xff].")); } } if (!(mode & M6812_OP_TRAP_ID) && !check_range (oper->X_add_number, mode)) { as_bad (_("Operand out of 8-bit range: `%ld'."), oper->X_add_number); } number_to_chars_bigendian (f, oper->X_add_number & 0x0FF, 1); } else if (oper->X_op != O_register) { if (mode & M6812_OP_TRAP_ID) as_bad (_("The trap id must be a constant.")); if (mode == M6811_OP_JUMP_REL) { fixS *fixp; fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1, oper, true, BFD_RELOC_8_PCREL); fixp->fx_pcrel_adjust = 1; } else { /* Now create an 8-bit fixup. If there was some %hi or %lo modifier, generate the reloc accordingly. */ fix_new_exp (frag_now, f - frag_now->fr_literal, 1, oper, false, ((opmode & M6811_OP_HIGH_ADDR) ? BFD_RELOC_M68HC11_HI8 : ((opmode & M6811_OP_LOW_ADDR) ? BFD_RELOC_M68HC11_LO8 : BFD_RELOC_8))); } number_to_chars_bigendian (f, 0, 1); } else { as_fatal (_("Operand `%x' not recognized in fixup8."), oper->X_op); }}/* Put a 2 byte expression described by 'oper'. If this expression contains unresolved symbols, generate a 16-bit fixup. */static voidfixup16 (oper, mode, opmode) expressionS *oper; int mode; int opmode ATTRIBUTE_UNUSED;{ char *f; f = frag_more (2); if (oper->X_op == O_constant) { if (!check_range (oper->X_add_number, mode)) { as_bad (_("Operand out of 16-bit range: `%ld'."), oper->X_add_number); } number_to_chars_bigendian (f, oper->X_add_number & 0x0FFFF, 2); } else if (oper->X_op != O_register) { fixS *fixp; /* Now create a 16-bit fixup. */ fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2, oper, (mode & M6812_OP_JUMP_REL16 ? true : false), (mode & M6812_OP_JUMP_REL16 ? BFD_RELOC_16_PCREL : BFD_RELOC_16)); number_to_chars_bigendian (f, 0, 2); if (mode & M6812_OP_JUMP_REL16) fixp->fx_pcrel_adjust = 2; } else { as_fatal (_("Operand `%x' not recognized in fixup16."), oper->X_op); }}/* 68HC11 and 68HC12 code generation. *//* Translate the short branch/bsr instruction into a long branch. */static unsigned charconvert_branch (code) unsigned char code;{ if (IS_OPCODE (code, M6812_BSR)) return M6812_JSR; else if (IS_OPCODE (code, M6811_BSR)) return M6811_JSR; else if (IS_OPCODE (code, M6811_BRA)) return (current_architecture & cpu6812) ? M6812_JMP : M6811_JMP; else as_fatal (_("Unexpected branch conversion with `%x'"), code); /* Keep gcc happy. */ return M6811_JSR;}/* Start a new insn that contains at least 'size' bytes. Record the line information of that insn in the dwarf2 debug sections. */static char *m68hc11_new_insn (size) int size;{ char *f; f = frag_more (size); dwarf2_emit_insn (size); return f;}/* Builds a jump instruction (bra, bcc, bsr). */static voidbuild_jump_insn (opcode, operands, nb_operands, jmp_mode) struct m68hc11_opcode *opcode; operand operands[]; int nb_operands; int jmp_mode;{ unsigned char code; char *f; unsigned long n; /* The relative branch convertion is not supported for brclr and brset. */ assert ((opcode->format & M6811_OP_BITMASK) == 0); assert (nb_operands == 1); assert (operands[0].reg1 == REG_NONE && operands[0].reg2 == REG_NONE); code = opcode->opcode; n = operands[0].exp.X_add_number; /* Turn into a long branch: - when force long branch option (and not for jbcc pseudos), - when jbcc and the constant is out of -128..127 range, - when branch optimization is allowed and branch out of range. */ if ((jmp_mode == 0 && flag_force_long_jumps) || (operands[0].exp.X_op == O_constant && (!check_range (n, opcode->format) && (jmp_mode == 1 || flag_fixed_branchs == 0)))) { if (code == M6811_BSR || code == M6811_BRA || code == M6812_BSR) { code = convert_branch (code); f = m68hc11_new_insn (1); number_to_chars_bigendian (f, code, 1); } else if (current_architecture & cpu6812) { /* 68HC12: translate the bcc into a lbcc. */ f = m68hc11_new_insn (2); number_to_chars_bigendian (f, M6811_OPCODE_PAGE2, 1); number_to_chars_bigendian (f + 1, code, 1); fixup16 (&operands[0].exp, M6812_OP_JUMP_REL16, M6812_OP_JUMP_REL16); return; } else { /* 68HC11: translate the bcc into b!cc +3; jmp <L>. */ f = m68hc11_new_insn (3); code ^= 1; number_to_chars_bigendian (f, code, 1); number_to_chars_bigendian (f + 1, 3, 1); number_to_chars_bigendian (f + 2, M6811_JMP, 1); } fixup16 (&operands[0].exp, M6811_OP_IND16, M6811_OP_IND16); return; } /* Branch with a constant that must fit in 8-bits. */ if (operands[0].exp.X_op == O_constant) { if (!check_range (n, opcode->format)) { as_bad (_("Operand out of range for a relative branch: `%ld'"), n); } else if (opcode->format & M6812_OP_JUMP_REL16) { f = m68hc11_new_insn (4); number_to_chars_bigendian (f, M6811_OPCODE_PAGE2, 1); number_to_chars_bigendian (f + 1, code, 1); number_to_chars_bigendian (f + 2, n & 0x0ffff, 2); } else { f = m68hc11_new_insn (2); number_to_chars_bigendian (f, code, 1); number_to_chars_bigendian (f + 1, n & 0x0FF, 1); } } else if (opcode->format & M6812_OP_JUMP_REL16) { f = m68hc11_new_insn (2); number_to_chars_bigendian (f, M6811_OPCODE_PAGE2, 1); number_to_chars_bigendian (f + 1, code, 1); fixup16 (&operands[0].exp, M6812_OP_JUMP_REL16, M6812_OP_JUMP_REL16); } else { char *opcode; /* Branch offset must fit in 8-bits, don't do some relax. */ if (jmp_mode == 0 && flag_fixed_branchs) { opcode = m68hc11_new_insn (1); number_to_chars_bigendian (opcode, code, 1); fixup8 (&operands[0].exp, M6811_OP_JUMP_REL, M6811_OP_JUMP_REL); } /* bra/bsr made be changed into jmp/jsr. */ else if (code == M6811_BSR || code == M6811_BRA || code == M6812_BSR) { opcode = m68hc11_new_insn (2); number_to_chars_bigendian (opcode, code, 1); number_to_chars_bigendian (opcode + 1, 0, 1); frag_var (rs_machine_dependent, 2, 1, ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF), operands[0].exp.X_add_symbol, (offsetT) n, opcode); } else if (current_architecture & cpu6812) { opcode = m68hc11_new_insn (2); number_to_chars_bigendian (opcode, code, 1); number_to_chars_bigendian (opcode + 1, 0, 1); frag_var (rs_machine_dependent, 2, 2, ENCODE_RELAX (STATE_CONDITIONAL_BRANCH_6812, STATE_UNDF), operands[0].exp.X_add_symbol, (offsetT) n, opcode); } else { opcode = m68hc11_new_insn (2); number_to_chars_bigendian (opcode, code, 1); number_to_chars_bigendian (opcode + 1, 0, 1); frag_var (rs_machine_dependent, 3, 3, ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF), operands[0].exp.X_add_symbol, (offsetT) n, opcode); } }}/* Builds a dbne/dbeq/tbne/tbeq instruction. */static voidbuild_dbranch_insn (opcode, operands, nb_operands, jmp_mode) struct m68hc11_opcode *opcode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -