/* tc-avr.c -- Assembler code for the ATMEL AVR
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Denis Chertykov <denisc@overta.ru>
This file is part of GAS, the GNU Assembler.
Boston, MA 02111-1307, USA. */
#include <stdio.h>
-#include <ctype.h>
#include "as.h"
+#include "safe-ctype.h"
#include "subsegs.h"
struct avr_opcodes_s
int mach;
};
+/* XXX - devices that don't seem to exist (renamed, replaced with larger
+ ones, or planned but never produced), left here for compatibility.
+ TODO: hide them in show_mcu_list output? */
+
static struct mcu_type_s mcu_types[] =
{
{"avr1", AVR_ISA_TINY1, bfd_mach_avr1},
{"avr2", AVR_ISA_2xxx, bfd_mach_avr2},
{"avr3", AVR_ISA_M103, bfd_mach_avr3},
- {"avr4", AVR_ISA_M83, bfd_mach_avr4},
+ {"avr4", AVR_ISA_M8, bfd_mach_avr4},
{"avr5", AVR_ISA_ALL, bfd_mach_avr5},
{"at90s1200", AVR_ISA_1200, bfd_mach_avr1},
- {"attiny10", AVR_ISA_TINY1, bfd_mach_avr1},
+ {"attiny10", AVR_ISA_TINY1, bfd_mach_avr1}, /* XXX -> tn11 */
{"attiny11", AVR_ISA_TINY1, bfd_mach_avr1},
{"attiny12", AVR_ISA_TINY1, bfd_mach_avr1},
{"attiny15", AVR_ISA_TINY1, bfd_mach_avr1},
{"attiny28", AVR_ISA_TINY1, bfd_mach_avr1},
{"at90s2313", AVR_ISA_2xxx, bfd_mach_avr2},
{"at90s2323", AVR_ISA_2xxx, bfd_mach_avr2},
- {"at90s2333", AVR_ISA_2xxx, bfd_mach_avr2},
+ {"at90s2333", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 4433 */
{"attiny22" , AVR_ISA_2xxx, bfd_mach_avr2},
{"at90s2343", AVR_ISA_2xxx, bfd_mach_avr2},
{"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2},
- {"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2},
- {"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2},
+ {"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8515 */
+ {"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8535 */
{"at90s8515", AVR_ISA_2xxx, bfd_mach_avr2},
{"at90s8535", AVR_ISA_2xxx, bfd_mach_avr2},
{"at90c8534", AVR_ISA_2xxx, bfd_mach_avr2},
- {"atmega603", AVR_ISA_M603, bfd_mach_avr3},
+ {"atmega603", AVR_ISA_M603, bfd_mach_avr3}, /* XXX -> m103 */
{"atmega103", AVR_ISA_M103, bfd_mach_avr3},
- {"atmega83", AVR_ISA_M83, bfd_mach_avr4},
- {"atmega85", AVR_ISA_M83, bfd_mach_avr4},
+ {"at43usb320",AVR_ISA_M103, bfd_mach_avr3},
+ {"at76c711", AVR_ISA_M603, bfd_mach_avr3},
+ {"atmega8", AVR_ISA_M8, bfd_mach_avr4},
+ {"atmega83", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m163 */
+ {"atmega85", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8 */
+ {"atmega16", AVR_ISA_M323, bfd_mach_avr5},
{"atmega161", AVR_ISA_M161, bfd_mach_avr5},
{"atmega163", AVR_ISA_M161, bfd_mach_avr5},
- {"atmega32", AVR_ISA_M161, bfd_mach_avr5},
+ {"atmega32", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega323", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega64", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega128", AVR_ISA_M128, bfd_mach_avr5},
+ {"at43usb355",AVR_ISA_94K, bfd_mach_avr5},
{"at94k", AVR_ISA_94K, bfd_mach_avr5},
{NULL, 0, 0}
};
fprintf (stream, _("Known MCU names:"));
x = 1000;
-
+
for (i = 0; mcu_types[i].name; i++)
{
int len = strlen (mcu_types[i].name);
-
+
x += len + 1;
-
+
if (x < 75)
fprintf (stream, " %s", mcu_types[i].name);
else
x = len + 2;
}
}
-
+
fprintf (stream, "\n");
}
if (size + 1 >= limit)
break;
}
-
+
to[size] = 0;
return op_end;
}
int dummy ATTRIBUTE_UNUSED;
{
char *str;
-
+
str = (char *) alloca (20);
input_line_pointer = extract_word (input_line_pointer, str, 20);
md_parse_option (OPTION_MMCU, str);
char *arg1 = arg;
do
- *t = tolower (*arg1++);
+ *t = TOLOWER (*arg1++);
while (*t++);
}
avr_opt.no_wrap = 1;
return 1;
}
-
+
return 0;
}
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
-
+
/* This loop outputs the LITTLENUMs in REVERSE order. */
for (wordP = words + prec - 1; prec--;)
{
md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
-
+
return NULL;
}
if (ex.X_add_number > max || ex.X_add_number < 0)
as_bad (_("number must be less than %d"), max + 1);
-
+
return ex.X_add_number;
}
{
if (*op == ',')
++op;
-
+
if (*op == '=')
{
reg2 = reg1;
reg2 = avr_operand (opcode, where, op, &str);
}
-
+
if (reg1_present && reg2_present)
reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200);
else if (reg2_present)
if (*str == 'r' || *str == 'R')
{
char r_name[20];
-
+
str = extract_word (str, r_name, sizeof (r_name));
op_mask = 0xff;
- if (isdigit (r_name[1]))
+ if (ISDIGIT (r_name[1]))
{
if (r_name[2] == '\0')
op_mask = r_name[1] - '0';
else if (r_name[1] != '0'
- && isdigit (r_name[2])
+ && ISDIGIT (r_name[2])
&& r_name[3] == '\0')
op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
}
op_mask = avr_get_constant (str, 31);
str = input_line_pointer;
}
-
+
if (op_mask <= 31)
{
switch (*op)
as_bad (_("register r16-r23 required"));
op_mask -= 16;
break;
-
+
case 'd':
if (op_mask < 16)
as_bad (_("register number above 15 required"));
op_mask -= 16;
break;
-
+
case 'v':
if (op_mask & 1)
as_bad (_("even register number required"));
op_mask >>= 1;
break;
-
+
case 'w':
if ((op_mask & 1) || op_mask < 24)
as_bad (_("register r24, r26, r28 or r30 required"));
case 'e':
{
char c;
-
+
if (*str == '-')
{
str = skip_space (str + 1);
op_mask = 0x1002;
}
- c = tolower (*str);
+ c = TOLOWER (*str);
if (c == 'x')
op_mask |= 0x100c;
else if (c == 'y')
case 'z':
if (*str == '-')
as_bad (_("can't predecrement"));
-
+
if (! (*str == 'z' || *str == 'Z'))
as_bad (_("pointer register Z required"));
-
+
str = skip_space (str + 1);
if (*str == '+')
case 'b':
{
- char c = tolower (*str++);
-
+ char c = TOLOWER (*str++);
+
if (c == 'y')
op_mask |= 0x8;
else if (c != 'z')
case 'M':
{
bfd_reloc_code_real_type r_type;
-
+
input_line_pointer = str;
r_type = avr_ldi_expression (&op_expr);
str = input_line_pointer;
case 'n':
{
unsigned int x;
-
+
x = ~avr_get_constant (str, 255);
str = input_line_pointer;
op_mask |= (x & 0xf) | ((x << 4) & 0xf00);
case 'K':
{
unsigned int x;
-
+
x = avr_get_constant (str, 63);
str = input_line_pointer;
op_mask |= (x & 0xf) | ((x & 0x30) << 2);
case 's':
{
unsigned int x;
-
+
x = avr_get_constant (str, 7);
str = input_line_pointer;
if (*op == 'S')
case 'P':
{
unsigned int x;
-
+
x = avr_get_constant (str, 63);
str = input_line_pointer;
op_mask |= (x & 0xf) | ((x & 0x30) << 5);
case 'p':
{
unsigned int x;
-
+
x = avr_get_constant (str, 31);
str = input_line_pointer;
op_mask |= x << 3;
}
break;
-
+
case '?':
break;
-
+
default:
as_bad (_("unknown constraint `%c'"), *op);
}
-
+
*line = str;
return op_mask;
}
&& (!S_IS_DEFINED (fixp->fx_addsy)
|| (S_GET_SEGMENT (fixp->fx_addsy) != sec)))
return 0;
-
+
return fixp->fx_frag->fr_address + fixp->fx_where;
}
/* GAS will call this for each fixup. It should store the correct
value in the object file. */
-int
-md_apply_fix3 (fixp, valuep, seg)
- fixS *fixp;
- valueT *valuep;
+void
+md_apply_fix3 (fixP, valP, seg)
+ fixS *fixP;
+ valueT * valP;
segT seg;
{
unsigned char *where;
unsigned long insn;
- long value;
+ long value = * (long *) valP;
- if (fixp->fx_addsy == (symbolS *) NULL)
- {
- value = *valuep;
- fixp->fx_done = 1;
- }
- else if (fixp->fx_pcrel)
+ if (fixP->fx_addsy == (symbolS *) NULL)
+ fixP->fx_done = 1;
+
+ else if (fixP->fx_pcrel)
{
- segT s = S_GET_SEGMENT (fixp->fx_addsy);
-
- if (fixp->fx_addsy && (s == seg || s == absolute_section))
+ segT s = S_GET_SEGMENT (fixP->fx_addsy);
+
+ if (fixP->fx_addsy && (s == seg || s == absolute_section))
{
- value = S_GET_VALUE (fixp->fx_addsy) + *valuep;
- fixp->fx_done = 1;
+ value += S_GET_VALUE (fixP->fx_addsy);
+ fixP->fx_done = 1;
}
- else
- value = *valuep;
}
else
{
- value = fixp->fx_offset;
-
- if (fixp->fx_subsy != (symbolS *) NULL)
+ value = fixP->fx_offset;
+
+ if (fixP->fx_subsy != (symbolS *) NULL)
{
- if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
+ if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
{
- value -= S_GET_VALUE (fixp->fx_subsy);
- fixp->fx_done = 1;
+ value -= S_GET_VALUE (fixP->fx_subsy);
+ fixP->fx_done = 1;
}
else
{
/* We don't actually support subtracting a symbol. */
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("expression too complex"));
}
}
}
-
- switch (fixp->fx_r_type)
+
+ switch (fixP->fx_r_type)
{
default:
- fixp->fx_no_overflow = 1;
+ fixP->fx_no_overflow = 1;
break;
case BFD_RELOC_AVR_7_PCREL:
case BFD_RELOC_AVR_13_PCREL:
break;
}
- if (fixp->fx_done)
+ if (fixP->fx_done)
{
/* Fetch the instruction, insert the fully resolved operand
value, and stuff the instruction back again. */
- where = fixp->fx_frag->fr_literal + fixp->fx_where;
+ where = fixP->fx_frag->fr_literal + fixP->fx_where;
insn = bfd_getl16 (where);
- switch (fixp->fx_r_type)
+ switch (fixP->fx_r_type)
{
case BFD_RELOC_AVR_7_PCREL:
if (value & 1)
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("odd address operand: %ld"), value);
-
+
/* Instruction addresses are always right-shifted by 1. */
value >>= 1;
--value; /* Correct PC. */
-
+
if (value < -64 || value > 63)
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("operand out of range: %ld"), value);
value = (value << 3) & 0x3f8;
bfd_putl16 ((bfd_vma) (value | insn), where);
case BFD_RELOC_AVR_13_PCREL:
if (value & 1)
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("odd address operand: %ld"), value);
-
+
/* Instruction addresses are always right-shifted by 1. */
value >>= 1;
--value; /* Correct PC. */
{
/* No wrap for devices with >8K of program memory. */
if ((avr_mcu->isa & AVR_ISA_MEGA) || avr_opt.no_wrap)
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("operand out of range: %ld"), value);
}
case BFD_RELOC_AVR_CALL:
{
unsigned long x;
-
+
x = bfd_getl16 (where);
if (value & 1)
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("odd address operand: %ld"), value);
value >>= 1;
x |= ((value & 0x10000) | ((value << 3) & 0x1f00000)) >> 16;
default:
as_fatal (_("line %d: unknown relocation type: 0x%x"),
- fixp->fx_line, fixp->fx_r_type);
+ fixP->fx_line, fixP->fx_r_type);
break;
}
}
else
{
- switch (fixp->fx_r_type)
+ switch (fixP->fx_r_type)
{
case -BFD_RELOC_AVR_HI8_LDI_NEG:
case -BFD_RELOC_AVR_HI8_LDI:
case -BFD_RELOC_AVR_LO8_LDI_NEG:
case -BFD_RELOC_AVR_LO8_LDI:
- as_bad_where (fixp->fx_file, fixp->fx_line,
+ as_bad_where (fixP->fx_file, fixP->fx_line,
_("only constant expression allowed"));
- fixp->fx_done = 1;
+ fixP->fx_done = 1;
break;
default:
break;
}
- fixp->fx_addnumber = value;
+ fixP->fx_addnumber = value;
}
- return 0;
}
/* A `BFD_ASSEMBLER' GAS will call this to generate a reloc. GAS
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)
{
}
else
as_bad (_("illegal expression"));
-
+
if (*str == '-')
{
neg_p = 1;
else
str += 3;
}
-
+
if (*str == '-' && *(str + 1) == '(')
{
neg_p ^= 1;
++closes;
str += 2;
}
-
+
input_line_pointer = str;
expression (exp);
-
+
do
{
if (*input_line_pointer != ')')
input_line_pointer++;
}
while (closes--);
-
+
return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod);
}
}
}
-
+
input_line_pointer = tmp;
expression (exp);
{
char *pm_name = "pm";
int len = strlen (pm_name);
-
+
if (strncasecmp (input_line_pointer, pm_name, len) == 0)
{
input_line_pointer = skip_space (input_line_pointer + len);
-
+
if (*input_line_pointer == '(')
{
input_line_pointer = skip_space (input_line_pointer + 1);
exp_mod_pm = 1;
expression (exp);
-
+
if (*input_line_pointer == ')')
++input_line_pointer;
else
as_bad (_("`)' required"));
exp_mod_pm = 0;
}
-
+
return;
}
-
+
input_line_pointer = tmp;
}
}
-
+
expression (exp);
}