/mingw-w64-v2.0.999/binutils/src/gas/config/tc-m68hc11.c
C | 4493 lines | 3521 code | 541 blank | 431 comment | 1193 complexity | ffe5b29f83b80da1e7012f091761c993 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, LGPL-3.0, Unlicense, GPL-2.0, LGPL-2.0, BSD-3-Clause, GPL-3.0
Large files files are truncated, but you can click here to view the full file
- /* tc-m68hc11.c -- Assembler code for the Motorola 68HC11 & 68HC12.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
- 2011, 2012
- Free Software Foundation, Inc.
- Written by Stephane Carrez (stcarrez@nerim.fr)
- XGATE and S12X added by James Murray (jsm@jsm-net.demon.co.uk)
- This file is part of GAS, the GNU Assembler.
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 51 Franklin Street - Fifth Floor,
- Boston, MA 02110-1301, USA. */
- #include "as.h"
- #include "safe-ctype.h"
- #include "subsegs.h"
- #include "opcode/m68hc11.h"
- #include "dwarf2dbg.h"
- #include "elf/m68hc11.h"
- const char comment_chars[] = ";!";
- const char line_comment_chars[] = "#*";
- const char line_separator_chars[] = "";
- const char EXP_CHARS[] = "eE";
- const char FLT_CHARS[] = "dD";
- #define STATE_CONDITIONAL_BRANCH (1)
- #define STATE_PC_RELATIVE (2)
- #define STATE_INDEXED_OFFSET (3)
- #define STATE_INDEXED_PCREL (4)
- #define STATE_XBCC_BRANCH (5)
- #define STATE_CONDITIONAL_BRANCH_6812 (6)
- #define STATE_BYTE (0)
- #define STATE_BITS5 (0)
- #define STATE_WORD (1)
- #define STATE_BITS9 (1)
- #define STATE_LONG (2)
- #define STATE_BITS16 (2)
- #define STATE_UNDF (3) /* Symbol undefined in pass1 */
- /* This macro has no side-effects. */
- #define ENCODE_RELAX(what,length) (((what) << 2) + (length))
- #define RELAX_STATE(s) ((s) >> 2)
- #define RELAX_LENGTH(s) ((s) & 3)
- #define IS_OPCODE(C1,C2) (((C1) & 0x0FF) == ((C2) & 0x0FF))
- /* This table describes how you change sizes for the various types of variable
- size expressions. This version only supports two kinds. */
- /* The fields are:
- How far Forward this mode will reach.
- How far Backward this mode will reach.
- How many bytes this mode will add to the size of the frag.
- Which mode to go to if the offset won't fit in this one. */
- relax_typeS md_relax_table[] =
- {
- {1, 1, 0, 0}, /* First entries aren't used. */
- {1, 1, 0, 0}, /* For no good reason except. */
- {1, 1, 0, 0}, /* that the VAX doesn't either. */
- {1, 1, 0, 0},
- /* Relax for bcc <L>.
- These insns are translated into b!cc +3 jmp L. */
- {(127), (-128), 0, ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD)},
- {0, 0, 3, 0},
- {1, 1, 0, 0},
- {1, 1, 0, 0},
- /* Relax for bsr <L> and bra <L>.
- These insns are translated into jsr and jmp. */
- {(127), (-128), 0, ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD)},
- {0, 0, 1, 0},
- {1, 1, 0, 0},
- {1, 1, 0, 0},
- /* Relax for indexed offset: 5-bits, 9-bits, 16-bits. */
- {(15), (-16), 0, ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9)},
- {(255), (-256), 1, ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16)},
- {0, 0, 2, 0},
- {1, 1, 0, 0},
- /* Relax for PC relative offset: 5-bits, 9-bits, 16-bits.
- For the 9-bit case, there will be a -1 correction to take into
- account the new byte that's why the range is -255..256. */
- {(15), (-16), 0, ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9)},
- {(256), (-255), 1, ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16)},
- {0, 0, 2, 0},
- {1, 1, 0, 0},
- /* Relax for dbeq/ibeq/tbeq r,<L>:
- These insns are translated into db!cc +3 jmp L. */
- {(255), (-256), 0, ENCODE_RELAX (STATE_XBCC_BRANCH, STATE_WORD)},
- {0, 0, 3, 0},
- {1, 1, 0, 0},
- {1, 1, 0, 0},
- /* Relax for bcc <L> on 68HC12.
- These insns are translated into lbcc <L>. */
- {(127), (-128), 0, ENCODE_RELAX (STATE_CONDITIONAL_BRANCH_6812, STATE_WORD)},
- {0, 0, 2, 0},
- {1, 1, 0, 0},
- {1, 1, 0, 0},
- };
- /* 68HC11 and 68HC12 registers. They are numbered according to the 68HC12. */
- typedef enum register_id
- {
- REG_NONE = -1,
- REG_A = 0,
- REG_B = 1,
- REG_CCR = 2,
- REG_D = 4,
- REG_X = 5,
- REG_Y = 6,
- REG_SP = 7,
- REG_PC = 8,
- REG_R0 = 0,
- REG_R1 = 1,
- REG_R2 = 2,
- REG_R3 = 3,
- REG_R4 = 4,
- REG_R5 = 5,
- REG_R6 = 6,
- REG_R7 = 7,
- REG_SP_XG = 8,
- REG_PC_XG = 9,
- REG_CCR_XG = 10
- } register_id;
- typedef struct operand
- {
- expressionS exp;
- register_id reg1;
- register_id reg2;
- int mode;
- } operand;
- struct m68hc11_opcode_def
- {
- long format;
- int min_operands;
- int max_operands;
- int nb_modes;
- int used;
- struct m68hc11_opcode *opcode;
- };
- static struct m68hc11_opcode_def *m68hc11_opcode_defs = 0;
- static int m68hc11_nb_opcode_defs = 0;
- typedef struct alias
- {
- const char *name;
- const char *alias;
- } alias;
- static alias alias_opcodes[] =
- {
- {"cpd", "cmpd"},
- {"cpx", "cmpx"},
- {"cpy", "cmpy"},
- {0, 0}
- };
- struct m9s12xg_opcode_def
- {
- long format;
- int min_operands;
- int max_operands;
- int nb_modes;
- int used;
- struct m9s12xg_opcode *opcode;
- };
- /* Local functions. */
- static register_id reg_name_search (char *);
- static register_id register_name (void);
- static int cmp_opcode (struct m68hc11_opcode *, struct m68hc11_opcode *);
- static char *print_opcode_format (struct m68hc11_opcode *, int);
- static char *skip_whites (char *);
- static int check_range (long, int);
- static void print_opcode_list (void);
- static void get_default_target (void);
- static void print_insn_format (char *);
- static int get_operand (operand *, int, long);
- static void fixup8 (expressionS *, int, int);
- static void fixup16 (expressionS *, int, int);
- static void fixup24 (expressionS *, int, int);
- static void fixup8_xg (expressionS *, int, int);
- static unsigned char convert_branch (unsigned char);
- static char *m68hc11_new_insn (int);
- static void build_dbranch_insn (struct m68hc11_opcode *,
- operand *, int, int);
- static int build_indexed_byte (operand *, int, int);
- static int build_reg_mode (operand *, int);
- static struct m68hc11_opcode *find (struct m68hc11_opcode_def *,
- operand *, int);
- static struct m68hc11_opcode *find_opcode (struct m68hc11_opcode_def *,
- operand *, int *);
- static void build_jump_insn (struct m68hc11_opcode *, operand *, int, int);
- static void build_insn_xg (struct m68hc11_opcode *, operand *, int);
- static void build_insn (struct m68hc11_opcode *, operand *, int);
- static int relaxable_symbol (symbolS *);
- /* Pseudo op to indicate a relax group. */
- static void s_m68hc11_relax (int);
- /* Pseudo op to control the ELF flags. */
- static void s_m68hc11_mode (int);
- /* Mark the symbols with STO_M68HC12_FAR to indicate the functions
- are using 'rtc' for returning. It is necessary to use 'call'
- to invoke them. This is also used by the debugger to correctly
- find the stack frame. */
- static void s_m68hc11_mark_symbol (int);
- /* Controls whether relative branches can be turned into long branches.
- When the relative offset is too large, the insn are changed:
- bra -> jmp
- bsr -> jsr
- bcc -> b!cc +3
- jmp L
- dbcc -> db!cc +3
- jmp L
- Setting the flag forbidds this. */
- static short flag_fixed_branches = 0;
- /* Force to use long jumps (absolute) instead of relative branches. */
- static short flag_force_long_jumps = 0;
- /* Change the direct addressing mode into an absolute addressing mode
- when the insn does not support direct addressing.
- For example, "clr *ZD0" is normally not possible and is changed
- into "clr ZDO". */
- static short flag_strict_direct_addressing = 1;
- /* When an opcode has invalid operand, print out the syntax of the opcode
- to stderr. */
- static short flag_print_insn_syntax = 0;
- /* Dumps the list of instructions with syntax and then exit:
- 1 -> Only dumps the list (sorted by name)
- 2 -> Generate an example (or test) that can be compiled. */
- static short flag_print_opcodes = 0;
- /* Opcode hash table. */
- static struct hash_control *m68hc11_hash;
- /* Current cpu (either cpu6811 or cpu6812). This is determined automagically
- by 'get_default_target' by looking at default BFD vector. This is overridden
- with the -m<cpu> option. */
- static int current_architecture = 0;
- /* Default cpu determined by 'get_default_target'. */
- static const char *default_cpu;
- /* Number of opcodes in the sorted table (filtered by current cpu). */
- static int num_opcodes;
- /* The opcodes sorted by name and filtered by current cpu. */
- static struct m68hc11_opcode *m68hc11_sorted_opcodes;
- /* ELF flags to set in the output file header. */
- static int elf_flags = E_M68HC11_F64;
- /* These are the machine dependent pseudo-ops. These are included so
- the assembler can work on the output from the SUN C compiler, which
- generates these. */
- /* This table describes all the machine specific pseudo-ops the assembler
- has to support. The fields are:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function. */
- const pseudo_typeS md_pseudo_table[] =
- {
- /* The following pseudo-ops are supported for MRI compatibility. */
- {"fcb", cons, 1},
- {"fdb", cons, 2},
- {"fqb", cons, 4},
- {"fcc", stringer, 8 + 1},
- {"rmb", s_space, 0},
- /* Motorola ALIS. */
- {"xrefb", s_ignore, 0}, /* Same as xref */
- /* Gcc driven relaxation. */
- {"relax", s_m68hc11_relax, 0},
- /* .mode instruction (ala SH). */
- {"mode", s_m68hc11_mode, 0},
- /* .far instruction. */
- {"far", s_m68hc11_mark_symbol, STO_M68HC12_FAR},
- /* .interrupt instruction. */
- {"interrupt", s_m68hc11_mark_symbol, STO_M68HC12_INTERRUPT},
- {0, 0, 0}
- };
- /* Options and initialization. */
- const char *md_shortopts = "Sm:";
- struct option md_longopts[] =
- {
- #define OPTION_FORCE_LONG_BRANCH (OPTION_MD_BASE)
- {"force-long-branches", no_argument, NULL, OPTION_FORCE_LONG_BRANCH},
- {"force-long-branchs", no_argument, NULL, OPTION_FORCE_LONG_BRANCH}, /* Misspelt version kept for backwards compatibility. */
- #define OPTION_SHORT_BRANCHES (OPTION_MD_BASE + 1)
- {"short-branches", no_argument, NULL, OPTION_SHORT_BRANCHES},
- {"short-branchs", no_argument, NULL, OPTION_SHORT_BRANCHES}, /* Misspelt version kept for backwards compatibility. */
- #define OPTION_STRICT_DIRECT_MODE (OPTION_MD_BASE + 2)
- {"strict-direct-mode", no_argument, NULL, OPTION_STRICT_DIRECT_MODE},
- #define OPTION_PRINT_INSN_SYNTAX (OPTION_MD_BASE + 3)
- {"print-insn-syntax", no_argument, NULL, OPTION_PRINT_INSN_SYNTAX},
- #define OPTION_PRINT_OPCODES (OPTION_MD_BASE + 4)
- {"print-opcodes", no_argument, NULL, OPTION_PRINT_OPCODES},
- #define OPTION_GENERATE_EXAMPLE (OPTION_MD_BASE + 5)
- {"generate-example", no_argument, NULL, OPTION_GENERATE_EXAMPLE},
- #define OPTION_MSHORT (OPTION_MD_BASE + 6)
- {"mshort", no_argument, NULL, OPTION_MSHORT},
- #define OPTION_MLONG (OPTION_MD_BASE + 7)
- {"mlong", no_argument, NULL, OPTION_MLONG},
- #define OPTION_MSHORT_DOUBLE (OPTION_MD_BASE + 8)
- {"mshort-double", no_argument, NULL, OPTION_MSHORT_DOUBLE},
- #define OPTION_MLONG_DOUBLE (OPTION_MD_BASE + 9)
- {"mlong-double", no_argument, NULL, OPTION_MLONG_DOUBLE},
- #define OPTION_XGATE_RAMOFFSET (OPTION_MD_BASE + 10)
- {"xgate-ramoffset", no_argument, NULL, OPTION_XGATE_RAMOFFSET},
- {NULL, no_argument, NULL, 0}
- };
- size_t md_longopts_size = sizeof (md_longopts);
- /* Get the target cpu for the assembler. This is based on the configure
- options and on the -m68hc11/-m68hc12 option. If no option is specified,
- we must get the default. */
- const char *
- m68hc11_arch_format (void)
- {
- get_default_target ();
- if (current_architecture & cpu6811)
- return "elf32-m68hc11";
- else
- return "elf32-m68hc12";
- }
- enum bfd_architecture
- m68hc11_arch (void)
- {
- get_default_target ();
- if (current_architecture & cpu6811)
- return bfd_arch_m68hc11;
- else
- return bfd_arch_m68hc12;
- }
- int
- m68hc11_mach (void)
- {
- return 0;
- }
- /* Listing header selected according to cpu. */
- const char *
- m68hc11_listing_header (void)
- {
- if (current_architecture & cpu6811)
- return "M68HC11 GAS ";
- else if (current_architecture & cpuxgate)
- return "XGATE GAS ";
- else if (current_architecture & cpu9s12x)
- return "S12X GAS ";
- else
- return "M68HC12 GAS ";
- }
- void
- md_show_usage (FILE *stream)
- {
- get_default_target ();
- fprintf (stream, _("\
- Motorola 68HC11/68HC12/68HCS12 options:\n\
- -m68hc11 | -m68hc12 |\n\
- -m68hcs12 | -mm9s12x |\n\
- -mm9s12xg specify the processor [default %s]\n\
- -mshort use 16-bit int ABI (default)\n\
- -mlong use 32-bit int ABI\n\
- -mshort-double use 32-bit double ABI\n\
- -mlong-double use 64-bit double ABI (default)\n\
- --force-long-branches always turn relative branches into absolute ones\n\
- -S,--short-branches do not turn relative branches into absolute ones\n\
- when the offset is out of range\n\
- --strict-direct-mode do not turn the direct mode into extended mode\n\
- when the instruction does not support direct mode\n\
- --print-insn-syntax print the syntax of instruction in case of error\n\
- --print-opcodes print the list of instructions with syntax\n\
- --xgate-ramoffset offset ram addresses by 0xc000\n\
- --generate-example generate an example of each instruction\n\
- (used for testing)\n"), default_cpu);
- }
- /* Try to identify the default target based on the BFD library. */
- static void
- get_default_target (void)
- {
- const bfd_target *target;
- bfd abfd;
- if (current_architecture != 0)
- return;
- default_cpu = "unknown";
- target = bfd_find_target (0, &abfd);
- if (target && target->name)
- {
- if (strcmp (target->name, "elf32-m68hc12") == 0)
- {
- current_architecture = cpu6812;
- default_cpu = "m68hc12";
- }
- else if (strcmp (target->name, "elf32-m68hc11") == 0)
- {
- current_architecture = cpu6811;
- default_cpu = "m68hc11";
- }
- else
- {
- as_bad (_("Default target `%s' is not supported."), target->name);
- }
- }
- }
- void
- m68hc11_print_statistics (FILE *file)
- {
- int i;
- struct m68hc11_opcode_def *opc;
- hash_print_statistics (file, "opcode table", m68hc11_hash);
- opc = m68hc11_opcode_defs;
- if (opc == 0 || m68hc11_nb_opcode_defs == 0)
- return;
- /* Dump the opcode statistics table. */
- fprintf (file, _("Name # Modes Min ops Max ops Modes mask # Used\n"));
- for (i = 0; i < m68hc11_nb_opcode_defs; i++, opc++)
- {
- fprintf (file, "%-7.7s %5d %7d %7d 0x%08lx %7d\n",
- opc->opcode->name,
- opc->nb_modes,
- opc->min_operands, opc->max_operands, opc->format, opc->used);
- }
- }
- int
- md_parse_option (int c, char *arg)
- {
- get_default_target ();
- switch (c)
- {
- /* -S means keep external to 2 bit offset rather than 16 bit one. */
- case OPTION_SHORT_BRANCHES:
- case 'S':
- flag_fixed_branches = 1;
- break;
- case OPTION_FORCE_LONG_BRANCH:
- flag_force_long_jumps = 1;
- break;
- case OPTION_PRINT_INSN_SYNTAX:
- flag_print_insn_syntax = 1;
- break;
- case OPTION_PRINT_OPCODES:
- flag_print_opcodes = 1;
- break;
- case OPTION_STRICT_DIRECT_MODE:
- flag_strict_direct_addressing = 0;
- break;
- case OPTION_GENERATE_EXAMPLE:
- flag_print_opcodes = 2;
- break;
- case OPTION_MSHORT:
- elf_flags &= ~E_M68HC11_I32;
- break;
- case OPTION_MLONG:
- elf_flags |= E_M68HC11_I32;
- break;
- case OPTION_MSHORT_DOUBLE:
- elf_flags &= ~E_M68HC11_F64;
- break;
- case OPTION_MLONG_DOUBLE:
- elf_flags |= E_M68HC11_F64;
- break;
- case OPTION_XGATE_RAMOFFSET:
- elf_flags |= E_M68HC11_XGATE_RAMOFFSET;
- break;
- case 'm':
- if ((strcasecmp (arg, "68hc11") == 0)
- || (strcasecmp (arg, "m68hc11") == 0))
- current_architecture = cpu6811;
- else if ((strcasecmp (arg, "68hc12") == 0)
- || (strcasecmp (arg, "m68hc12") == 0))
- current_architecture = cpu6812;
- else if ((strcasecmp (arg, "68hcs12") == 0)
- || (strcasecmp (arg, "m68hcs12") == 0))
- current_architecture = cpu6812 | cpu6812s;
- else if (strcasecmp (arg, "m9s12x") == 0)
- current_architecture = cpu6812 | cpu6812s | cpu9s12x;
- else if ((strcasecmp (arg, "m9s12xg") == 0)
- || (strcasecmp (arg, "xgate") == 0))
- /* xgate for backwards compatability */
- current_architecture = cpuxgate;
- else
- as_bad (_("Option `%s' is not recognized."), arg);
- break;
- default:
- return 0;
- }
- return 1;
- }
- symbolS *
- md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
- {
- return 0;
- }
- char *
- md_atof (int type, char *litP, int *sizeP)
- {
- return ieee_md_atof (type, litP, sizeP, TRUE);
- }
- valueT
- md_section_align (asection *seg, valueT addr)
- {
- int align = bfd_get_section_alignment (stdoutput, seg);
- return ((addr + (1 << align) - 1) & (-1 << align));
- }
- static int
- cmp_opcode (struct m68hc11_opcode *op1, struct m68hc11_opcode *op2)
- {
- return strcmp (op1->name, op2->name);
- }
- #define IS_CALL_SYMBOL(MODE) \
- (((MODE) & (M6812_OP_PAGE|M6811_OP_IND16)) \
- == ((M6812_OP_PAGE|M6811_OP_IND16)))
- /* Initialize the assembler. Create the opcode hash table
- (sorted on the names) with the M6811 opcode table
- (from opcode library). */
- void
- md_begin (void)
- {
- char *prev_name = "";
- struct m68hc11_opcode *opcodes;
- struct m68hc11_opcode_def *opc = 0;
- int i, j;
- get_default_target ();
- m68hc11_hash = hash_new ();
- /* Get a writable copy of the opcode table and sort it on the names. */
- opcodes = (struct m68hc11_opcode *) xmalloc (m68hc11_num_opcodes *
- sizeof (struct
- m68hc11_opcode));
- m68hc11_sorted_opcodes = opcodes;
- num_opcodes = 0;
- for (i = 0; i < m68hc11_num_opcodes; i++)
- {
- if (m68hc11_opcodes[i].arch & current_architecture)
- {
- opcodes[num_opcodes] = m68hc11_opcodes[i];
- if (opcodes[num_opcodes].name[0] == 'b'
- && opcodes[num_opcodes].format & M6811_OP_JUMP_REL
- && !(opcodes[num_opcodes].format & M6811_OP_BITMASK))
- {
- num_opcodes++;
- opcodes[num_opcodes] = m68hc11_opcodes[i];
- }
- num_opcodes++;
- for (j = 0; alias_opcodes[j].name != 0; j++)
- if (strcmp (m68hc11_opcodes[i].name, alias_opcodes[j].name) == 0)
- {
- opcodes[num_opcodes] = m68hc11_opcodes[i];
- opcodes[num_opcodes].name = alias_opcodes[j].alias;
- num_opcodes++;
- break;
- }
- }
- }
- qsort (opcodes, num_opcodes, sizeof (struct m68hc11_opcode),
- (int (*) (const void*, const void*)) cmp_opcode);
- opc = (struct m68hc11_opcode_def *)
- xmalloc (num_opcodes * sizeof (struct m68hc11_opcode_def));
- m68hc11_opcode_defs = opc--;
- /* Insert unique names into hash table. The M6811 instruction set
- has several identical opcode names that have different opcodes based
- on the operands. This hash table then provides a quick index to
- the first opcode with a particular name in the opcode table. */
- for (i = 0; i < num_opcodes; i++, opcodes++)
- {
- int expect;
- if (strcmp (prev_name, opcodes->name))
- {
- prev_name = (char *) opcodes->name;
- opc++;
- opc->format = 0;
- opc->min_operands = 100;
- opc->max_operands = 0;
- opc->nb_modes = 0;
- opc->opcode = opcodes;
- opc->used = 0;
- hash_insert (m68hc11_hash, opcodes->name, opc);
- }
- opc->nb_modes++;
- opc->format |= opcodes->format;
- /* See how many operands this opcode needs. */
- expect = 0;
- if (opcodes->arch == cpuxgate)
- {
- if (opcodes->format & (M68XG_OP_IMM3 | M68XG_OP_R | M68XG_OP_REL9
- | M68XG_OP_REL10 ))
- expect = 1;
- else if (opcodes->format & (M68XG_OP_R_R | M68XG_OP_R_IMM4
- | M68XG_OP_R_IMM8 | M68XG_OP_R_IMM8))
- expect = 2;
- else if (opcodes->format & (M68XG_OP_R_R_R | M68XG_OP_R_R_OFFS5
- | M68XG_OP_RD_RB_RI | M68XG_OP_RD_RB_RIp
- | M68XG_OP_RD_RB_mRI))
- expect = 3;
- }
- else
- {
- if (opcodes->format & M6811_OP_MASK)
- expect++;
- if (opcodes->format & M6811_OP_BITMASK)
- expect++;
- if (opcodes->format & (M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
- expect++;
- if (opcodes->format & (M6812_OP_IND16_P2 | M6812_OP_IDX_P2))
- expect++;
- /* Special case for call instruction. */
- if ((opcodes->format & M6812_OP_PAGE)
- && !(opcodes->format & M6811_OP_IND16))
- expect++;
- }
- if (expect < opc->min_operands)
- opc->min_operands = expect;
- if (IS_CALL_SYMBOL (opcodes->format))
- expect++;
- if (expect > opc->max_operands)
- opc->max_operands = expect;
- }
- opc++;
- m68hc11_nb_opcode_defs = opc - m68hc11_opcode_defs;
- if (flag_print_opcodes)
- {
- print_opcode_list ();
- exit (EXIT_SUCCESS);
- }
- }
- void
- m68hc11_init_after_args (void)
- {
- }
- /* Builtin help. */
- /* Return a string that represents the operand format for the instruction.
- When example is true, this generates an example of operand. This is used
- to give an example and also to generate a test. */
- static char *
- print_opcode_format (struct m68hc11_opcode *opcode, int example)
- {
- static char buf[128];
- int format = opcode->format;
- char *p;
- p = buf;
- buf[0] = 0;
- if (current_architecture == cpuxgate)
- {
- if (format & M68XG_OP_IMM3)
- {
- if (example)
- sprintf (p, "#%d", rand () & 0x007);
- else
- strcpy (p, _("imm3"));
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R)
- {
- if (example)
- sprintf (p, "R%d", rand () & 0x07);
- else
- strcpy (p, _("RD"));
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R_R)
- {
- if (example)
- sprintf (p, "R%d,R%d", rand () & 0x07, rand () & 0x07);
- else
- strcpy (p, _("RD,RS"));
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R_IMM4)
- {
- if (example)
- sprintf (p, "R%d,#%d", rand () & 0x07, rand () & 0x0f);
- else
- strcpy (p, _("RI, #imm4"));
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R_R_R)
- {
- if (example)
- sprintf (p, "R%d,R%d,R%d", rand () & 0x07, rand () & 0x07, rand () & 0x07);
- else
- strcpy (p, "RD,RS1,RS2");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_REL9)
- {
- if (example)
- sprintf (p, "%d", rand () & 0x1FF);
- else
- strcpy (p, "<rel9>");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_REL10)
- {
- if (example)
- sprintf (p, "%d", rand () & 0x3FF);
- else
- strcpy (p, "<rel10>");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R_R_OFFS5)
- {
- if (example)
- sprintf (p, "R%d, (R%d, #0x%x)", rand () & 0x07, rand () & 0x07, rand () & 0x1f);
- else
- strcpy (p, _("RD, (RI,#offs5)"));
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_RD_RB_RI)
- {
- if (example)
- sprintf (p, "R%d, (R%d, R%d)", rand () & 0x07, rand () & 0x07, rand () & 0x07);
- else
- strcpy (p, "RD, (RB, RI)");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_RD_RB_RIp)
- {
- if (example)
- sprintf (p, "R%d, (R%d, R%d+)", rand () & 0x07, rand () & 0x07, rand () & 0x07);
- else
- strcpy (p, "RD, (RB, RI+)");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_RD_RB_mRI)
- {
- if (example)
- sprintf (p, "R%d, (R%d, -R%d)", rand () & 0x07, rand () & 0x07, rand () & 0x07);
- else
- strcpy (p, "RD, (RB, -RI)");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R_IMM8)
- {
- if (example)
- sprintf (p, "R%d, #0x%x", rand () & 0x07, rand () & 0xff);
- else
- strcpy (p, "RD, #imm8");
- p = &p[strlen (p)];
- }
- else if (format & M68XG_OP_R_IMM16)
- {
- if (example)
- sprintf (p, "R%d, #0x%x", rand () & 0x07, rand () & 0xffff);
- else
- strcpy (p, "RD, #imm16");
- p = &p[strlen (p)];
- }
- }
- else
- {
- if (format & M6811_OP_IMM8)
- {
- if (example)
- sprintf (p, "#%d", rand () & 0x0FF);
- else
- strcpy (p, _("#<imm8>"));
- p = &p[strlen (p)];
- }
- if (format & M6811_OP_IMM16)
- {
- if (example)
- sprintf (p, "#%d", rand () & 0x0FFFF);
- else
- strcpy (p, _("#<imm16>"));
- p = &p[strlen (p)];
- }
- if (format & M6811_OP_IX)
- {
- if (example)
- sprintf (p, "%d,X", rand () & 0x0FF);
- else
- strcpy (p, _("<imm8>,X"));
- p = &p[strlen (p)];
- }
- if (format & M6811_OP_IY)
- {
- if (example)
- sprintf (p, "%d,X", rand () & 0x0FF);
- else
- strcpy (p, _("<imm8>,X"));
- p = &p[strlen (p)];
- }
- if (format & M6812_OP_IDX)
- {
- if (example)
- sprintf (p, "%d,X", rand () & 0x0FF);
- else
- strcpy (p, "n,r");
- p = &p[strlen (p)];
- }
- if (format & M6812_OP_PAGE)
- {
- if (example)
- sprintf (p, ", %d", rand () & 0x0FF);
- else
- strcpy (p, ", <page>");
- p = &p[strlen (p)];
- }
- if (format & M6811_OP_DIRECT)
- {
- if (example)
- sprintf (p, "*Z%d", rand () & 0x0FF);
- else
- strcpy (p, _("*<abs8>"));
- p = &p[strlen (p)];
- }
- if (format & M6811_OP_BITMASK)
- {
- if (buf[0])
- *p++ = ' ';
- if (example)
- sprintf (p, "#$%02x", rand () & 0x0FF);
- else
- strcpy (p, _("#<mask>"));
- p = &p[strlen (p)];
- if (format & M6811_OP_JUMP_REL)
- *p++ = ' ';
- }
- if (format & M6811_OP_IND16)
- {
- if (example)
- sprintf (p, _("symbol%d"), rand () & 0x0FF);
- else
- strcpy (p, _("<abs>"));
- p = &p[strlen (p)];
- }
- if (format & (M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
- {
- if (example)
- {
- if (format & M6811_OP_BITMASK)
- {
- sprintf (p, ".+%d", rand () & 0x7F);
- }
- else
- {
- sprintf (p, "L%d", rand () & 0x0FF);
- }
- }
- else
- strcpy (p, _("<label>"));
- }
- }
- return buf;
- }
- /* Prints the list of instructions with the possible operands. */
- static void
- print_opcode_list (void)
- {
- int i;
- char *prev_name = "";
- struct m68hc11_opcode *opcodes;
- int example = flag_print_opcodes == 2;
- if (example)
- printf (_("# Example of `%s' instructions\n\t.sect .text\n_start:\n"),
- default_cpu);
- opcodes = m68hc11_sorted_opcodes;
- /* Walk the list sorted on names (by md_begin). We only report
- one instruction per line, and we collect the different operand
- formats. */
- for (i = 0; i < num_opcodes; i++, opcodes++)
- {
- char *fmt = print_opcode_format (opcodes, example);
- if (example)
- {
- printf ("L%d:\t", i);
- printf ("%s %s\n", opcodes->name, fmt);
- }
- else
- {
- if (strcmp (prev_name, opcodes->name))
- {
- if (i > 0)
- printf ("\n");
- printf ("%-5.5s ", opcodes->name);
- prev_name = (char *) opcodes->name;
- }
- if (fmt[0])
- printf (" [%s]", fmt);
- }
- }
- printf ("\n");
- }
- /* Print the instruction format. This operation is called when some
- instruction is not correct. Instruction format is printed as an
- error message. */
- static void
- print_insn_format (char *name)
- {
- struct m68hc11_opcode_def *opc;
- struct m68hc11_opcode *opcode;
- char buf[128];
- opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name);
- if (opc == NULL)
- {
- as_bad (_("Instruction `%s' is not recognized."), name);
- return;
- }
- opcode = opc->opcode;
- as_bad (_("Instruction formats for `%s':"), name);
- do
- {
- char *fmt;
- fmt = print_opcode_format (opcode, 0);
- sprintf (buf, "\t%-5.5s %s", opcode->name, fmt);
- as_bad ("%s", buf);
- opcode++;
- }
- while (strcmp (opcode->name, name) == 0);
- }
- /* Analysis of 68HC11 and 68HC12 operands. */
- /* reg_name_search() finds the register number given its name.
- Returns the register number or REG_NONE on failure. */
- static register_id
- reg_name_search (char *name)
- {
- if (strcasecmp (name, "x") == 0 || strcasecmp (name, "ix") == 0)
- return REG_X;
- if (strcasecmp (name, "y") == 0 || strcasecmp (name, "iy") == 0)
- return REG_Y;
- if (strcasecmp (name, "a") == 0)
- return REG_A;
- if (strcasecmp (name, "b") == 0)
- return REG_B;
- if (strcasecmp (name, "d") == 0)
- return REG_D;
- if (strcasecmp (name, "sp") == 0)
- return REG_SP;
- if (strcasecmp (name, "pc") == 0)
- return REG_PC;
- if (strcasecmp (name, "ccr") == 0)
- return REG_CCR;
- /* XGATE */
- if (strcasecmp (name, "r0") == 0)
- return REG_R0;
- if (strcasecmp (name, "r1") == 0)
- return REG_R1;
- if (strcasecmp (name, "r2") == 0)
- return REG_R2;
- if (strcasecmp (name, "r3") == 0)
- return REG_R3;
- if (strcasecmp (name, "r4") == 0)
- return REG_R4;
- if (strcasecmp (name, "r5") == 0)
- return REG_R5;
- if (strcasecmp (name, "r6") == 0)
- return REG_R6;
- if (strcasecmp (name, "r7") == 0)
- return REG_R7;
- if (strcasecmp (name, "sp") == 0)
- return REG_SP_XG;
- if (strcasecmp (name, "pc") == 0)
- return REG_PC_XG;
- if (strcasecmp (name, "ccr") == 0)
- return REG_CCR_XG;
- return REG_NONE;
- }
- static char *
- skip_whites (char *p)
- {
- while (*p == ' ' || *p == '\t')
- p++;
- return p;
- }
- /* Check the string at input_line_pointer
- to see if it is a valid register name. */
- static register_id
- register_name (void)
- {
- register_id reg_number;
- char c, *p = input_line_pointer;
- if (!is_name_beginner (*p++))
- return REG_NONE;
- while (is_part_of_name (*p++))
- continue;
- c = *--p;
- if (c)
- *p++ = 0;
- /* Look to see if it's in the register table. */
- reg_number = reg_name_search (input_line_pointer);
- if (reg_number != REG_NONE)
- {
- if (c)
- *--p = c;
- input_line_pointer = p;
- return reg_number;
- }
- if (c)
- *--p = c;
- return reg_number;
- }
- #define M6811_OP_CALL_ADDR 0x00800000
- #define M6811_OP_PAGE_ADDR 0x04000000
- /* Parse a string of operands and return an array of expressions.
- Operand mode[0] mode[1] exp[0] exp[1]
- #n M6811_OP_IMM16 - O_*
- *<exp> M6811_OP_DIRECT - O_*
- .{+-}<exp> M6811_OP_JUMP_REL - O_*
- <exp> M6811_OP_IND16 - O_*
- ,r N,r M6812_OP_IDX M6812_OP_REG O_constant O_register
- n,-r M6812_PRE_DEC M6812_OP_REG O_constant O_register
- n,+r M6812_PRE_INC " "
- n,r- M6812_POST_DEC " "
- n,r+ M6812_POST_INC " "
- A,r B,r D,r M6811_OP_REG M6812_OP_REG O_register O_register
- [D,r] M6811_OP_D_IDX M6812_OP_REG O_register O_register
- [n,r] M6811_OP_D_IDX_2 M6812_OP_REG O_constant O_register */
- static int
- get_operand (operand *oper, int which, long opmode)
- {
- char *p = input_line_pointer;
- int mode;
- register_id reg;
- oper->exp.X_op = O_absent;
- oper->reg1 = REG_NONE;
- oper->reg2 = REG_NONE;
- mode = M6811_OP_NONE;
- p = skip_whites (p);
- if (*p == 0 || *p == '\n' || *p == '\r')
- {
- input_line_pointer = p;
- return 0;
- }
- if (*p == '*' && (opmode & (M6811_OP_DIRECT | M6811_OP_IND16)))
- {
- mode = M6811_OP_DIRECT;
- p++;
- }
- else if (*p == '#')
- {
- if (!(opmode & (M6811_OP_IMM8 | M6811_OP_IMM16 | M6811_OP_BITMASK)))
- {
- as_bad (_("Immediate operand is not allowed for operand %d."),
- which);
- return -1;
- }
- mode = M6811_OP_IMM16;
- p++;
- if (strncmp (p, "%hi", 3) == 0)
- {
- p += 3;
- mode |= M6811_OP_HIGH_ADDR;
- }
- else if (strncmp (p, "%lo", 3) == 0)
- {
- p += 3;
- mode |= M6811_OP_LOW_ADDR;
- }
- /* %page modifier is used to obtain only the page number
- of the address of a function. */
- else if (strncmp (p, "%page", 5) == 0)
- {
- p += 5;
- mode |= M6811_OP_PAGE_ADDR;
- }
- /* %addr modifier is used to obtain the physical address part
- of the function (16-bit). For 68HC12 the function will be
- mapped in the 16K window at 0x8000 and the value will be
- within that window (although the function address may not fit
- in 16-bit). See bfd/elf32-m68hc12.c for the translation. */
- else if (strncmp (p, "%addr", 5) == 0)
- {
- p += 5;
- mode |= M6811_OP_CALL_ADDR;
- }
- }
- else if (*p == '.' && (p[1] == '+' || p[1] == '-'))
- {
- p++;
- mode = M6811_OP_JUMP_REL;
- }
- else if (*p == '[')
- {
- if (current_architecture & cpu6811)
- as_bad (_("Indirect indexed addressing is not valid for 68HC11."));
- p++;
- mode = M6812_OP_D_IDX;
- p = skip_whites (p);
- }
- else if (*p == ',') /* Special handling of ,x and ,y. */
- {
- p++;
- input_line_pointer = p;
- reg = register_name ();
- if (reg != REG_NONE)
- {
- oper->reg1 = reg;
- oper->exp.X_op = O_constant;
- oper->exp.X_add_number = 0;
- oper->mode = M6812_OP_IDX;
- return 1;
- }
- as_bad (_("Spurious `,' or bad indirect register addressing mode."));
- return -1;
- }
- /* Handle 68HC12 page specification in 'call foo,%page(bar)'. */
- else if ((opmode & M6812_OP_PAGE) && strncmp (p, "%page", 5) == 0)
- {
- p += 5;
- mode = M6811_OP_PAGE_ADDR | M6812_OP_PAGE | M6811_OP_IND16;
- }
- input_line_pointer = p;
- if (mode == M6811_OP_NONE || mode == M6812_OP_D_IDX)
- reg = register_name ();
- else
- reg = REG_NONE;
- if (reg != REG_NONE)
- {
- p = skip_whites (input_line_pointer);
- if (*p == ']' && mode == M6812_OP_D_IDX)
- {
- as_bad
- (_("Missing second register or offset for indexed-indirect mode."));
- return -1;
- }
- oper->reg1 = reg;
- oper->mode = mode | M6812_OP_REG;
- if (*p != ',')
- {
- if (mode == M6812_OP_D_IDX)
- {
- as_bad (_("Missing second register for indexed-indirect mode."));
- return -1;
- }
- return 1;
- }
- p++;
- input_line_pointer = p;
- reg = register_name ();
- if (reg != REG_NONE)
- {
- p = skip_whites (input_line_pointer);
- if (mode == M6812_OP_D_IDX)
- {
- if (*p != ']')
- {
- as_bad (_("Missing `]' to close indexed-indirect mode."));
- return -1;
- }
- p++;
- oper->mode = M6812_OP_D_IDX;
- }
- 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_D_IDX)
- {
- p = skip_whites (input_line_pointer);
- if (*p == ',')
- {
- int possible_mode = M6811_OP_NONE;
- char *old_input_line;
- old_input_line = p;
- 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);
- }
- 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_D_IDX)
- {
- p = skip_whites (input_line_pointer);
- if (*p++ != ']')
- {
- as_bad (_("Missing `]' to close register indirect operand."));
- return -1;
- }
- input_line_pointer = p;
- oper->reg1 = reg;
- oper->mode = M6812_OP_D_IDX_2;
- return 1;
- }
- 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;
- }
- input_line_pointer = old_input_line;
- }
- 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 int
- check_range (long num, int mode)
- {
- if (current_architecture == cpuxgate)
- {
- switch (mode)
- {
- case M68XG_OP_IMM3:
- return (num >= 0 && num <= 7) ? 1 : 0;
- case M68XG_OP_R_IMM4:
- return (num >= 0 && num <= 15) ? 1 : 0;
- case M68XG_OP_R_R_OFFS5:
- return (num >= 0 && num <= 31) ? 1 : 0;
- case M68XG_OP_R_IMM8:
- return (num >= 0 && num <= 255) ? 1 : 0;
- case M68XG_OP_R_IMM16:
- return (num >= 0 && num <= 65535) ? 1 : 0;
- case M68XG_OP_B_MARKER:
- return (num >= -512 && num <= 511) ? 1 : 0;
- case M68XG_OP_BRA_MARKER:
- return (num >= -1024 && num <= 1023) ? 1 : 0;
- default:
- return 0;
- }
- }
- else
- {
- /* 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;
- mode &= ~M6811_OP_BRANCH;
- 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:
- case M6812_OP_PAGE:
- 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_IND16 | M6812_OP_PAGE:
- 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 void
- fixup8 (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
- {
- fixS *fixp;
- int reloc;
- /* Now create an 8-bit fixup. If there was some %hi, %lo
- or %page modifier, generate the reloc accordingly. */
- if (opmode & M6811_OP_HIGH_ADDR)
- reloc = BFD_RELOC_M68HC11_HI8;
- else if (opmode & M6811_OP_LOW_ADDR)
- reloc = BFD_RELOC_M68HC11_LO8;
- else if (opmode & M6811_OP_PAGE_ADDR)
- reloc = BFD_RELOC_M68HC11_PAGE;
- else
- reloc = BFD_RELOC_8;
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, FALSE, reloc);
- if (reloc != BFD_RELOC_8)
- fixp->fx_no_overflow = 1;
- }
- 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 void
- fixup16 (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;
- int reloc;
- if ((opmode & M6811_OP_CALL_ADDR) && (mode & M6811_OP_IMM16))
- reloc = BFD_RELOC_M68HC11_LO16;
- else if (mode & M6812_OP_JUMP_REL16)
- reloc = BFD_RELOC_16_PCREL;
- else if (mode & M6812_OP_PAGE)
- reloc = BFD_RELOC_M68HC11_LO16;
- else
- reloc = BFD_RELOC_16;
- /* Now create a 16-bit fixup. */
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
- oper,
- reloc == BFD_RELOC_16_PCREL,
- reloc);
- number_to_chars_bigendian (f, 0, 2);
- if (reloc == BFD_RELOC_16_PCREL)
- fixp->fx_pcrel_adjust = 2;
- if (reloc == BFD_RELOC_M68HC11_LO16)
- fixp->fx_no_overflow = 1;
- }
- else
- {
- as_fatal (_("Operand `%x' not recognized in fixup16."), oper->X_op);
- }
- }
- /* Put a 3 byte expression described by 'oper'. If this expression contains
- unresolved symbols, generate a 24-bit fixup. */
- static void
- fixup24 (expressionS *oper, int mode, int opmode ATTRIBUTE_UNUSED)
- {
- char *f;
- f = frag_more (3);
- 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 & 0x0FFFFFF, 3);
- }
- else if (oper->X_op != O_register)
- {
- /* Now create a 24-bit fixup. */
- fix_new_exp (frag_now, f - frag_now->fr_literal, 3,
- oper, FALSE, BFD_RELOC_M68HC11_24);
- number_to_chars_bigendian (f, 0, 3);
- }
- else
- {
- as_fatal (_("Operand `%x' not recognized in fixup16."), oper->X_op);
- }
- }
- /* XGATE Put a 1 byte expression described by 'oper'. If this expression
- containts unresolved symbols, generate an 8-bit fixup. */
- static void
- fixup8_xg (expressionS *oper, int mode, int opmode)
- {
- char *f;
- f = frag_more (1);
- if (oper->X_op == O_constant)
- {
- fixS *fixp;
- int reloc;
- if ((opmode & M6811_OP_HIGH_ADDR) || (opmode & M6811_OP_LOW_ADDR))
- {
- if (opmode & M6811_OP_HIGH_ADDR)
- reloc = BFD_RELOC_M68HC11_HI8;
- else
- reloc = BFD_RELOC_M68HC11_LO8;
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, FALSE, reloc);
- fixp->fx_no_overflow = 1;
- number_to_chars_bigendian (f, 0, 1);
- }
- else
- {
- if (!(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 == M68XG_OP_REL9)
- {
- fixS *fixp;
- /* Future improvement:
- This fixup/reloc isn't adding on constants to symbols. */
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal -1, 2,
- oper, TRUE, BFD_RELOC_M68HC12_9_PCREL);
- fixp->fx_pcrel_adjust = 1;
- }
- else if (mode == M68XG_OP_REL10)
- {
- fixS *fixp;
- /* Future improvement:
- This fixup/reloc isn't adding on constants to symbols. */
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal -1, 2,
- oper, TRUE, BFD_RELOC_M68HC12_10_PCREL);
- fixp->fx_pcrel_adjust = 1;
- }
- else
- {
- fixS *fixp;
- int reloc;
- /* Now create an 8-bit fixup. If there was some %hi, %lo
- modifier, generate the reloc accordingly. */
- if (opmode & M6811_OP_HIGH_ADDR)
- reloc = BFD_RELOC_M68HC11_HI8;
- else if (opmode & M6811_OP_LOW_ADDR)
- reloc = BFD_RELOC_M68HC11_LO8;
- else
- reloc = BFD_RELOC_8;
- fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, FALSE, reloc);
- if (reloc != BFD_RELOC_8)
- fixp->fx_no_overflow = 1;
- }
- number_to_chars_bigendian (f, 0, 1);
- }
- else
- as_fatal (_("Operand `%x' not recognized in fixup8."), oper->X_op);
- }
- /* 68HC11 and 68HC12 code generation. */
- /* Translate the short branch/bsr instruction into a long branch. */
- static unsigned char
- convert_branch (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 (int size)
- {
- char *f;
- f = frag_more (size);
- dwarf2_emit_insn (size);
- return f;
- }
- /* Builds a jump instruction (bra, bcc, bsr). */
- static void
- build_jump_insn (struct m68hc11_opcode *opcode, operand operands[],
- int nb_operands, int jmp_mode)
- {
- unsigned char code;
- char *f;
- unsigned long n;
- /* The relative branch conversion is not supported for
- brclr and brset. */
- gas_assert ((opcode->format & M6811_OP_BITMASK) == 0);
- gas_assert (nb_operands == 1);
- gas_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_branches == 0))))
- {
- fix_new (frag_now, frag_now_fix (), 0,
- &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
- 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)
- {
- fix_new (frag_now, frag_now_fix (), 0,
- &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
- f = m68hc11_new_insn (2);
- …
Large files files are truncated, but you can click here to view the full file