/* tc-s12z.c -- Assembler code for the Freescale S12Z
- Copyright (C) 2018 Free Software Foundation, Inc.
+ Copyright (C) 2018-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
const char line_comment_chars[] = "#*";
const char line_separator_chars[] = "";
+static char * register_prefix = NULL;
+
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
static char *fail_line_pointer;
+/* A wrapper around the standard library's strtol.
+ It converts STR into an integral value.
+ This wrapper deals with literal_prefix_dollar_hex. */
+static long
+s12z_strtol (const char *str, char ** endptr)
+{
+ int base = 0;
+ bool negative = false;
+
+ long result = 0;
+
+ char *start = (char *) str;
+
+ /* In the case where literal_prefix_dollar_hex is TRUE the sign has
+ to be handled explicitly. Otherwise the string will not be
+ recognised as an integer. */
+ if (str[0] == '-')
+ {
+ negative = true;
+ ++str;
+ }
+ else if (str[0] == '+')
+ {
+ ++str;
+ }
+
+ if (literal_prefix_dollar_hex && (str[0] == '$'))
+ {
+ base = 16;
+ str++;
+ }
+
+ result = strtol (str, endptr, base);
+ if (*endptr == str)
+ {
+ *endptr = start;
+ }
+ if (negative)
+ result = -result;
+
+ return result;
+}
+
+
\f
/* Options and initialization. */
-const char *md_shortopts = "Sm:";
+const char *md_shortopts = "";
struct option md_longopts[] =
{
+#define OPTION_REG_PREFIX (OPTION_MD_BASE)
+ {"mreg-prefix", required_argument, NULL, OPTION_REG_PREFIX},
+#define OPTION_DOLLAR_HEX (OPTION_MD_BASE + 1)
+ {"mdollar-hex", no_argument, NULL, OPTION_DOLLAR_HEX},
+ {NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
}
void
-md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
+md_show_usage (FILE *stream)
{
+ fputs (_("\ns12z options:\n"), stream);
+ fputs (_(" -mreg-prefix=PREFIX set a prefix used to indicate register names (default none)\n"), stream);
+ fputs (_(" -mdollar-hex the prefix '$' instead of '0x' is used to indicate literal hexadecimal constants\n"), stream);
}
void
}
int
-md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char *arg)
{
- return 0;
+ switch (c)
+ {
+ case OPTION_REG_PREFIX:
+ register_prefix = xstrdup (arg);
+ break;
+ case OPTION_DOLLAR_HEX:
+ literal_prefix_dollar_hex = TRUE;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
}
\f
symbolS *
valueT
md_section_align (asection *seg, valueT addr)
{
- int align = bfd_get_section_alignment (stdoutput, seg);
+ int align = bfd_section_alignment (seg);
return ((addr + (1 << align) - 1) & -(1 << align));
}
void
s12z_init_after_args (void)
{
+ if (flag_traditional_format)
+ literal_prefix_dollar_hex = TRUE;
}
\f
/* Builtin help. */
\f
-static int lex_reg_name (uint16_t which, int *reg);
+static bfd_boolean lex_reg_name (uint16_t which, int *reg);
-static int
+static bfd_boolean
lex_constant (long *v)
{
char *end = NULL;
if (lex_reg_name (~0, &dummy))
{
input_line_pointer = p;
- return 0;
+ return false;
}
errno = 0;
- *v = strtol (p, &end, 0);
+ *v = s12z_strtol (p, &end);
if (errno == 0 && end != p)
{
input_line_pointer = end;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-static int
+static bfd_boolean
lex_match (char x)
{
char *p = input_line_pointer;
if (*p != x)
- return 0;
+ return false;
input_line_pointer++;
- return 1;
+ return true;
}
-static int
+static bfd_boolean
lex_expression (expressionS *exp)
{
char *ilp = input_line_pointer;
expression (exp);
if (exp->X_op != O_absent)
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-/* immediate operand */
-static int
-lex_imm (long *v)
+/* Immediate operand.
+ If EXP_O is non-null, then a symbolic expression is permitted,
+ in which case, EXP_O will be populated with the parsed expression.
+ */
+static bfd_boolean
+lex_imm (long *v, expressionS *exp_o)
{
char *ilp = input_line_pointer;
goto fail;
if (exp.X_op != O_constant)
- goto fail;
+ {
+ if (!exp_o)
+ as_bad (_("A non-constant expression is not permitted here"));
+ else
+ *exp_o = exp;
+ }
*v = exp.X_add_number;
- return 1;
+ return true;
-fail:
+ fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
/* Short mmediate operand */
-static int
+static bfd_boolean
lex_imm_e4 (long *val)
{
char *ilp = input_line_pointer;
- if ((lex_imm (val)))
+ if ((lex_imm (val, NULL)))
{
if ((*val == -1) || (*val > 0 && *val <= 15))
{
- return 1;
+ return true;
}
}
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
lex_match_string (const char *s)
{
char *p = input_line_pointer;
size_t len = p - input_line_pointer;
if (len != strlen (s))
- return 0;
+ return false;
if (0 == strncasecmp (s, input_line_pointer, len))
{
input_line_pointer = p;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Parse a register name.
On success, REG will be filled with the index of the register which
was successfully scanned.
*/
-static int
+static bfd_boolean
lex_reg_name (uint16_t which, int *reg)
{
char *p = input_line_pointer;
- while (p != 0 &&
- ((*p >= 'a' && *p <='z') || (*p >= '0' && *p <= '9') || (*p >= 'A' && *p <='Z')))
+
+ if (p == 0)
+ return false;
+
+ /* Scan (and ignore) the register prefix. */
+ if (register_prefix)
+ {
+ int len = strlen (register_prefix);
+ if (0 == strncmp (register_prefix, p, len))
+ p += len;
+ else
+ return false;
+ }
+
+ char *start_of_reg_name = p;
+
+ while ((*p >= 'a' && *p <='z')
+ || (*p >= '0' && *p <= '9')
+ || (*p >= 'A' && *p <='Z'))
{
p++;
}
- int len = p - input_line_pointer;
+ size_t len = p - start_of_reg_name;
if (len <= 0)
- return 0;
+ return false;
int i;
for (i = 0; i < S12Z_N_REGISTERS; ++i)
{
gas_assert (registers[i].name);
- if (0 == strncasecmp (registers[i].name, input_line_pointer, len))
+ if (len == strlen (registers[i].name)
+ && 0 == strncasecmp (registers[i].name, start_of_reg_name, len))
{
if ((0x1U << i) & which)
{
input_line_pointer = p;
*reg = i;
- return 1;
+ return true;
}
}
}
- return 0;
+ return false;
}
static int
if (*p != x)
{
as_bad (_("Expecting '%c'"), x);
- return 0;
+ return false;
}
input_line_pointer++;
- return 1;
+ return true;
}
-static int
-lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp)
+static bfd_boolean
+lex_opr (uint8_t *buffer, int *n_bytes, expressionS *exp,
+ bool immediate_ok)
{
char *ilp = input_line_pointer;
uint8_t *xb = buffer;
*xb = 0;
if (lex_imm_e4 (&imm))
{
+ if (!immediate_ok)
+ {
+ as_bad (_("An immediate value in a source operand is inappropriate"));
+ return false;
+ }
if (imm > 0)
*xb = imm;
else
*xb = 0;
*xb |= 0x70;
*n_bytes = 1;
- return 1;
+ return true;
}
else if (lex_reg_name (REG_BIT_Dn, ®))
{
*xb = reg;
*xb |= 0xb8;
*n_bytes = 1;
- return 1;
+ return true;
}
else if (lex_match ('['))
{
}
if (!lex_force_match (']'))
goto fail;
- return 1;
+ return true;
}
else if (lex_match ('('))
{
if (! lex_match (')'))
goto fail;
- return 1;
+ return true;
}
else if (lex_expression (exp))
{
buffer[3] = value;
}
}
- return 1;
+ return true;
}
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
lex_offset (long *val)
{
char *end = NULL;
char *p = input_line_pointer;
if (*p++ != '*')
- return 0;
+ return false;
if (*p != '+' && *p != '-')
- return 0;
+ return false;
bool negative = (*p == '-');
p++;
errno = 0;
- *val = strtol (p, &end, 0);
+ *val = s12z_strtol (p, &end);
if (errno == 0)
{
if (negative)
*val *= -1;
input_line_pointer = end;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
\f
if (*input_line_pointer != '\0')
{
as_bad (_("Garbage at end of instruction"));
- return 0;
+ return false;
}
char *f = s12z_new_insn (insn->page);
number_to_chars_bigendian (f++, insn->opc, 1);
- return 1;
+ return true;
+}
+
+
+static void
+emit_reloc (expressionS *exp, char *f, int size, enum bfd_reloc_code_real reloc)
+{
+ if (exp->X_op != O_absent && exp->X_op != O_constant)
+ {
+ fixS *fix = fix_new_exp (frag_now,
+ f - frag_now->fr_literal,
+ size,
+ exp,
+ FALSE,
+ reloc);
+ /* Some third party tools seem to use the lower bits
+ of this addend for flags. They don't get added
+ to the final location. The purpose of these flags
+ is not known. We simply set it to zero. */
+ fix->fx_addnumber = 0x00;
+ }
}
/* Emit the code for an OPR address mode operand */
{
int i;
number_to_chars_bigendian (f++, buffer[0], 1);
- if (exp->X_op != O_absent && exp->X_op != O_constant)
- {
- fix_new_exp (frag_now,
- f - frag_now->fr_literal,
- 3,
- exp,
- FALSE,
- BFD_RELOC_24);
- }
+
+ emit_reloc (exp, f, 3, BFD_RELOC_S12Z_OPR);
+
for (i = 1; i < n_bytes; ++i)
number_to_chars_bigendian (f++, buffer[i], 1);
return f + 3;
}
-static int
+static bfd_boolean
opr (const struct instruction *insn)
{
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (lex_opr (buffer, &n_bytes, &exp))
+ if (lex_opr (buffer, &n_bytes, &exp, false))
{
/* Large constant direct values are more efficiently encoded as ext24 mode.
Otherwise a decision has to be deferred to a relax. */
emit_opr (f, buffer, n_bytes, &exp);
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Parse a 15 bit offset, as an expression.
LONG_DISPLACEMENT will be set to true if the offset is wider than 7 bits.
*/
-static int
+static bfd_boolean
lex_15_bit_offset (bool *long_displacement, expressionS *exp)
{
char *ilp = input_line_pointer;
/* If a symbol was parsed we don't know the displacement.
We have to assume it is long, and relax it later if possible. */
*long_displacement = true;
- return 1;
+ return true;
}
}
else
if (val > 0x3FFF || val < -0x4000)
{
as_fatal (_("Offset is outside of 15 bit range"));
- return 0;
+ return false;
}
*long_displacement = (val > 63 || val < -64);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
static void
}
}
-static int
+static bfd_boolean
rel (const struct instruction *insn)
{
bool long_displacement;
expressionS exp;
if (! lex_15_bit_offset (&long_displacement, &exp))
- return 0;
+ return false;
char *f = s12z_new_insn (long_displacement ? 3 : 2);
number_to_chars_bigendian (f++, insn->opc, 1);
emit_15_bit_offset (f, 3, &exp);
- return 1;
+ return true;
}
-static int
+static bfd_boolean
reg_inh (const struct instruction *insn)
{
int reg;
number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
number_to_chars_bigendian (f++, insn->opc + reg, 1);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Special case for CLR X and CLR Y */
-static int
+static bfd_boolean
clr_xy (const struct instruction *insn ATTRIBUTE_UNUSED)
{
int reg;
{
char *f = s12z_new_insn (1);
number_to_chars_bigendian (f, 0x9a + reg - REG_X, 1);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Some instructions have a suffix like ".l", ".b", ".w" etc
which indicates the size of the operands. */
-static int
+static bfd_boolean
size_from_suffix (const struct instruction *insn, int idx)
{
const char *dot = strchr (insn->name, '.');
return size;
}
-static int
+static bfd_boolean
mul_reg_reg_reg (const struct instruction *insn)
{
char *ilp = input_line_pointer;
number_to_chars_bigendian (f++, mb, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
mul_reg_reg_imm (const struct instruction *insn)
{
char *ilp = input_line_pointer;
goto fail;
long imm;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
number_to_chars_bigendian (f++, mb, 1);
number_to_chars_bigendian (f++, imm, size);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
mul_reg_reg_opr (const struct instruction *insn)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, true))
goto fail;
int size = size_from_suffix (insn, 0);
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
mul_reg_opr_opr (const struct instruction *insn)
{
char *ilp = input_line_pointer;
uint8_t buffer1[4];
int n_bytes1;
expressionS exp1;
- if (!lex_opr (buffer1, &n_bytes1, &exp1))
+ if (!lex_opr (buffer1, &n_bytes1, &exp1, false))
goto fail;
if (!lex_match (','))
uint8_t buffer2[4];
int n_bytes2;
expressionS exp2;
- if (!lex_opr (buffer2, &n_bytes2, &exp2))
+ if (!lex_opr (buffer2, &n_bytes2, &exp2, false))
goto fail;
int size1 = size_from_suffix (insn, 0);
f = emit_opr (f, buffer1, n_bytes1, &exp1);
f = emit_opr (f, buffer2, n_bytes2, &exp2);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
{
int reg;
if (!lex_reg_name (grp, ®))
- return 0;
+ return false;
*reg_bits |= 0x1u << reg;
lex_reg_list (grp, reg_bits);
}
/* Empty list */
- return 1;
+ return true;
}
-static int
+static bfd_boolean
psh_pull (const struct instruction *insn)
{
uint8_t pb =
char *f = s12z_new_insn (2);
number_to_chars_bigendian (f++, insn->opc, 1);
number_to_chars_bigendian (f++, pb, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
tfr (const struct instruction *insn)
{
int reg1;
if (!lex_reg_name (~0, ®2))
goto fail;
- if ((0 == strcasecmp ("sex", insn->name))
- || (0 == strcasecmp ("zex", insn->name)))
- {
- if (registers[reg1].bytes >= registers[reg2].bytes)
- {
- as_bad (_("Source register for %s must be smaller that the destination register"),
- insn->name);
- goto fail;
- }
- }
+ if ( ((0 == strcasecmp ("sex", insn->name))
+ || (0 == strcasecmp ("zex", insn->name)))
+ && (registers[reg2].bytes <= registers[reg1].bytes))
+ as_warn (_("Source register for %s is no larger than the destination register"),
+ insn->name);
+ else if (reg1 == reg2)
+ as_warn (_("The destination and source registers are identical"));
char *f = s12z_new_insn (1 + insn->page);
if (insn->page == 2)
number_to_chars_bigendian (f++, insn->opc, 1);
number_to_chars_bigendian (f++, reg1 << 4 | reg2, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
imm8 (const struct instruction *insn)
{
long imm;
- if (! lex_imm (&imm))
- return 0;
+ if (! lex_imm (&imm, NULL))
+ return false;
if (imm > 127 || imm < -128)
{
as_bad (_("Immediate value %ld is out of range for instruction %s"),
number_to_chars_bigendian (f++, insn->opc, 1);
number_to_chars_bigendian (f++, imm, 1);
- return 1;
+ return true;
}
-static int
+static bfd_boolean
reg_imm (const struct instruction *insn, int allowed_reg)
{
char *ilp = input_line_pointer;
if (!lex_force_match (','))
goto fail;
long imm;
- if (! lex_imm (&imm))
+ if (! lex_imm (&imm, NULL))
goto fail;
short size = registers[reg].bytes;
number_to_chars_bigendian (f++, insn->opc + reg, 1);
number_to_chars_bigendian (f++, imm, size);
- return 1;
+ return true;
}
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
regd_imm (const struct instruction *insn)
{
return reg_imm (insn, REG_BIT_Dn);
}
-static int
+static bfd_boolean
regdxy_imm (const struct instruction *insn)
{
return reg_imm (insn, REG_BIT_Dn | REG_BIT_XY);
}
-static int
+static bfd_boolean
regs_imm (const struct instruction *insn)
{
return reg_imm (insn, 0x1U << REG_S);
}
-static int
+static bfd_boolean
trap_imm (const struct instruction *insn ATTRIBUTE_UNUSED)
{
long imm = -1;
- if (! lex_imm (&imm))
+ if (! lex_imm (&imm, NULL))
goto fail;
if (imm < 0x92 || imm > 0xFF ||
(imm >= 0xB0 && imm <= 0xB7))
{
as_bad (_("trap value %ld is not valid"), imm);
- return 0;
+ return false;
}
else
{
char *f = s12z_new_insn (2);
number_to_chars_bigendian (f++, PAGE2_PREBYTE, 1);
number_to_chars_bigendian (f++, imm & 0xFF, 1);
- return 1;
+ return true;
}
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
- return 0;
+ return false;
}
/* Special one byte instruction CMP X, Y */
-static int
+static bfd_boolean
regx_regy (const struct instruction *insn)
{
int reg;
{
char *f = s12z_new_insn (1);
number_to_chars_bigendian (f, insn->opc, 1);
- return 1;
+ return true;
}
}
}
- return 0;
+ return false;
}
/* Special one byte instruction SUB D6, X, Y */
-static int
+static bfd_boolean
regd6_regx_regy (const struct instruction *insn)
{
char *ilp = input_line_pointer;
char *f = s12z_new_insn (1);
number_to_chars_bigendian (f, insn->opc, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
/* Special one byte instruction SUB D6, Y, X */
-static int
+static bfd_boolean
regd6_regy_regx (const struct instruction *insn)
{
char *ilp = input_line_pointer;
char *f = s12z_new_insn (1);
number_to_chars_bigendian (f, insn->opc, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
-reg_opr (const struct instruction *insn, int allowed_regs)
+static bfd_boolean
+reg_opr (const struct instruction *insn, int allowed_regs,
+ bool immediate_ok)
{
char *ilp = input_line_pointer;
int reg;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (lex_opr (buffer, &n_bytes, &exp))
+ if (lex_opr (buffer, &n_bytes, &exp, immediate_ok))
{
/* Large constant direct values are more efficiently encoded as ext24 mode.
Otherwise a decision has to be deferred to a relax. */
emit_opr (f, buffer, n_bytes, &exp);
}
- return 1;
+ return true;
}
}
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
-regdxy_opr (const struct instruction *insn)
+static bfd_boolean
+regdxy_opr_dest (const struct instruction *insn)
{
- return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY);
+ return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY, false);
}
-static int
+static bfd_boolean
+regdxy_opr_src (const struct instruction *insn)
+{
+ return reg_opr (insn, REG_BIT_Dn | REG_BIT_XY, true);
+}
+
+
+static bfd_boolean
regd_opr (const struct instruction *insn)
{
- return reg_opr (insn, REG_BIT_Dn);
+ return reg_opr (insn, REG_BIT_Dn, true);
}
-static int
-regs_opr (const struct instruction *insn)
+/* OP0: S; OP1: destination OPR */
+static bfd_boolean
+regs_opr_dest (const struct instruction *insn)
{
- return reg_opr (insn, 0x1U << REG_S);
+ return reg_opr (insn, 0x1U << REG_S, false);
}
-static int
+/* OP0: S; OP1: source OPR */
+static bfd_boolean
+regs_opr_src (const struct instruction *insn)
+{
+ return reg_opr (insn, 0x1U << REG_S, true);
+}
+
+static bfd_boolean
imm_opr (const struct instruction *insn)
{
char *ilp = input_line_pointer;
long imm;
- if (!lex_imm (&imm))
+ expressionS exp0;
+ int size = size_from_suffix (insn, 0);
+ exp0.X_op = O_absent;
+
+ /* Note: The ternary expression below means that "MOV.x #symbol,
+ mem-expr" is accepted when x is a member of {'w', 'p', 'l'} but
+ not when it is 'b'.
+ The Freescale assembler accepts "MOV.b #symbol, mem-expr" but
+ produces obviously incorrect code. Since such an instruction
+ would require an 8-bit reloc (which we don't have) and some
+ non-optimal kludges in the OPR encoding, it seems sensible that
+ such instructions should be rejected. */
+ if (!lex_imm (&imm, size > 1 ? &exp0 : NULL))
goto fail;
if (!lex_match (','))
uint8_t buffer[4];
int n_bytes;
- expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ expressionS exp1;
+ if (!lex_opr (buffer, &n_bytes, &exp1, false))
goto fail;
- int size = size_from_suffix (insn, 0);
char *f = s12z_new_insn (1 + n_bytes + size);
number_to_chars_bigendian (f++, insn->opc, 1);
+ emit_reloc (&exp0, f, size, size == 4 ? BFD_RELOC_32 : BFD_RELOC_S12Z_OPR);
+
int i;
for (i = 0; i < size; ++i)
number_to_chars_bigendian (f++, imm >> (CHAR_BIT * (size - i - 1)), 1);
- emit_opr (f, buffer, n_bytes, &exp);
+ emit_opr (f, buffer, n_bytes, &exp1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
opr_opr (const struct instruction *insn)
{
char *ilp = input_line_pointer;
uint8_t buffer1[4];
int n_bytes1;
expressionS exp1;
- if (!lex_opr (buffer1, &n_bytes1, &exp1))
+ if (!lex_opr (buffer1, &n_bytes1, &exp1, false))
goto fail;
uint8_t buffer2[4];
int n_bytes2;
expressionS exp2;
- if (!lex_opr (buffer2, &n_bytes2, &exp2))
+ if (!lex_opr (buffer2, &n_bytes2, &exp2, false))
goto fail;
char *f = s12z_new_insn (1 + n_bytes1 + n_bytes2);
f = emit_opr (f, buffer1, n_bytes1, &exp1);
f = emit_opr (f, buffer2, n_bytes2, &exp2);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
reg67sxy_opr (const struct instruction *insn)
{
int reg;
if (!lex_reg_name (REG_BIT_XYS | (0x1U << REG_D6) | (0x1U << REG_D7), ®))
- return 0;
+ return false;
if (!lex_match (','))
- return 0;
+ return false;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
- return 0;
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
+ return false;
char *f = s12z_new_insn (1 + n_bytes);
number_to_chars_bigendian (f++, insn->opc + reg - REG_D6, 1);
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
}
-static int
+static bfd_boolean
rotate (const struct instruction *insn, short dir)
{
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (lex_opr (buffer, &n_bytes, &exp))
+ if (lex_opr (buffer, &n_bytes, &exp, false))
{
char *f = s12z_new_insn (n_bytes + 2);
number_to_chars_bigendian (f++, insn->opc, 1);
number_to_chars_bigendian (f++, sb, 1);
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-static int
+static bfd_boolean
rol (const struct instruction *insn)
{
return rotate (insn, 1);
}
-static int
+static bfd_boolean
ror (const struct instruction *insn)
{
return rotate (insn, 0);
left = 1; right = 0;
logical = 0; arithmetic = 1;
*/
-static int
+static bfd_boolean
lex_shift_reg_imm1 (const struct instruction *insn, short type, short dir)
{
/*
goto fail;
long imm = -1;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
if (imm != 1 && imm != 2)
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
gas_assert (n_bytes == 1);
number_to_chars_bigendian (f++, sb, 1);
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
/* Shift instruction with a register operand.
left = 1; right = 0;
logical = 0; arithmetic = 1; */
-static int
+static bfd_boolean
lex_shift_reg (const struct instruction *insn, short type, short dir)
{
int Dd, Ds, Dn;
xb |= Dn;
number_to_chars_bigendian (f++, xb, 1);
- return 1;
+ return true;
}
- else if (lex_imm (&imm))
+ else if (lex_imm (&imm, NULL))
{
if (imm < 0 || imm > 31)
{
number_to_chars_bigendian (f++, xb, 1);
}
- return 1;
+ return true;
}
fail:
fail_line_pointer = input_line_pointer;
- return 0;
+ return false;
}
static void
}
/* Shift instruction with a OPR operand */
-static int
+static bfd_boolean
shift_two_operand (const struct instruction *insn)
{
uint8_t sb = 0x34;
uint8_t buffer[4];
int n_opr_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ if (!lex_opr (buffer, &n_opr_bytes, &exp, false))
goto fail;
if (!lex_match (','))
goto fail;
long imm = -1;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
if (imm != 1 && imm != 2)
number_to_chars_bigendian (f++, sb, 1);
emit_opr (f, buffer, n_opr_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
/* Shift instruction with a OPR operand */
-static int
+static bfd_boolean
shift_opr_imm (const struct instruction *insn)
{
char *ilp = input_line_pointer;
int n_opr_bytes1;
expressionS exp1;
- if (!lex_opr (buffer1, &n_opr_bytes1, &exp1))
+ if (!lex_opr (buffer1, &n_opr_bytes1, &exp1, false))
goto fail;
n_bytes += n_opr_bytes1;
expressionS exp2;
long imm;
bool immediate = false;
- if (lex_imm (&imm))
+ if (lex_imm (&imm, NULL))
{
immediate = true;
}
- else if (!lex_opr (buffer2, &n_opr_bytes2, &exp2))
+ else if (!lex_opr (buffer2, &n_opr_bytes2, &exp2, false))
goto fail;
uint8_t sb = 0x20;
f = emit_opr (f, buffer2, n_opr_bytes2, &exp2);
}
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
/* Shift instruction with a register operand */
-static int
+static bfd_boolean
shift_reg (const struct instruction *insn)
{
short dir = -1;
impute_shift_dir_and_type (insn, &type, &dir);
if (lex_shift_reg_imm1 (insn, type, dir))
- return 1;
+ return true;
return lex_shift_reg (insn, type, dir);
}
-static int
+static bfd_boolean
bm_regd_imm (const struct instruction *insn)
{
char *ilp = input_line_pointer;
goto fail;
long imm;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
number_to_chars_bigendian (f++, insn->opc, 1);
number_to_chars_bigendian (f++, bm, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bm_opr_reg (const struct instruction *insn)
{
char *ilp = input_line_pointer;
int n_opr_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ if (!lex_opr (buffer, &n_opr_bytes, &exp, false))
goto fail;
if (!lex_match (','))
emit_opr (f, buffer, n_opr_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bm_opr_imm (const struct instruction *insn)
{
char *ilp = input_line_pointer;
int n_opr_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_opr_bytes, &exp))
+ if (!lex_opr (buffer, &n_opr_bytes, &exp, false))
goto fail;
if (!lex_match (','))
long imm;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
int size = size_from_suffix (insn, 0);
number_to_chars_bigendian (f++, bm, 1);
emit_opr (f, buffer, n_opr_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bm_regd_reg (const struct instruction *insn)
{
char *ilp = input_line_pointer;
number_to_chars_bigendian (f++, bm, 1);
number_to_chars_bigendian (f++, xb, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
\f
-static int
+static bfd_boolean
bf_reg_opr_imm (const struct instruction *insn, short ie)
{
char *ilp = input_line_pointer;
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
goto fail;
long width;
- if (!lex_imm (&width))
+ if (!lex_imm (&width, NULL))
goto fail;
if (width < 0 || width > 31)
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bf_opr_reg_imm (const struct instruction *insn, short ie)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
goto fail;
long width;
- if (!lex_imm (&width))
+ if (!lex_imm (&width, NULL))
goto fail;
if (width < 0 || width > 31)
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bf_reg_reg_imm (const struct instruction *insn, short ie)
{
char *ilp = input_line_pointer;
goto fail;
long width;
- if (!lex_imm (&width))
+ if (!lex_imm (&width, NULL))
goto fail;
if (width < 0 || width > 31)
number_to_chars_bigendian (f++, bb, 1);
number_to_chars_bigendian (f++, i1, 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bf_reg_reg_reg (const struct instruction *insn ATTRIBUTE_UNUSED, short ie)
{
char *ilp = input_line_pointer;
number_to_chars_bigendian (f++, 0x08 | Dd, 1);
number_to_chars_bigendian (f++, bb , 1);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bf_opr_reg_reg (const struct instruction *insn, short ie)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bf_reg_opr_reg (const struct instruction *insn, short ie)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
emit_opr (f, buffer, n_bytes, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
bfe_reg_reg_reg (const struct instruction *insn)
{
return bf_reg_reg_reg (insn, 0);
}
-static int
+static bfd_boolean
bfi_reg_reg_reg (const struct instruction *insn)
{
return bf_reg_reg_reg (insn, 1);
}
-static int
+static bfd_boolean
bfe_reg_reg_imm (const struct instruction *insn)
{
return bf_reg_reg_imm (insn, 0);
}
-static int
+static bfd_boolean
bfi_reg_reg_imm (const struct instruction *insn)
{
return bf_reg_reg_imm (insn, 1);
}
-static int
+static bfd_boolean
bfe_reg_opr_reg (const struct instruction *insn)
{
return bf_reg_opr_reg (insn, 0);
}
-static int
+static bfd_boolean
bfi_reg_opr_reg (const struct instruction *insn)
{
return bf_reg_opr_reg (insn, 1);
}
-static int
+static bfd_boolean
bfe_opr_reg_reg (const struct instruction *insn)
{
return bf_opr_reg_reg (insn, 0);
}
-static int
+static bfd_boolean
bfi_opr_reg_reg (const struct instruction *insn)
{
return bf_opr_reg_reg (insn, 1);
}
-static int
+static bfd_boolean
bfe_reg_opr_imm (const struct instruction *insn)
{
return bf_reg_opr_imm (insn, 0);
}
-static int
+static bfd_boolean
bfi_reg_opr_imm (const struct instruction *insn)
{
return bf_reg_opr_imm (insn, 1);
}
-static int
+static bfd_boolean
bfe_opr_reg_imm (const struct instruction *insn)
{
return bf_opr_reg_imm (insn, 0);
}
-static int
+static bfd_boolean
bfi_opr_reg_imm (const struct instruction *insn)
{
return bf_opr_reg_imm (insn, 1);
\f
-static int
+static bfd_boolean
tb_reg_rel (const struct instruction *insn)
{
char *ilp = input_line_pointer;
emit_15_bit_offset (f, 4, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
tb_opr_rel (const struct instruction *insn)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
emit_15_bit_offset (f, n_bytes + 4, &exp2);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
\f
-static int
+static bfd_boolean
test_br_reg_reg_rel (const struct instruction *insn)
{
char *ilp = input_line_pointer;
emit_15_bit_offset (f, 5, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
test_br_opr_reg_rel (const struct instruction *insn)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
emit_15_bit_offset (f, n, &exp2);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
test_br_opr_imm_rel (const struct instruction *insn)
{
char *ilp = input_line_pointer;
uint8_t buffer[4];
int n_bytes;
expressionS exp;
- if (!lex_opr (buffer, &n_bytes, &exp))
+ if (!lex_opr (buffer, &n_bytes, &exp, false))
goto fail;
if (!lex_match (','))
goto fail;
long imm;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
if (imm < 0 || imm > 31)
emit_15_bit_offset (f, n_bytes + 4, &exp2);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
-static int
+static bfd_boolean
test_br_reg_imm_rel (const struct instruction *insn)
{
char *ilp = input_line_pointer;
goto fail;
long imm;
- if (!lex_imm (&imm))
+ if (!lex_imm (&imm, NULL))
goto fail;
if (imm < 0 || imm > 31)
emit_15_bit_offset (f, 4, &exp);
- return 1;
+ return true;
fail:
fail_line_pointer = input_line_pointer;
input_line_pointer = ilp;
- return 0;
+ return false;
}
{"tfr", 1, 0x9e, tfr, 0},
{"zex", 1, 0x9e, tfr, 0},
- {"ld", 1, 0xa0, regdxy_opr, 0xb0},
+ {"ld", 1, 0xa0, regdxy_opr_src, 0xb0},
{"jmp", 1, 0xaa, opr, 0xba},
{"jsr", 1, 0xab, opr, 0xbb},
{"exg", 1, 0xae, tfr, 0},
{"sex", 1, 0xae, tfr, 0},
- {"st", 1, 0xc0, regdxy_opr, 0xd0},
+ {"st", 1, 0xc0, regdxy_opr_dest, 0xd0},
{"andcc", 1, 0xce, imm8, 0},
{"orcc", 1, 0xde, imm8, 0},
{"btgl.l", 1, 0xee, bm_opr_reg, 0},
{"cmp", 1, 0xe0, regdxy_imm, 0},
- {"cmp", 1, 0xf0, regdxy_opr, 0},
+ {"cmp", 1, 0xf0, regdxy_opr_src, 0},
{"cmp", 1, 0xfc, regx_regy, 0},
{"sub", 1, 0xfd, regd6_regx_regy, 0},
/* Page 2 */
/* The -10 below is a kludge. The opcode is in fact 0x00 */
- {"ld", 2, -10, regs_opr, 0},
+ {"ld", 2, -10, regs_opr_src, 0},
/* The -9 below is a kludge. The opcode is in fact 0x01 */
- {"st", 2, -9, regs_opr, 0},
+ {"st", 2, -9, regs_opr_dest, 0},
/* The -8 below is a kludge. The opcode is in fact 0x02 */
- {"cmp", 2, -8, regs_opr, 0},
+ {"cmp", 2, -8, regs_opr_src, 0},
/* The -7 below is a kludge. The opcode is in fact 0x03 */
{"ld", 2, -7, regs_imm, 0},
s12z_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS *fragP ATTRIBUTE_UNUSED,
long stretch ATTRIBUTE_UNUSED)
{
- return 0;
+ return false;
}
void
int
md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, asection *segment ATTRIBUTE_UNUSED)
{
- return 0;
+ return false;
}
we need to make sure that the linker relaxation is done
correctly, so in some cases we force the original symbol to be
used. */
-int
+bfd_boolean
tc_s12z_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
{
- return 1;
+ return true;
}
void
case BFD_RELOC_24:
bfd_putb24 ((bfd_vma) value, (unsigned char *) where);
break;
+ case BFD_RELOC_S12Z_OPR:
+ {
+ switch (fixP->fx_size)
+ {
+ case 3:
+ bfd_putb24 ((bfd_vma) value, (unsigned char *) where);
+ break;
+ case 2:
+ bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
+ break;
+ default:
+ abort ();
+ }
+ }
+ break;
case BFD_RELOC_32:
bfd_putb32 ((bfd_vma) value, (unsigned char *) where);
break;
case BFD_RELOC_16_PCREL:
- if (value < -0x8000 || value > 0x7FFF)
+ if (value < -0x4000 || value > 0x3FFF)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("Value out of 16-bit range."));