#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
+#include "libiberty.h"
struct avr_opcodes_s
{
- char *name;
- char *constraints;
- int insn_size; /* In words. */
- int isa;
- unsigned int bin_opcode;
+ char * name;
+ char * constraints;
+ int insn_size; /* In words. */
+ int isa;
+ unsigned int bin_opcode;
};
#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
};
/* Current MCU type. */
-static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_2xxx,bfd_mach_avr2};
-static struct mcu_type_s *avr_mcu = &default_mcu;
+static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_2xxx,bfd_mach_avr2};
+static struct mcu_type_s * avr_mcu = & default_mcu;
/* AVR target-specific switches. */
struct avr_opt_s
{
- int all_opcodes; /* -mall-opcodes: accept all known AVR opcodes */
- int no_skip_bug; /* -mno-skip-bug: no warnings for skipping 2-word insns */
- int no_wrap; /* -mno-wrap: reject rjmp/rcall with 8K wrap-around */
+ int all_opcodes; /* -mall-opcodes: accept all known AVR opcodes. */
+ int no_skip_bug; /* -mno-skip-bug: no warnings for skipping 2-word insns. */
+ int no_wrap; /* -mno-wrap: reject rjmp/rcall with 8K wrap-around. */
};
static struct avr_opt_s avr_opt = { 0, 0, 0 };
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
-static void avr_set_arch (int dummy);
+
+static void avr_set_arch (int);
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
#define LDI_IMMEDIATE(x) (((x) & 0xf) | (((x) << 4) & 0xf00))
-static void show_mcu_list PARAMS ((FILE *));
-static char *skip_space PARAMS ((char *));
-static char *extract_word PARAMS ((char *, char *, int));
-static unsigned int avr_operand PARAMS ((struct avr_opcodes_s *,
- int, char *, char **));
-static unsigned int avr_operands PARAMS ((struct avr_opcodes_s *, char **));
-static unsigned int avr_get_constant PARAMS ((char *, int));
-static char *parse_exp PARAMS ((char *, expressionS *));
-static bfd_reloc_code_real_type avr_ldi_expression PARAMS ((expressionS *));
-
-#define EXP_MOD_NAME(i) exp_mod[i].name
-#define EXP_MOD_RELOC(i) exp_mod[i].reloc
-#define EXP_MOD_NEG_RELOC(i) exp_mod[i].neg_reloc
-#define HAVE_PM_P(i) exp_mod[i].have_pm
+#define EXP_MOD_NAME(i) exp_mod[i].name
+#define EXP_MOD_RELOC(i) exp_mod[i].reloc
+#define EXP_MOD_NEG_RELOC(i) exp_mod[i].neg_reloc
+#define HAVE_PM_P(i) exp_mod[i].have_pm
struct exp_mod_s
{
- char *name;
- bfd_reloc_code_real_type reloc;
- bfd_reloc_code_real_type neg_reloc;
- int have_pm;
+ char * name;
+ bfd_reloc_code_real_type reloc;
+ bfd_reloc_code_real_type neg_reloc;
+ int have_pm;
};
static struct exp_mod_s exp_mod[] =
static struct hash_control *avr_mod_hash;
#define OPTION_MMCU 'm'
-#define OPTION_ALL_OPCODES (OPTION_MD_BASE + 1)
-#define OPTION_NO_SKIP_BUG (OPTION_MD_BASE + 2)
-#define OPTION_NO_WRAP (OPTION_MD_BASE + 3)
+enum options
+{
+ OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
+ OPTION_NO_SKIP_BUG,
+ OPTION_NO_WRAP
+};
struct option md_longopts[] =
{
/* Display nicely formatted list of known MCU names. */
static void
-show_mcu_list (stream)
- FILE *stream;
+show_mcu_list (FILE *stream)
{
int i, x;
}
static inline char *
-skip_space (s)
- char *s;
+skip_space (char *s)
{
while (*s == ' ' || *s == '\t')
++s;
}
int
-md_estimate_size_before_relax (fragp, seg)
- fragS *fragp ATTRIBUTE_UNUSED;
- asection *seg ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
+ asection *seg ATTRIBUTE_UNUSED)
{
abort ();
return 0;
}
void
-md_show_usage (stream)
- FILE *stream;
+md_show_usage (FILE *stream)
{
fprintf (stream,
_("AVR options:\n"
}
static void
-avr_set_arch (dummy)
- int dummy ATTRIBUTE_UNUSED;
+avr_set_arch (int dummy ATTRIBUTE_UNUSED)
{
- char *str;
+ char str[20];
- str = (char *) alloca (20);
input_line_pointer = extract_word (input_line_pointer, str, 20);
md_parse_option (OPTION_MMCU, str);
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
}
int
-md_parse_option (c, arg)
- int c;
- char *arg;
+md_parse_option (int c, char *arg)
{
switch (c)
{
}
symbolS *
-md_undefined_symbol (name)
- char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
- return 0;
+ return NULL;
}
/* Turn a string in input_line_pointer into a floating point constant
returned, or NULL on OK. */
char *
-md_atof (type, litP, sizeP)
- int type;
- char *litP;
- int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
{
int prec;
LITTLENUM_TYPE words[4];
}
void
-md_convert_frag (abfd, sec, fragP)
- bfd *abfd ATTRIBUTE_UNUSED;
- asection *sec ATTRIBUTE_UNUSED;
- fragS *fragP ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec ATTRIBUTE_UNUSED,
+ fragS *fragP ATTRIBUTE_UNUSED)
{
abort ();
}
void
-md_begin ()
+md_begin (void)
{
unsigned int i;
struct avr_opcodes_s *opcode;
+
avr_hash = hash_new ();
/* Insert unique names into hash table. This hash table then provides a
avr_mod_hash = hash_new ();
- for (i = 0; i < sizeof (exp_mod) / sizeof (exp_mod[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE (exp_mod); ++i)
hash_insert (avr_mod_hash, EXP_MOD_NAME (i), (void *) (i + 10));
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
If result greater than MAX then error. */
static unsigned int
-avr_get_constant (str, max)
- char *str;
- int max;
+avr_get_constant (char *str, int max)
{
expressionS ex;
+
str = skip_space (str);
input_line_pointer = str;
- expression (&ex);
+ expression (& ex);
if (ex.X_op != O_constant)
as_bad (_("constant value required"));
return ex.X_add_number;
}
-/* Parse instruction operands.
- Return binary opcode. */
+/* Parse for ldd/std offset. */
-static unsigned int
-avr_operands (opcode, line)
- struct avr_opcodes_s *opcode;
- char **line;
+static void
+avr_offset_expression (expressionS *exp)
{
- char *op = opcode->constraints;
- unsigned int bin = opcode->bin_opcode;
- char *frag = frag_more (opcode->insn_size * 2);
- char *str = *line;
- int where = frag - frag_now->fr_literal;
- static unsigned int prev = 0; /* Previous opcode. */
+ char *str = input_line_pointer;
+ char *tmp;
+ char op[8];
- /* Opcode have operands. */
- if (*op)
+ tmp = str;
+ str = extract_word (str, op, sizeof (op));
+
+ input_line_pointer = tmp;
+ expression (exp);
+
+ /* Warn about expressions that fail to use lo8 (). */
+ if (exp->X_op == O_constant)
{
- unsigned int reg1 = 0;
- unsigned int reg2 = 0;
- int reg1_present = 0;
- int reg2_present = 0;
+ int x = exp->X_add_number;
+
+ if (x < -255 || x > 255)
+ as_warn (_("constant out of 8-bit range: %d"), x);
+ }
+}
- /* Parse first operand. */
- if (REGISTER_P (*op))
- reg1_present = 1;
- reg1 = avr_operand (opcode, where, op, &str);
- ++op;
+/* Parse ordinary expression. */
- /* Parse second operand. */
- if (*op)
- {
- if (*op == ',')
- ++op;
+static char *
+parse_exp (char *s, expressionS *op)
+{
+ input_line_pointer = s;
+ expression (op);
+ if (op->X_op == O_absent)
+ as_bad (_("missing operand"));
+ return input_line_pointer;
+}
- if (*op == '=')
- {
- reg2 = reg1;
- reg2_present = 1;
- }
- else
- {
- if (REGISTER_P (*op))
- reg2_present = 1;
+/* Parse special expressions (needed for LDI command):
+ xx8 (address)
+ xx8 (-address)
+ pm_xx8 (address)
+ pm_xx8 (-address)
+ where xx is: hh, hi, lo. */
- str = skip_space (str);
- if (*str++ != ',')
- as_bad (_("`,' required"));
- str = skip_space (str);
+static bfd_reloc_code_real_type
+avr_ldi_expression (expressionS *exp)
+{
+ char *str = input_line_pointer;
+ char *tmp;
+ char op[8];
+ int mod;
+ tmp = str;
- reg2 = avr_operand (opcode, where, op, &str);
+ str = extract_word (str, op, sizeof (op));
- }
+ if (op[0])
+ {
+ mod = (int) hash_find (avr_mod_hash, op);
- if (reg1_present && reg2_present)
- reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200);
- else if (reg2_present)
- reg2 <<= 4;
- }
- if (reg1_present)
- reg1 <<= 4;
- bin |= reg1 | reg2;
- }
+ if (mod)
+ {
+ int closes = 0;
- /* Detect undefined combinations (like ld r31,Z+). */
- if (!avr_opt.all_opcodes && AVR_UNDEF_P (bin))
- as_warn (_("undefined combination of operands"));
+ mod -= 10;
+ str = skip_space (str);
- if (opcode->insn_size == 2)
- {
- /* Warn if the previous opcode was cpse/sbic/sbis/sbrc/sbrs
- (AVR core bug, fixed in the newer devices). */
+ if (*str == '(')
+ {
+ int neg_p = 0;
- if (!(avr_opt.no_skip_bug ||
- (avr_mcu->isa & (AVR_ISA_MUL | AVR_ISA_MOVW)))
- && AVR_SKIP_P (prev))
- as_warn (_("skipping two-word instruction"));
+ ++str;
- bfd_putl32 ((bfd_vma) bin, frag);
- }
- else
- bfd_putl16 ((bfd_vma) bin, frag);
+ if (strncmp ("pm(", str, 3) == 0
+ || strncmp ("-(pm(", str, 5) == 0)
+ {
+ if (HAVE_PM_P (mod))
+ {
+ ++mod;
+ ++closes;
+ }
+ else
+ as_bad (_("illegal expression"));
- prev = bin;
- *line = str;
- return bin;
-}
+ if (*str == '-')
+ {
+ neg_p = 1;
+ ++closes;
+ str += 5;
+ }
+ else
+ str += 3;
+ }
-/* Parse for ldd/std offset */
+ if (*str == '-' && *(str + 1) == '(')
+ {
+ neg_p ^= 1;
+ ++closes;
+ str += 2;
+ }
-static void
-avr_offset_expression (expressionS *exp)
-{
- char *str = input_line_pointer;
- char *tmp;
- char op[8];
+ input_line_pointer = str;
+ expression (exp);
- tmp = str;
- str = extract_word (str, op, sizeof (op));
+ do
+ {
+ if (*input_line_pointer != ')')
+ {
+ as_bad (_("`)' required"));
+ break;
+ }
+ input_line_pointer++;
+ }
+ while (closes--);
+
+ return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod);
+ }
+ }
+ }
input_line_pointer = tmp;
expression (exp);
if (exp->X_op == O_constant)
{
int x = exp->X_add_number;
-
+
if (x < -255 || x > 255)
as_warn (_("constant out of 8-bit range: %d"), x);
}
+
+ return BFD_RELOC_AVR_LDI;
}
/* Parse one instruction operand.
Return operand bitmask. Also fixups can be generated. */
static unsigned int
-avr_operand (opcode, where, op, line)
- struct avr_opcodes_s *opcode;
- int where;
- char *op;
- char **line;
+avr_operand (struct avr_opcodes_s *opcode,
+ int where,
+ char *op,
+ char **line)
{
expressionS op_expr;
unsigned int op_mask = 0;
return op_mask;
}
+/* Parse instruction operands.
+ Return binary opcode. */
+
+static unsigned int
+avr_operands (struct avr_opcodes_s *opcode, char **line)
+{
+ char *op = opcode->constraints;
+ unsigned int bin = opcode->bin_opcode;
+ char *frag = frag_more (opcode->insn_size * 2);
+ char *str = *line;
+ int where = frag - frag_now->fr_literal;
+ static unsigned int prev = 0; /* Previous opcode. */
+
+ /* Opcode have operands. */
+ if (*op)
+ {
+ unsigned int reg1 = 0;
+ unsigned int reg2 = 0;
+ int reg1_present = 0;
+ int reg2_present = 0;
+
+ /* Parse first operand. */
+ if (REGISTER_P (*op))
+ reg1_present = 1;
+ reg1 = avr_operand (opcode, where, op, &str);
+ ++op;
+
+ /* Parse second operand. */
+ if (*op)
+ {
+ if (*op == ',')
+ ++op;
+
+ if (*op == '=')
+ {
+ reg2 = reg1;
+ reg2_present = 1;
+ }
+ else
+ {
+ if (REGISTER_P (*op))
+ reg2_present = 1;
+
+ str = skip_space (str);
+ if (*str++ != ',')
+ as_bad (_("`,' required"));
+ str = skip_space (str);
+
+ reg2 = avr_operand (opcode, where, op, &str);
+ }
+
+ if (reg1_present && reg2_present)
+ reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200);
+ else if (reg2_present)
+ reg2 <<= 4;
+ }
+ if (reg1_present)
+ reg1 <<= 4;
+ bin |= reg1 | reg2;
+ }
+
+ /* Detect undefined combinations (like ld r31,Z+). */
+ if (!avr_opt.all_opcodes && AVR_UNDEF_P (bin))
+ as_warn (_("undefined combination of operands"));
+
+ if (opcode->insn_size == 2)
+ {
+ /* Warn if the previous opcode was cpse/sbic/sbis/sbrc/sbrs
+ (AVR core bug, fixed in the newer devices). */
+ if (!(avr_opt.no_skip_bug ||
+ (avr_mcu->isa & (AVR_ISA_MUL | AVR_ISA_MOVW)))
+ && AVR_SKIP_P (prev))
+ as_warn (_("skipping two-word instruction"));
+
+ bfd_putl32 ((bfd_vma) bin, frag);
+ }
+ else
+ bfd_putl16 ((bfd_vma) bin, frag);
+
+ prev = bin;
+ *line = str;
+ return bin;
+}
+
/* GAS will call this function for each section at the end of the assembly,
to permit the CPU backend to adjust the alignment of a section. */
valueT
-md_section_align (seg, addr)
- asection *seg;
- valueT addr;
+md_section_align (asection *seg, valueT addr)
{
int align = bfd_get_section_alignment (stdoutput, seg);
return ((addr + (1 << align) - 1) & (-1 << align));
macro would return the length of an instruction. */
long
-md_pcrel_from_section (fixp, sec)
- fixS *fixp;
- segT sec;
+md_pcrel_from_section (fixS *fixp, segT sec)
{
if (fixp->fx_addsy != (symbolS *) NULL
&& (!S_IS_DEFINED (fixp->fx_addsy)
value in the object file. */
void
-md_apply_fix (fixP, valP, seg)
- fixS *fixP;
- valueT * valP;
- segT seg;
+md_apply_fix (fixS *fixP, valueT * valP, segT seg)
{
unsigned char *where;
unsigned long insn;
then it is done here. */
arelent *
-tc_gen_reloc (seg, fixp)
- asection *seg ATTRIBUTE_UNUSED;
- fixS *fixp;
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED,
+ fixS *fixp)
{
arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
+ reloc = xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
}
void
-md_assemble (str)
- char *str;
+md_assemble (char *str)
{
struct avr_opcodes_s *opcode;
char op[11];
but that is wrong. Our caller assumes we don't change it. */
{
char *t = input_line_pointer;
+
avr_operands (opcode, &str);
if (*skip_space (str))
as_bad (_("garbage at end of line"));
}
}
-/* Parse ordinary expression. */
-
-static char *
-parse_exp (s, op)
- char *s;
- expressionS *op;
-{
- input_line_pointer = s;
- expression (op);
- if (op->X_op == O_absent)
- as_bad (_("missing operand"));
- return input_line_pointer;
-}
-
-/* Parse special expressions (needed for LDI command):
- xx8 (address)
- xx8 (-address)
- pm_xx8 (address)
- pm_xx8 (-address)
- where xx is: hh, hi, lo. */
-
-static bfd_reloc_code_real_type
-avr_ldi_expression (exp)
- expressionS *exp;
-{
- char *str = input_line_pointer;
- char *tmp;
- char op[8];
- int mod;
- tmp = str;
-
- str = extract_word (str, op, sizeof (op));
-
- if (op[0])
- {
- mod = (int) hash_find (avr_mod_hash, op);
-
- if (mod)
- {
- int closes = 0;
-
- mod -= 10;
- str = skip_space (str);
-
- if (*str == '(')
- {
- int neg_p = 0;
-
- ++str;
-
- if (strncmp ("pm(", str, 3) == 0
- || strncmp ("-(pm(", str, 5) == 0)
- {
- if (HAVE_PM_P (mod))
- {
- ++mod;
- ++closes;
- }
- else
- as_bad (_("illegal expression"));
-
- if (*str == '-')
- {
- neg_p = 1;
- ++closes;
- str += 5;
- }
- else
- str += 3;
- }
-
- if (*str == '-' && *(str + 1) == '(')
- {
- neg_p ^= 1;
- ++closes;
- str += 2;
- }
-
- input_line_pointer = str;
- expression (exp);
-
- do
- {
- if (*input_line_pointer != ')')
- {
- as_bad (_("`)' required"));
- break;
- }
- input_line_pointer++;
- }
- while (closes--);
-
- return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod);
- }
- }
- }
-
- input_line_pointer = tmp;
- expression (exp);
-
- /* Warn about expressions that fail to use lo8 (). */
- if (exp->X_op == O_constant)
- {
- int x = exp->X_add_number;
- if (x < -255 || x > 255)
- as_warn (_("constant out of 8-bit range: %d"), x);
- }
-
- return BFD_RELOC_AVR_LDI;
-}
-
/* Flag to pass `pm' mode between `avr_parse_cons_expression' and
`avr_cons_fix_new'. */
static int exp_mod_pm = 0;
Relocation: BFD_RELOC_AVR_16_PM. */
void
-avr_parse_cons_expression (exp, nbytes)
- expressionS *exp;
- int nbytes;
+avr_parse_cons_expression (expressionS *exp, int nbytes)
{
char *tmp;
}
void
-avr_cons_fix_new (frag, where, nbytes, exp)
- fragS *frag;
- int where;
- int nbytes;
- expressionS *exp;
+avr_cons_fix_new (fragS *frag,
+ int where,
+ int nbytes,
+ expressionS *exp)
{
if (exp_mod_pm == 0)
{