/* tc-m68hc11.c -- Assembler code for the Motorola 68HC11 & 68HC12.
- Copyright (C) 1999-2015 Free Software Foundation, Inc.
+ Copyright (C) 1999-2023 Free Software Foundation, Inc.
Written by Stephane Carrez (stcarrez@nerim.fr)
XGATE and S12X added by James Murray (jsm@jsm-net.demon.co.uk)
dbcc -> db!cc +3
jmp L
- Setting the flag forbidds this. */
+ Setting the flag forbids this. */
static short flag_fixed_branches = 0;
/* Force to use long jumps (absolute) instead of relative branches. */
static short flag_print_opcodes = 0;
/* Opcode hash table. */
-static struct hash_control *m68hc11_hash;
+static htab_t 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
{
#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. */
+ {"force-long-branchs", no_argument, NULL, OPTION_FORCE_LONG_BRANCH}, /* Misspelled 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. */
+ {"short-branchs", no_argument, NULL, OPTION_SHORT_BRANCHES}, /* Misspelled version kept for backwards compatibility. */
#define OPTION_STRICT_DIRECT_MODE (OPTION_MD_BASE + 2)
{"strict-direct-mode", no_argument, NULL, OPTION_STRICT_DIRECT_MODE},
int i;
struct m68hc11_opcode_def *opc;
- hash_print_statistics (file, "opcode table", m68hc11_hash);
+ htab_print_statistics (file, "opcode table", m68hc11_hash);
opc = m68hc11_opcode_defs;
if (opc == 0 || m68hc11_nb_opcode_defs == 0)
}
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
get_default_target ();
switch (c)
current_architecture = cpu6812 | cpu6812s | cpu9s12x;
else if ((strcasecmp (arg, "m9s12xg") == 0)
|| (strcasecmp (arg, "xgate") == 0))
- /* xgate for backwards compatability */
+ /* xgate for backwards compatibility */
current_architecture = cpuxgate;
else
as_bad (_("Option `%s' is not recognized."), arg);
return 0;
}
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
- return ieee_md_atof (type, litP, sizeP, TRUE);
+ 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));
+ int align = bfd_section_alignment (seg);
+ return ((addr + (1 << align) - 1) & -(1 << align));
}
static int
void
md_begin (void)
{
- char *prev_name = "";
+ const char *prev_name = "";
struct m68hc11_opcode *opcodes;
struct m68hc11_opcode_def *opc = 0;
int i, j;
get_default_target ();
- m68hc11_hash = hash_new ();
+ m68hc11_hash = str_htab_create ();
/* 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));
+ opcodes = XNEWVEC (struct m68hc11_opcode, m68hc11_num_opcodes);
m68hc11_sorted_opcodes = opcodes;
num_opcodes = 0;
for (i = 0; i < m68hc11_num_opcodes; i++)
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--;
+ opc = XNEWVEC (struct m68hc11_opcode_def, num_opcodes);
+ m68hc11_opcode_defs = opc;
/* Insert unique names into hash table. The M6811 instruction set
has several identical opcode names that have different opcodes based
if (strcmp (prev_name, opcodes->name))
{
- prev_name = (char *) opcodes->name;
-
+ prev_name = 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 - 1)->format = 0;
+ (opc - 1)->min_operands = 100;
+ (opc - 1)->max_operands = 0;
+ (opc - 1)->nb_modes = 0;
+ (opc - 1)->opcode = opcodes;
+ (opc - 1)->used = 0;
+ str_hash_insert (m68hc11_hash, opcodes->name, opc - 1, 0);
}
- opc->nb_modes++;
- opc->format |= opcodes->format;
+ (opc - 1)->nb_modes++;
+ (opc - 1)->format |= opcodes->format;
/* See how many operands this opcode needs. */
expect = 0;
expect++;
}
- if (expect < opc->min_operands)
- opc->min_operands = expect;
+ if (expect < (opc - 1)->min_operands)
+ (opc - 1)->min_operands = expect;
if (IS_CALL_SYMBOL (opcodes->format))
expect++;
- if (expect > opc->max_operands)
- opc->max_operands = expect;
+ if (expect > (opc - 1)->max_operands)
+ (opc - 1)->max_operands = expect;
}
- opc++;
m68hc11_nb_opcode_defs = opc - m68hc11_opcode_defs;
if (flag_print_opcodes)
print_opcode_list (void)
{
int i;
- char *prev_name = "";
+ const char *prev_name = "";
struct m68hc11_opcode *opcodes;
int example = flag_print_opcodes == 2;
struct m68hc11_opcode *opcode;
char buf[128];
- opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name);
+ opc = (struct m68hc11_opcode_def *) str_hash_find (m68hc11_hash, name);
if (opc == NULL)
{
as_bad (_("Instruction `%s' is not recognized."), name);
mode = M6811_OP_IMM16;
p++;
- if (strncmp (p, "%hi", 3) == 0)
+ if (startswith (p, "%hi"))
{
p += 3;
mode |= M6811_OP_HIGH_ADDR;
}
- else if (strncmp (p, "%lo", 3) == 0)
+ else if (startswith (p, "%lo"))
{
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)
+ else if (startswith (p, "%page"))
{
p += 5;
mode |= M6811_OP_PAGE_ADDR;
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)
+ else if (startswith (p, "%addr"))
{
p += 5;
mode |= M6811_OP_CALL_ADDR;
return -1;
}
/* Handle 68HC12 page specification in 'call foo,%page(bar)'. */
- else if ((opmode & M6812_OP_PAGE) && strncmp (p, "%page", 5) == 0)
+ else if ((opmode & M6812_OP_PAGE) && startswith (p, "%page"))
{
p += 5;
mode = M6811_OP_PAGE_ADDR | M6812_OP_PAGE | M6811_OP_IND16;
if (mode == M6811_OP_JUMP_REL)
{
fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, TRUE, BFD_RELOC_8_PCREL);
+ oper, true, BFD_RELOC_8_PCREL);
}
else
{
fixS *fixp;
- int reloc;
+ bfd_reloc_code_real_type reloc;
/* Now create an 8-bit fixup. If there was some %hi, %lo
or %page modifier, generate the reloc accordingly. */
reloc = BFD_RELOC_8;
fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, FALSE, reloc);
+ oper, false, reloc);
if (reloc != BFD_RELOC_8)
fixp->fx_no_overflow = 1;
}
else if (oper->X_op != O_register)
{
fixS *fixp;
- int reloc;
+ bfd_reloc_code_real_type reloc;
if ((opmode & M6811_OP_CALL_ADDR) && (mode & M6811_OP_IMM16))
reloc = BFD_RELOC_M68HC11_LO16;
{
/* Now create a 24-bit fixup. */
fix_new_exp (frag_now, f - frag_now->fr_literal, 3,
- oper, FALSE, BFD_RELOC_M68HC11_24);
+ oper, false, BFD_RELOC_M68HC11_24);
number_to_chars_bigendian (f, 0, 3);
}
else
}
/* XGATE Put a 1 byte expression described by 'oper'. If this expression
- containts unresolved symbols, generate an 8-bit fixup. */
+ contains unresolved symbols, generate an 8-bit fixup. */
static void
fixup8_xg (expressionS *oper, int mode, int opmode)
{
if (oper->X_op == O_constant)
{
fixS *fixp;
- int reloc;
+ bfd_reloc_code_real_type reloc;
if ((opmode & M6811_OP_HIGH_ADDR) || (opmode & M6811_OP_LOW_ADDR))
{
reloc = BFD_RELOC_M68HC11_LO8;
fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, FALSE, reloc);
+ oper, false, reloc);
fixp->fx_no_overflow = 1;
number_to_chars_bigendian (f, 0, 1);
}
/* Future improvement:
This fixup/reloc isn't adding on constants to symbols. */
fix_new_exp (frag_now, f - frag_now->fr_literal -1, 2,
- oper, TRUE, BFD_RELOC_M68HC12_9_PCREL);
+ oper, true, BFD_RELOC_M68HC12_9_PCREL);
}
else if (mode == M68XG_OP_REL10)
{
/* Future improvement:
This fixup/reloc isn't adding on constants to symbols. */
fix_new_exp (frag_now, f - frag_now->fr_literal -1, 2,
- oper, TRUE, BFD_RELOC_M68HC12_10_PCREL);
+ oper, true, BFD_RELOC_M68HC12_10_PCREL);
}
else
{
fixS *fixp;
- int reloc;
+ bfd_reloc_code_real_type reloc;
/* Now create an 8-bit fixup. If there was some %hi, %lo
modifier, generate the reloc accordingly. */
reloc = BFD_RELOC_8;
fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- oper, FALSE, reloc);
+ oper, false, reloc);
if (reloc != BFD_RELOC_8)
fixp->fx_no_overflow = 1;
}
if (!check_range (val, M6812_OP_IDX))
as_bad (_("Offset out of 16-bit range: %ld."), val);
- if (move_insn && !(val >= -16 && val <= 15)
- && ((!(mode & M6812_OP_IDX) && !(mode & M6812_OP_D_IDX_2))
+ if (move_insn && !(val >= -16 && val <= 15)
+ && ((!(mode & M6812_OP_IDX) && !(mode & M6812_OP_D_IDX_2))
|| !(current_architecture & cpu9s12x)))
{
as_bad (_("Offset out of 5-bit range for movw/movb insn: %ld."),
default:
as_bad (_("Invalid accumulator register."));
+ /* Fall through. */
case REG_D:
byte = 0xE6;
operands[0].mode = M6811_OP_LOW_ADDR;
f = frag_more (1);
fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- &operands[0].exp, FALSE, BFD_RELOC_M68HC12_LO8XG);
+ &operands[0].exp, false, BFD_RELOC_M68HC12_LO8XG);
fixp->fx_no_overflow = 1;
number_to_chars_bigendian (f, 0, 1);
operands[0].mode = M6811_OP_HIGH_ADDR;
f = frag_more (1);
fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
- &operands[0].exp, FALSE, BFD_RELOC_M68HC12_HI8XG);
+ &operands[0].exp, false, BFD_RELOC_M68HC12_HI8XG);
fixp->fx_no_overflow = 1;
number_to_chars_bigendian (f, 0, 1);
f = m68hc11_new_insn (1);
number_to_chars_bigendian (f, opcode->opcode >> 8, 1); /* High byte. */
fixup8_xg (&operands[0].exp, format, M68XG_OP_REL9);
- }
+ }
else if (format & M68XG_OP_REL10)
{
f = m68hc11_new_insn (1);
if (current_architecture == cpuxgate)
{
/* Find the opcode definition given its name. */
- opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name);
+ opc = (struct m68hc11_opcode_def *) str_hash_find (m68hc11_hash, name);
if (opc == NULL)
{
as_bad (_("Opcode `%s' is not recognized."), name);
}
/* Special handling of TFR. */
- if (strncmp (opc->opcode->name, "tfr",3) == 0)
+ if (startswith (opc->opcode->name, "tfr"))
{
/* There must be two operands with a comma. */
input_line_pointer = skip_whites (input_line_pointer);
}
else
as_bad ("No opcode found\n");
-
+
return;
}
else
{
opcode_local.opcode |= (operands[0].exp.X_add_number);
operands[0].mode = M68XG_OP_IMM3;
-
+
opcode = find (opc, operands, 1);
if (opcode)
{
}
/* Special handling of SIF. */
- if (strncmp (opc->opcode->name, "sif",3) == 0)
+ if (startswith (opc->opcode->name, "sif"))
{
/* Either OP_NONE or OP_RS. */
if (*input_line_pointer != '\n')
opcode = find (opc, operands, 1);
if (opcode)
{
- if ((strncmp (opc->opcode->name, "com",3) == 0)
- || (strncmp (opc->opcode->name, "neg",3) == 0))
+ if ((startswith (opc->opcode->name, "com"))
+ || (startswith (opc->opcode->name, "neg")))
/* Special case for com RD as alias for sub RD,R0,RS */
/* Special case for neg RD as alias for sub RD,R0,RS */
opcode_local.opcode = opcode->opcode
| (operands[0].reg1 << 8) | (operands[0].reg1 << 2);
- else if (strncmp (opc->opcode->name, "tst",3) == 0)
+ else if (startswith (opc->opcode->name, "tst"))
/* Special case for tst RS alias for sub R0, RS, R0 */
opcode_local.opcode = opcode->opcode
| (operands[0].reg1 << 5);
if (opc->format & (M68XG_OP_REL9 | M68XG_OP_REL10))
{
- opcode_local.format = opc->format;
+ opcode_local.format = opc->format;
input_line_pointer = skip_whites (input_line_pointer);
expression (&operands[0].exp);
if (operands[0].exp.X_op == O_illegal)
if ((*input_line_pointer == '\n') || (*input_line_pointer == '\r')
|| (*input_line_pointer == '\0'))
return; /* nothing left */
-
+
if (*input_line_pointer == '#')
{
as_bad ("No register specified before hash\n");
return;
- }
+ }
/* first operand is expected to be a register */
if ((*input_line_pointer == 'R') || (*input_line_pointer == 'r'))
{
input_line_pointer++;
input_line_pointer = skip_whites (input_line_pointer);
- if (strncmp (input_line_pointer, "%hi", 3) == 0)
+ if (startswith (input_line_pointer, "%hi"))
{
input_line_pointer += 3;
operands[0].mode = M6811_OP_HIGH_ADDR;
}
- else if (strncmp (input_line_pointer, "%lo", 3) == 0)
+ else if (startswith (input_line_pointer, "%lo"))
{
input_line_pointer += 3;
operands[0].mode = M6811_OP_LOW_ADDR;
if (opcode)
opcode_local.opcode = opcode->opcode
| (operands[0].reg1 << 8);
-
+
if (operands[0].exp.X_op != O_constant)
as_bad ("Only constants supported at for IMM4 mode\n");
else
{
- if (check_range
+ if (check_range
(operands[0].exp.X_add_number,M68XG_OP_R_IMM4))
opcode_local.opcode
|= (operands[0].exp.X_add_number << 4);
opcode = find (opc, operands, 1);
if (opcode)
{
- if ((strncmp (opc->opcode->name, "com",3) == 0)
- || (strncmp (opc->opcode->name, "mov",3) == 0)
- || (strncmp (opc->opcode->name, "neg",3) == 0))
+ if ((startswith (opc->opcode->name, "com"))
+ || (startswith (opc->opcode->name, "mov"))
+ || (startswith (opc->opcode->name, "neg")))
{
/* Special cases for:
com RD, RS alias for xnor RD,R0,RS
mov RD, RS alias for or RD, R0, RS
neg RD, RS alias for sub RD, R0, RS */
- opcode_local.opcode = opcode->opcode
+ opcode_local.opcode = opcode->opcode
| (operands[0].reg1 << 8) | (operands[1].reg1 << 2);
}
- else if ((strncmp (opc->opcode->name, "cmp",3) == 0)
- || (strncmp (opc->opcode->name, "cpc",3) == 0))
+ else if ((startswith (opc->opcode->name, "cmp"))
+ || (startswith (opc->opcode->name, "cpc")))
{
/* special cases for:
cmp RS1, RS2 alias for sub R0, RS1, RS2
cpc RS1, RS2 alias for sbc R0, RS1, RS2 */
- opcode_local.opcode = opcode->opcode
+ opcode_local.opcode = opcode->opcode
| (operands[0].reg1 << 5) | (operands[1].reg1 << 2);
}
else
opcode = find (opc, operands, 1);
if (opcode)
{
- opcode_local.opcode = opcode->opcode
+ opcode_local.opcode = opcode->opcode
| (operands[0].reg1 << 8) | (operands[1].reg1 << 5)
| (operands[2].reg1 << 2);
opcode_local.format = M68XG_OP_NONE;
}
input_line_pointer = skip_whites (input_line_pointer);
-
+
if (*input_line_pointer != ',')
{
as_bad (_("Missing operand."));
{
input_line_pointer++;
}
-
+
/* Ok so far, can only be one mode. */
opcode_local.format = M68XG_OP_R_R_OFFS5;
operands[0].mode = M68XG_OP_R_R_OFFS5;
}
/* Find the opcode definition given its name. */
- opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name);
+ opc = (struct m68hc11_opcode_def *) str_hash_find (m68hc11_hash, name);
/* If it's not recognized, look for 'jbsr' and 'jbxx'. These are
pseudo insns for relative branch. For these branches, we always
is given. */
if (opc == NULL && name[0] == 'j' && name[1] == 'b')
{
- opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, &name[1]);
+ opc = (struct m68hc11_opcode_def *) str_hash_find (m68hc11_hash,
+ &name[1]);
if (opc
&& (!(opc->format & M6811_OP_JUMP_REL)
|| (opc->format & M6811_OP_BITMASK)))
{
name[nlen++] = TOLOWER (*op_end++);
name[nlen] = 0;
- opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash,
- name);
+ opc = (struct m68hc11_opcode_def *) str_hash_find (m68hc11_hash,
+ name);
}
}
}
do
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
symbolP = symbol_find_or_make (name);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
SKIP_WHITESPACE ();
bfdsym = symbol_get_bfdsym (symbolP);
- elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+ elfsym = elf_symbol_from (bfdsym);
gas_assert (elfsym);
{
arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
if (fixp->fx_r_type == 0)
const relax_typeS *table = TC_GENERIC_RELAX_TABLE;
/* We only have to cope with frags as prepared by
- md_estimate_size_before_relax. The STATE_BITS16 case may geet here
+ md_estimate_size_before_relax. The STATE_BITS16 case may get here
because of the different reasons that it's not relaxable. */
switch (fragP->fr_subtype)
{
if (fragP->fr_symbol == NULL
|| S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
as_fatal (_("internal inconsistency problem in %s: fr_symbol %lx"),
- __FUNCTION__, (long) fragP->fr_symbol);
+ __func__, (long) fragP->fr_symbol);
symbolP = fragP->fr_symbol;
if (symbol_resolved_p (symbolP))
as_fatal (_("internal inconsistency problem in %s: resolved symbol"),
- __FUNCTION__);
+ __func__);
aim = S_GET_VALUE (symbolP);
break;
default:
as_fatal (_("internal inconsistency problem in %s: fr_subtype %d"),
- __FUNCTION__, fragP->fr_subtype);
+ __func__, fragP->fr_subtype);
}
/* The rest is stolen from relax_frag. There's no obvious way to
/* We don't actually support subtracting a symbol. */
if (fixP->fx_subsy != (symbolS *) NULL)
- as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
+ as_bad_subtract (fixP);
/* Patch the instruction with the resolved operand. Elf relocation
info will also be generated to take care of linker/loader fixups.
value);
if (value >= 0)
where[0] |= value;
- else
+ else
where[0] |= (0x10 | (16 + value));
break;
/* sign bit already in xb postbyte */
if (value >= 0)
where[1] = value;
- else
+ else
where[1] = (256 + value);
break;