mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 18:08:24 +08:00
* config/tc-avr.c: Convert to ISO C90 format. Fix formatting and generally
tidy up the code. * config/tc-avr.h: Likewise.
This commit is contained in:
@ -1,3 +1,9 @@
|
|||||||
|
2005-10-12 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
* config/tc-avr.c: Convert to ISO C90 format. Fix formatting and
|
||||||
|
generally tidy up the code.
|
||||||
|
* config/tc-avr.h: Likewise.
|
||||||
|
|
||||||
2005-10-12 Jan Beulich <jbeulich@novell.com>
|
2005-10-12 Jan Beulich <jbeulich@novell.com>
|
||||||
|
|
||||||
* config/tc-ia64.c (dot_reg_val): Use expression_and_evaluate.
|
* config/tc-ia64.c (dot_reg_val): Use expression_and_evaluate.
|
||||||
|
@ -25,14 +25,15 @@
|
|||||||
#include "as.h"
|
#include "as.h"
|
||||||
#include "safe-ctype.h"
|
#include "safe-ctype.h"
|
||||||
#include "subsegs.h"
|
#include "subsegs.h"
|
||||||
|
#include "libiberty.h"
|
||||||
|
|
||||||
struct avr_opcodes_s
|
struct avr_opcodes_s
|
||||||
{
|
{
|
||||||
char *name;
|
char * name;
|
||||||
char *constraints;
|
char * constraints;
|
||||||
int insn_size; /* In words. */
|
int insn_size; /* In words. */
|
||||||
int isa;
|
int isa;
|
||||||
unsigned int bin_opcode;
|
unsigned int bin_opcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
|
#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
|
||||||
@ -121,22 +122,23 @@ static struct mcu_type_s mcu_types[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Current MCU type. */
|
/* Current MCU type. */
|
||||||
static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_2xxx,bfd_mach_avr2};
|
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 * avr_mcu = & default_mcu;
|
||||||
|
|
||||||
/* AVR target-specific switches. */
|
/* AVR target-specific switches. */
|
||||||
struct avr_opt_s
|
struct avr_opt_s
|
||||||
{
|
{
|
||||||
int all_opcodes; /* -mall-opcodes: accept all known AVR opcodes */
|
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_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 no_wrap; /* -mno-wrap: reject rjmp/rcall with 8K wrap-around. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct avr_opt_s avr_opt = { 0, 0, 0 };
|
static struct avr_opt_s avr_opt = { 0, 0, 0 };
|
||||||
|
|
||||||
const char EXP_CHARS[] = "eE";
|
const char EXP_CHARS[] = "eE";
|
||||||
const char FLT_CHARS[] = "dD";
|
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. */
|
/* The target specific pseudo-ops which we support. */
|
||||||
const pseudo_typeS md_pseudo_table[] =
|
const pseudo_typeS md_pseudo_table[] =
|
||||||
@ -147,27 +149,17 @@ const pseudo_typeS md_pseudo_table[] =
|
|||||||
|
|
||||||
#define LDI_IMMEDIATE(x) (((x) & 0xf) | (((x) << 4) & 0xf00))
|
#define LDI_IMMEDIATE(x) (((x) & 0xf) | (((x) << 4) & 0xf00))
|
||||||
|
|
||||||
static void show_mcu_list PARAMS ((FILE *));
|
#define EXP_MOD_NAME(i) exp_mod[i].name
|
||||||
static char *skip_space PARAMS ((char *));
|
#define EXP_MOD_RELOC(i) exp_mod[i].reloc
|
||||||
static char *extract_word PARAMS ((char *, char *, int));
|
#define EXP_MOD_NEG_RELOC(i) exp_mod[i].neg_reloc
|
||||||
static unsigned int avr_operand PARAMS ((struct avr_opcodes_s *,
|
#define HAVE_PM_P(i) exp_mod[i].have_pm
|
||||||
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
|
|
||||||
|
|
||||||
struct exp_mod_s
|
struct exp_mod_s
|
||||||
{
|
{
|
||||||
char *name;
|
char * name;
|
||||||
bfd_reloc_code_real_type reloc;
|
bfd_reloc_code_real_type reloc;
|
||||||
bfd_reloc_code_real_type neg_reloc;
|
bfd_reloc_code_real_type neg_reloc;
|
||||||
int have_pm;
|
int have_pm;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct exp_mod_s exp_mod[] =
|
static struct exp_mod_s exp_mod[] =
|
||||||
@ -189,9 +181,12 @@ static struct hash_control *avr_hash;
|
|||||||
static struct hash_control *avr_mod_hash;
|
static struct hash_control *avr_mod_hash;
|
||||||
|
|
||||||
#define OPTION_MMCU 'm'
|
#define OPTION_MMCU 'm'
|
||||||
#define OPTION_ALL_OPCODES (OPTION_MD_BASE + 1)
|
enum options
|
||||||
#define OPTION_NO_SKIP_BUG (OPTION_MD_BASE + 2)
|
{
|
||||||
#define OPTION_NO_WRAP (OPTION_MD_BASE + 3)
|
OPTION_ALL_OPCODES = OPTION_MD_BASE + 1,
|
||||||
|
OPTION_NO_SKIP_BUG,
|
||||||
|
OPTION_NO_WRAP
|
||||||
|
};
|
||||||
|
|
||||||
struct option md_longopts[] =
|
struct option md_longopts[] =
|
||||||
{
|
{
|
||||||
@ -207,8 +202,7 @@ size_t md_longopts_size = sizeof (md_longopts);
|
|||||||
/* Display nicely formatted list of known MCU names. */
|
/* Display nicely formatted list of known MCU names. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
show_mcu_list (stream)
|
show_mcu_list (FILE *stream)
|
||||||
FILE *stream;
|
|
||||||
{
|
{
|
||||||
int i, x;
|
int i, x;
|
||||||
|
|
||||||
@ -234,8 +228,7 @@ show_mcu_list (stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline char *
|
static inline char *
|
||||||
skip_space (s)
|
skip_space (char *s)
|
||||||
char *s;
|
|
||||||
{
|
{
|
||||||
while (*s == ' ' || *s == '\t')
|
while (*s == ' ' || *s == '\t')
|
||||||
++s;
|
++s;
|
||||||
@ -268,17 +261,15 @@ extract_word (char *from, char *to, int limit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
md_estimate_size_before_relax (fragp, seg)
|
md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
|
||||||
fragS *fragp ATTRIBUTE_UNUSED;
|
asection *seg ATTRIBUTE_UNUSED)
|
||||||
asection *seg ATTRIBUTE_UNUSED;
|
|
||||||
{
|
{
|
||||||
abort ();
|
abort ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
md_show_usage (stream)
|
md_show_usage (FILE *stream)
|
||||||
FILE *stream;
|
|
||||||
{
|
{
|
||||||
fprintf (stream,
|
fprintf (stream,
|
||||||
_("AVR options:\n"
|
_("AVR options:\n"
|
||||||
@ -300,21 +291,17 @@ md_show_usage (stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
avr_set_arch (dummy)
|
avr_set_arch (int dummy ATTRIBUTE_UNUSED)
|
||||||
int dummy ATTRIBUTE_UNUSED;
|
|
||||||
{
|
{
|
||||||
char *str;
|
char str[20];
|
||||||
|
|
||||||
str = (char *) alloca (20);
|
|
||||||
input_line_pointer = extract_word (input_line_pointer, str, 20);
|
input_line_pointer = extract_word (input_line_pointer, str, 20);
|
||||||
md_parse_option (OPTION_MMCU, str);
|
md_parse_option (OPTION_MMCU, str);
|
||||||
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
|
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
md_parse_option (c, arg)
|
md_parse_option (int c, char *arg)
|
||||||
int c;
|
|
||||||
char *arg;
|
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@ -367,10 +354,9 @@ md_parse_option (c, arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
symbolS *
|
symbolS *
|
||||||
md_undefined_symbol (name)
|
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
|
||||||
char *name ATTRIBUTE_UNUSED;
|
|
||||||
{
|
{
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn a string in input_line_pointer into a floating point constant
|
/* Turn a string in input_line_pointer into a floating point constant
|
||||||
@ -379,10 +365,7 @@ md_undefined_symbol (name)
|
|||||||
returned, or NULL on OK. */
|
returned, or NULL on OK. */
|
||||||
|
|
||||||
char *
|
char *
|
||||||
md_atof (type, litP, sizeP)
|
md_atof (int type, char *litP, int *sizeP)
|
||||||
int type;
|
|
||||||
char *litP;
|
|
||||||
int *sizeP;
|
|
||||||
{
|
{
|
||||||
int prec;
|
int prec;
|
||||||
LITTLENUM_TYPE words[4];
|
LITTLENUM_TYPE words[4];
|
||||||
@ -419,19 +402,19 @@ md_atof (type, litP, sizeP)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
md_convert_frag (abfd, sec, fragP)
|
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
bfd *abfd ATTRIBUTE_UNUSED;
|
asection *sec ATTRIBUTE_UNUSED,
|
||||||
asection *sec ATTRIBUTE_UNUSED;
|
fragS *fragP ATTRIBUTE_UNUSED)
|
||||||
fragS *fragP ATTRIBUTE_UNUSED;
|
|
||||||
{
|
{
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
md_begin ()
|
md_begin (void)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct avr_opcodes_s *opcode;
|
struct avr_opcodes_s *opcode;
|
||||||
|
|
||||||
avr_hash = hash_new ();
|
avr_hash = hash_new ();
|
||||||
|
|
||||||
/* Insert unique names into hash table. This hash table then provides a
|
/* Insert unique names into hash table. This hash table then provides a
|
||||||
@ -442,7 +425,7 @@ md_begin ()
|
|||||||
|
|
||||||
avr_mod_hash = hash_new ();
|
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));
|
hash_insert (avr_mod_hash, EXP_MOD_NAME (i), (void *) (i + 10));
|
||||||
|
|
||||||
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
|
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
|
||||||
@ -452,14 +435,13 @@ md_begin ()
|
|||||||
If result greater than MAX then error. */
|
If result greater than MAX then error. */
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
avr_get_constant (str, max)
|
avr_get_constant (char *str, int max)
|
||||||
char *str;
|
|
||||||
int max;
|
|
||||||
{
|
{
|
||||||
expressionS ex;
|
expressionS ex;
|
||||||
|
|
||||||
str = skip_space (str);
|
str = skip_space (str);
|
||||||
input_line_pointer = str;
|
input_line_pointer = str;
|
||||||
expression (&ex);
|
expression (& ex);
|
||||||
|
|
||||||
if (ex.X_op != O_constant)
|
if (ex.X_op != O_constant)
|
||||||
as_bad (_("constant value required"));
|
as_bad (_("constant value required"));
|
||||||
@ -470,95 +452,7 @@ avr_get_constant (str, max)
|
|||||||
return ex.X_add_number;
|
return ex.X_add_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse instruction operands.
|
/* Parse for ldd/std offset. */
|
||||||
Return binary opcode. */
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
avr_operands (opcode, line)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse for ldd/std offset */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
avr_offset_expression (expressionS *exp)
|
avr_offset_expression (expressionS *exp)
|
||||||
@ -583,15 +477,123 @@ avr_offset_expression (expressionS *exp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse ordinary expression. */
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 (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;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse one instruction operand.
|
/* Parse one instruction operand.
|
||||||
Return operand bitmask. Also fixups can be generated. */
|
Return operand bitmask. Also fixups can be generated. */
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
avr_operand (opcode, where, op, line)
|
avr_operand (struct avr_opcodes_s *opcode,
|
||||||
struct avr_opcodes_s *opcode;
|
int where,
|
||||||
int where;
|
char *op,
|
||||||
char *op;
|
char **line)
|
||||||
char **line;
|
|
||||||
{
|
{
|
||||||
expressionS op_expr;
|
expressionS op_expr;
|
||||||
unsigned int op_mask = 0;
|
unsigned int op_mask = 0;
|
||||||
@ -828,13 +830,95 @@ avr_operand (opcode, where, op, line)
|
|||||||
return op_mask;
|
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,
|
/* 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. */
|
to permit the CPU backend to adjust the alignment of a section. */
|
||||||
|
|
||||||
valueT
|
valueT
|
||||||
md_section_align (seg, addr)
|
md_section_align (asection *seg, valueT addr)
|
||||||
asection *seg;
|
|
||||||
valueT addr;
|
|
||||||
{
|
{
|
||||||
int align = bfd_get_section_alignment (stdoutput, seg);
|
int align = bfd_get_section_alignment (stdoutput, seg);
|
||||||
return ((addr + (1 << align) - 1) & (-1 << align));
|
return ((addr + (1 << align) - 1) & (-1 << align));
|
||||||
@ -847,9 +931,7 @@ md_section_align (seg, addr)
|
|||||||
macro would return the length of an instruction. */
|
macro would return the length of an instruction. */
|
||||||
|
|
||||||
long
|
long
|
||||||
md_pcrel_from_section (fixp, sec)
|
md_pcrel_from_section (fixS *fixp, segT sec)
|
||||||
fixS *fixp;
|
|
||||||
segT sec;
|
|
||||||
{
|
{
|
||||||
if (fixp->fx_addsy != (symbolS *) NULL
|
if (fixp->fx_addsy != (symbolS *) NULL
|
||||||
&& (!S_IS_DEFINED (fixp->fx_addsy)
|
&& (!S_IS_DEFINED (fixp->fx_addsy)
|
||||||
@ -863,10 +945,7 @@ md_pcrel_from_section (fixp, sec)
|
|||||||
value in the object file. */
|
value in the object file. */
|
||||||
|
|
||||||
void
|
void
|
||||||
md_apply_fix (fixP, valP, seg)
|
md_apply_fix (fixS *fixP, valueT * valP, segT seg)
|
||||||
fixS *fixP;
|
|
||||||
valueT * valP;
|
|
||||||
segT seg;
|
|
||||||
{
|
{
|
||||||
unsigned char *where;
|
unsigned char *where;
|
||||||
unsigned long insn;
|
unsigned long insn;
|
||||||
@ -1095,15 +1174,14 @@ md_apply_fix (fixP, valP, seg)
|
|||||||
then it is done here. */
|
then it is done here. */
|
||||||
|
|
||||||
arelent *
|
arelent *
|
||||||
tc_gen_reloc (seg, fixp)
|
tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED,
|
||||||
asection *seg ATTRIBUTE_UNUSED;
|
fixS *fixp)
|
||||||
fixS *fixp;
|
|
||||||
{
|
{
|
||||||
arelent *reloc;
|
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->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
|
||||||
|
|
||||||
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
|
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
|
||||||
@ -1126,8 +1204,7 @@ tc_gen_reloc (seg, fixp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
md_assemble (str)
|
md_assemble (char *str)
|
||||||
char *str;
|
|
||||||
{
|
{
|
||||||
struct avr_opcodes_s *opcode;
|
struct avr_opcodes_s *opcode;
|
||||||
char op[11];
|
char op[11];
|
||||||
@ -1158,6 +1235,7 @@ md_assemble (str)
|
|||||||
but that is wrong. Our caller assumes we don't change it. */
|
but that is wrong. Our caller assumes we don't change it. */
|
||||||
{
|
{
|
||||||
char *t = input_line_pointer;
|
char *t = input_line_pointer;
|
||||||
|
|
||||||
avr_operands (opcode, &str);
|
avr_operands (opcode, &str);
|
||||||
if (*skip_space (str))
|
if (*skip_space (str))
|
||||||
as_bad (_("garbage at end of line"));
|
as_bad (_("garbage at end of line"));
|
||||||
@ -1165,117 +1243,6 @@ md_assemble (str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
/* Flag to pass `pm' mode between `avr_parse_cons_expression' and
|
||||||
`avr_cons_fix_new'. */
|
`avr_cons_fix_new'. */
|
||||||
static int exp_mod_pm = 0;
|
static int exp_mod_pm = 0;
|
||||||
@ -1285,9 +1252,7 @@ static int exp_mod_pm = 0;
|
|||||||
Relocation: BFD_RELOC_AVR_16_PM. */
|
Relocation: BFD_RELOC_AVR_16_PM. */
|
||||||
|
|
||||||
void
|
void
|
||||||
avr_parse_cons_expression (exp, nbytes)
|
avr_parse_cons_expression (expressionS *exp, int nbytes)
|
||||||
expressionS *exp;
|
|
||||||
int nbytes;
|
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
@ -1329,11 +1294,10 @@ avr_parse_cons_expression (exp, nbytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
avr_cons_fix_new (frag, where, nbytes, exp)
|
avr_cons_fix_new (fragS *frag,
|
||||||
fragS *frag;
|
int where,
|
||||||
int where;
|
int nbytes,
|
||||||
int nbytes;
|
expressionS *exp)
|
||||||
expressionS *exp;
|
|
||||||
{
|
{
|
||||||
if (exp_mod_pm == 0)
|
if (exp_mod_pm == 0)
|
||||||
{
|
{
|
||||||
|
@ -53,13 +53,13 @@
|
|||||||
/* You may define this macro to parse an expression used in a data
|
/* You may define this macro to parse an expression used in a data
|
||||||
allocation pseudo-op such as `.word'. You can use this to
|
allocation pseudo-op such as `.word'. You can use this to
|
||||||
recognize relocation directives that may appear in such directives. */
|
recognize relocation directives that may appear in such directives. */
|
||||||
#define TC_PARSE_CONS_EXPRESSION(EXPR,N) avr_parse_cons_expression (EXPR,N)
|
#define TC_PARSE_CONS_EXPRESSION(EXPR,N) avr_parse_cons_expression (EXPR, N)
|
||||||
void avr_parse_cons_expression (expressionS *exp, int nbytes);
|
extern void avr_parse_cons_expression (expressionS *, int);
|
||||||
|
|
||||||
/* You may define this macro to generate a fixup for a data
|
/* You may define this macro to generate a fixup for a data
|
||||||
allocation pseudo-op. */
|
allocation pseudo-op. */
|
||||||
#define TC_CONS_FIX_NEW(FRAG,WHERE,N,EXP) avr_cons_fix_new(FRAG,WHERE,N,EXP)
|
#define TC_CONS_FIX_NEW(FRAG,WHERE,N,EXP) avr_cons_fix_new (FRAG, WHERE, N, EXP)
|
||||||
void avr_cons_fix_new(fragS *frag,int where, int nbytes, expressionS *exp);
|
extern void avr_cons_fix_new (fragS *,int, int, expressionS *);
|
||||||
|
|
||||||
/* This should just call either `number_to_chars_bigendian' or
|
/* This should just call either `number_to_chars_bigendian' or
|
||||||
`number_to_chars_littleendian', whichever is appropriate. On
|
`number_to_chars_littleendian', whichever is appropriate. On
|
||||||
@ -100,8 +100,8 @@ void avr_cons_fix_new(fragS *frag,int where, int nbytes, expressionS *exp);
|
|||||||
relative adjustment should be made. On many processors, the base
|
relative adjustment should be made. On many processors, the base
|
||||||
of a PC relative instruction is the next instruction, so this
|
of a PC relative instruction is the next instruction, so this
|
||||||
macro would return the length of an instruction. */
|
macro would return the length of an instruction. */
|
||||||
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC)
|
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section (FIX, SEC)
|
||||||
extern long md_pcrel_from_section PARAMS ((struct fix *, segT));
|
extern long md_pcrel_from_section (struct fix *, segT);
|
||||||
|
|
||||||
/* The number of bytes to put into a word in a listing. This affects
|
/* The number of bytes to put into a word in a listing. This affects
|
||||||
the way the bytes are clumped together in the listing. For
|
the way the bytes are clumped together in the listing. For
|
||||||
|
Reference in New Issue
Block a user