📄 tc-m68hc11.c
字号:
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 == 2); assert (operands[0].reg1 != REG_NONE); code = opcode->opcode & 0x0FF; f = m68hc11_new_insn (1); number_to_chars_bigendian (f, code, 1); n = operands[1].exp.X_add_number; code = operands[0].reg1; if (operands[0].reg1 == REG_NONE || operands[0].reg1 == REG_CCR || operands[0].reg1 == REG_PC) as_bad (_("Invalid register for dbcc/tbcc instruction.")); if (opcode->format & M6812_OP_IBCC_MARKER) code |= 0x80; else if (opcode->format & M6812_OP_TBCC_MARKER) code |= 0x40; if (!(opcode->format & M6812_OP_EQ_MARKER)) code |= 0x20; /* Turn into a long branch: - when force long branch option (and not for jbcc pseudos), - when jdbcc and the constant is out of -256..255 range, - when branch optimization is allowed and branch out of range. */ if ((jmp_mode == 0 && flag_force_long_jumps) || (operands[1].exp.X_op == O_constant && (!check_range (n, M6812_OP_IBCC_MARKER) && (jmp_mode == 1 || flag_fixed_branchs == 0)))) { f = frag_more (2); code ^= 0x20; number_to_chars_bigendian (f, code, 1); number_to_chars_bigendian (f + 1, M6812_JMP, 1); fixup16 (&operands[0].exp, M6811_OP_IND16, M6811_OP_IND16); return; } /* Branch with a constant that must fit in 9-bits. */ if (operands[1].exp.X_op == O_constant) { if (!check_range (n, M6812_OP_IBCC_MARKER)) { as_bad (_("Operand out of range for a relative branch: `%ld'"), n); } else { if ((long) n < 0) code |= 0x10; f = frag_more (2); number_to_chars_bigendian (f, code, 1); number_to_chars_bigendian (f + 1, n & 0x0FF, 1); } } else { /* Branch offset must fit in 8-bits, don't do some relax. */ if (jmp_mode == 0 && flag_fixed_branchs) { fixup8 (&operands[0].exp, M6811_OP_JUMP_REL, M6811_OP_JUMP_REL); } else { f = frag_more (2); number_to_chars_bigendian (f, code, 1); number_to_chars_bigendian (f + 1, 0, 1); frag_var (rs_machine_dependent, 3, 3, ENCODE_RELAX (STATE_XBCC_BRANCH, STATE_UNDF), operands[1].exp.X_add_symbol, (offsetT) n, f); } }}#define OP_EXTENDED (M6811_OP_PAGE2 | M6811_OP_PAGE3 | M6811_OP_PAGE4)/* Assemble the post index byte for 68HC12 extended addressing modes. */static intbuild_indexed_byte (op, format, move_insn) operand *op; int format ATTRIBUTE_UNUSED; int move_insn;{ unsigned char byte = 0; char *f; int mode; long val; val = op->exp.X_add_number; mode = op->mode; if (mode & M6812_AUTO_INC_DEC) { byte = 0x20; if (mode & (M6812_POST_INC | M6812_POST_DEC)) byte |= 0x10; if (op->exp.X_op == O_constant) { if (!check_range (val, mode)) { as_bad (_("Increment/decrement value is out of range: `%ld'."), val); } if (mode & (M6812_POST_INC | M6812_PRE_INC)) byte |= (val - 1) & 0x07; else byte |= (8 - ((val) & 7)) | 0x8; } switch (op->reg1) { case REG_NONE: as_fatal (_("Expecting a register.")); case REG_X: byte |= 0; break; case REG_Y: byte |= 0x40; break; case REG_SP: byte |= 0x80; break; default: as_bad (_("Invalid register for post/pre increment.")); break; } f = frag_more (1); number_to_chars_bigendian (f, byte, 1); return 1; } if (mode & M6812_OP_IDX) { switch (op->reg1) { case REG_X: byte = 0; break; case REG_Y: byte = 1; break; case REG_SP: byte = 2; break; case REG_PC: byte = 3; break; default: as_bad (_("Invalid register.")); break; } if (op->exp.X_op == O_constant) { if (!check_range (val, M6812_OP_IDX)) { as_bad (_("Offset out of 16-bit range: %ld."), val); } if (move_insn && !(val >= -16 && val <= 15)) { as_bad (_("Offset out of 5-bit range for movw/movb insn: %ld."), val); return -1; } if (val >= -16 && val <= 15 && !(mode & M6812_OP_IDX_2)) { byte = byte << 6; byte |= val & 0x1f; f = frag_more (1); number_to_chars_bigendian (f, byte, 1); return 1; } else if (val >= -256 && val <= 255 && !(mode & M6812_OP_IDX_2)) { byte = byte << 3; byte |= 0xe0; if (val < 0) byte |= 0x1; f = frag_more (2); number_to_chars_bigendian (f, byte, 1); number_to_chars_bigendian (f + 1, val & 0x0FF, 1); return 2; } else { byte = byte << 3; if (mode & M6812_OP_IDX_2) byte |= 0xe3; else byte |= 0xe2; f = frag_more (3); number_to_chars_bigendian (f, byte, 1); number_to_chars_bigendian (f + 1, val & 0x0FFFF, 2); return 3; } } if (op->reg1 != REG_PC) { byte = (byte << 3) | 0xe2; f = frag_more (1); number_to_chars_bigendian (f, byte, 1); f = frag_more (2); fix_new_exp (frag_now, f - frag_now->fr_literal, 2, &op->exp, false, BFD_RELOC_16); number_to_chars_bigendian (f, 0, 2); } else { f = frag_more (1); number_to_chars_bigendian (f, byte, 1); frag_var (rs_machine_dependent, 2, 2, ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_UNDF), op->exp.X_add_symbol, op->exp.X_add_number, f); } return 3; } if (mode & M6812_OP_REG) { if (mode & M6812_OP_IDX_2) { if (op->reg1 != REG_D) as_bad (_("Expecting register D for indexed indirect mode.")); if (move_insn) as_bad (_("Indexed indirect mode is not allowed for movb/movw.")); byte = 0xE7; } else { switch (op->reg1) { case REG_A: byte = 0xE4; break; case REG_B: byte = 0xE5; break; default: as_bad (_("Invalid accumulator register.")); case REG_D: byte = 0xE6; break; } } switch (op->reg2) { case REG_X: break; case REG_Y: byte |= (1 << 3); break; case REG_SP: byte |= (2 << 3); break; case REG_PC: byte |= (3 << 3); break; default: as_bad (_("Invalid indexed register.")); break; } f = frag_more (1); number_to_chars_bigendian (f, byte, 1); return 1; } as_fatal (_("Addressing mode not implemented yet.")); return 0;}/* Assemble the 68HC12 register mode byte. */static intbuild_reg_mode (op, format) operand *op; int format;{ unsigned char byte; char *f; if (format & M6812_OP_SEX_MARKER && op->reg1 != REG_A && op->reg1 != REG_B && op->reg1 != REG_CCR) as_bad (_("Invalid source register for this instruction, use 'tfr'.")); else if (op->reg1 == REG_NONE || op->reg1 == REG_PC) as_bad (_("Invalid source register.")); if (format & M6812_OP_SEX_MARKER && op->reg2 != REG_D && op->reg2 != REG_X && op->reg2 != REG_Y && op->reg2 != REG_SP) as_bad (_("Invalid destination register for this instruction, use 'tfr'.")); else if (op->reg2 == REG_NONE || op->reg2 == REG_PC) as_bad (_("Invalid destination register.")); byte = (op->reg1 << 4) | (op->reg2); if (format & M6812_OP_EXG_MARKER) byte |= 0x80; f = frag_more (1); number_to_chars_bigendian (f, byte, 1); return 1;}/* build_insn takes a pointer to the opcode entry in the opcode table, the array of operand expressions and builds the correspding instruction. This operation only deals with non relative jumps insn (need special handling). */static voidbuild_insn (opcode, operands, nb_operands) struct m68hc11_opcode *opcode; operand operands[]; int nb_operands ATTRIBUTE_UNUSED;{ int i; char *f; long format; int move_insn = 0; /* Put the page code instruction if there is one. */ format = opcode->format; if (format & OP_EXTENDED) { int page_code; f = m68hc11_new_insn (2); if (format & M6811_OP_PAGE2) page_code = M6811_OPCODE_PAGE2; else if (format & M6811_OP_PAGE3) page_code = M6811_OPCODE_PAGE3; else page_code = M6811_OPCODE_PAGE4; number_to_chars_bigendian (f, page_code, 1); f++; } else f = m68hc11_new_insn (1); number_to_chars_bigendian (f, opcode->opcode, 1); i = 0; /* The 68HC12 movb and movw instructions are special. We have to handle them in a special way. */ if (format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)) { move_insn = 1; if (format & M6812_OP_IDX) { build_indexed_byte (&operands[0], format, 1); i = 1; format &= ~M6812_OP_IDX; } if (format & M6812_OP_IDX_P2) { build_indexed_byte (&operands[1], format, 1); i = 0; format &= ~M6812_OP_IDX_P2; } } if (format & (M6811_OP_DIRECT | M6811_OP_IMM8)) { fixup8 (&operands[i].exp, format & (M6811_OP_DIRECT | M6811_OP_IMM8 | M6812_OP_TRAP_ID), operands[i].mode); i++; } else if (format & (M6811_OP_IMM16 | M6811_OP_IND16)) { fixup16 (&operands[i].exp, format & (M6811_OP_IMM16 | M6811_OP_IND16), operands[i].mode); i++; } else if (format & (M6811_OP_IX | M6811_OP_IY)) { if ((format & M6811_OP_IX) && (operands[0].reg1 != REG_X)) as_bad (_("Invalid indexed register, expecting register X.")); if ((format & M6811_OP_IY) && (operands[0].reg1 != REG_Y)) as_bad (_("Invalid indexed register, expecting register Y.")); fixup8 (&operands[0].exp, M6811_OP_IX, operands[0].mode); i = 1; } else if (format & (M6812_OP_IDX | M6812_OP_IDX_2 | M6812_OP_IDX_1 | M6812_OP_D_IDX)) { build_indexed_byte (&operands[i], format, move_insn); i++; } else if (format & M6812_OP_REG && current_architecture & cpu6812) { build_reg_mode (&operands[i], format); i++; } if (format & M6811_OP_BITMASK) { fixup8 (&operands[i].exp, M6811_OP_BITMASK, operands[i].mode); i++; } if (format & M6811_OP_JUMP_REL) { fixup8 (&operands[i].exp, M6811_OP_JUMP_REL, operands[i].mode); } else if (format & M6812_OP_IND16_P2) { fixup16 (&operands[1].exp, M6811_OP_IND16, operands[1].mode); }}/* Opcode identification and operand analysis. *//* find() gets a pointer to an entry in the opcode table. It must look at all opcodes with the same name and use the operands to choose the correct opcode. Returns the opcode pointer if there was a match and 0 if none. */static struct m68hc11_opcode *find (opc, operands, nb_operands) struct m68hc11_opcode_def *opc; operand operands[]; int nb_operands;{ int i, match, pos; struct m68hc11_opcode *opcode; struct m68hc11_opcode *op_indirect; op_indirect = 0; opcode = opc->opcode; /* Now search the opcode table table for one with operands that matches what we've got. We're only done if the operands matched so far AND there are no more to check. */ for (pos = match = 0; match == 0 && pos < opc->nb_modes; pos++, opcode++) { int poss_indirect = 0; long format = opcode->format; int expect; expect = 0; if (opcode->format & M6811_OP_MASK) expect++; if (opcode->format & M6811_OP_BITMASK) expect++; if (opcode->format & (M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16)) expect++; if (opcode->format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)) expect++; for (i = 0; expect == nb_operands && i < nb_operands; i++) { int mode = operands[i].mode; if (mode & M6811_OP_IMM16) { if (format & (M6811_OP_IMM8 | M6811_OP_IMM16 | M6811_OP_BITMASK)) continue; break; } if (mode == M6811_OP_DIRECT) { if (format & M6811_OP_DIRECT) continue; /* If the operand is a page 0 operand, remember a possible <abs-16> addressing mode. We mark this and continue to check other operands. */ if (format & M6811_OP_IND16 && flag_strict_direct_addressing && op_indirect == 0) { poss_indirect = 1; continue; } break; } if (mode & M6811_OP_IND16) { if (i == 0 && (format & M6811_OP_IND16) != 0) continue; if (i != 0 && (format & M6812_OP_IND16_P2) != 0) continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -