mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-09-10 14:59:31 +08:00
* config/tc-avr.c: New AVR_ISA_ defined.
(md_assemble): Handle opcodes with optional operands (lpm,elpm). (avr_operand): Handle 'a', 'v' and 'z' constraint letters needed for `fmul', `movw' and `lpm R,Z' instructions. (avr_operands): Warn if current opcode is a two-word instruction and previous opcode was cpse/sbic/sbis/sbrc/sbrs. (avr_opcodes): New commands added. (REGISTER_P): Check 'a' and 'v' constraint letters. (mcu_types): New MCU added.
This commit is contained in:
@ -1,3 +1,15 @@
|
|||||||
|
Sun Apr 23 16:45:45 2000 Denis Chertykov <denisc@overta.ru>
|
||||||
|
|
||||||
|
* config/tc-avr.c: New AVR_ISA_ defined.
|
||||||
|
(md_assemble): Handle opcodes with optional operands (lpm,elpm).
|
||||||
|
(avr_operand): Handle 'a', 'v' and 'z' constraint letters needed
|
||||||
|
for `fmul', `movw' and `lpm R,Z' instructions.
|
||||||
|
(avr_operands): Warn if current opcode is a two-word instruction
|
||||||
|
and previous opcode was cpse/sbic/sbis/sbrc/sbrs.
|
||||||
|
(avr_opcodes): New commands added.
|
||||||
|
(REGISTER_P): Check 'a' and 'v' constraint letters.
|
||||||
|
(mcu_types): New MCU added.
|
||||||
|
|
||||||
2000-05-01 Alan Modra <alan@linuxcare.com.au>
|
2000-05-01 Alan Modra <alan@linuxcare.com.au>
|
||||||
|
|
||||||
* configure.in: Set bfd_gas=yes on i386-*-pe and i386-*-nt* to
|
* configure.in: Set bfd_gas=yes on i386-*-pe and i386-*-nt* to
|
||||||
|
@ -29,11 +29,28 @@ const char comment_chars[] = ";";
|
|||||||
const char line_comment_chars[] = "#";
|
const char line_comment_chars[] = "#";
|
||||||
const char line_separator_chars[] = "$";
|
const char line_separator_chars[] = "$";
|
||||||
|
|
||||||
#define AVR_ISA_1200 1
|
#define AVR_ISA_1200 0x0001 /* in the beginning there was ... */
|
||||||
#define AVR_ISA_2xxx 3
|
#define AVR_ISA_LPM 0x0002 /* device has LPM */
|
||||||
#define AVR_ISA_MEGA_x03 0x17
|
#define AVR_ISA_LPMX 0x0004 /* device has LPM Rd,Z[+] */
|
||||||
#define AVR_ISA_MEGA 0x10
|
#define AVR_ISA_SRAM 0x0008 /* device has SRAM (LD, ST, PUSH, POP, ...) */
|
||||||
#define AVR_ISA_MEGA_161 0x1b
|
#define AVR_ISA_WRAP 0x0010 /* device has exactly 8K program memory */
|
||||||
|
#define AVR_ISA_MEGA 0x0020 /* device has >8K program memory (JMP, CALL) */
|
||||||
|
#define AVR_ISA_MUL 0x0040 /* device has new core (MUL, MOVW, ...) */
|
||||||
|
#define AVR_ISA_ELPM 0x0080 /* device has >64K program memory (ELPM) */
|
||||||
|
#define AVR_ISA_ELPMX 0x0100 /* device has ELPM Rd,Z[+] (none yet) */
|
||||||
|
#define AVR_ISA_SPM 0x0200 /* device can program itself (<=64K) */
|
||||||
|
#define AVR_ISA_ESPM 0x0400 /* device can program itself (>64K, none yet) */
|
||||||
|
#define AVR_ISA_EIND 0x0800 /* device has >128K program memory (none yet) */
|
||||||
|
|
||||||
|
#define AVR_ISA_TINY1 (AVR_ISA_1200 | AVR_ISA_LPM)
|
||||||
|
#define AVR_ISA_2xxx (AVR_ISA_TINY1 | AVR_ISA_SRAM)
|
||||||
|
#define AVR_ISA_85xx (AVR_ISA_2xxx | AVR_ISA_WRAP)
|
||||||
|
#define AVR_ISA_M603 (AVR_ISA_2xxx | AVR_ISA_MEGA)
|
||||||
|
#define AVR_ISA_M103 (AVR_ISA_M603 | AVR_ISA_ELPM)
|
||||||
|
#define AVR_ISA_M161 (AVR_ISA_M603 | AVR_ISA_MUL | AVR_ISA_LPMX | AVR_ISA_SPM)
|
||||||
|
#define AVR_ISA_94K (AVR_ISA_M603 | AVR_ISA_MUL | AVR_ISA_LPMX)
|
||||||
|
|
||||||
|
#define AVR_ISA_ALL 0xFFFF
|
||||||
|
|
||||||
const char *md_shortopts = "m:";
|
const char *md_shortopts = "m:";
|
||||||
struct mcu_type_s
|
struct mcu_type_s
|
||||||
@ -45,11 +62,16 @@ struct mcu_type_s
|
|||||||
|
|
||||||
static struct mcu_type_s mcu_types[] =
|
static struct mcu_type_s mcu_types[] =
|
||||||
{
|
{
|
||||||
{"avr1", AVR_ISA_1200, bfd_mach_avr1},
|
{"avr1", AVR_ISA_TINY1, bfd_mach_avr1},
|
||||||
{"avr2", AVR_ISA_2xxx, bfd_mach_avr2},
|
{"avr2", AVR_ISA_85xx, bfd_mach_avr2},
|
||||||
{"avr3", AVR_ISA_MEGA_x03, bfd_mach_avr3},
|
{"avr3", AVR_ISA_M103, bfd_mach_avr3},
|
||||||
{"avr4", AVR_ISA_MEGA_161, bfd_mach_avr4},
|
{"avr4", AVR_ISA_ALL, bfd_mach_avr4},
|
||||||
{"at90s1200", AVR_ISA_1200, bfd_mach_avr1},
|
{"at90s1200", AVR_ISA_1200, bfd_mach_avr1},
|
||||||
|
{"attiny10", AVR_ISA_TINY1, bfd_mach_avr1},
|
||||||
|
{"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},
|
{"at90s2313", AVR_ISA_2xxx, bfd_mach_avr2},
|
||||||
{"at90s2323", 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},
|
||||||
@ -58,11 +80,15 @@ static struct mcu_type_s mcu_types[] =
|
|||||||
{"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2},
|
{"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2},
|
||||||
{"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2},
|
{"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2},
|
||||||
{"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2},
|
{"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2},
|
||||||
{"at90s8515", AVR_ISA_2xxx, bfd_mach_avr2},
|
{"at90s8515", AVR_ISA_85xx, bfd_mach_avr2},
|
||||||
{"at90s8535", AVR_ISA_2xxx, bfd_mach_avr2},
|
{"at90s8535", AVR_ISA_85xx, bfd_mach_avr2},
|
||||||
{"atmega603", AVR_ISA_MEGA_x03, bfd_mach_avr3},
|
{"at90c8534", AVR_ISA_85xx, bfd_mach_avr2},
|
||||||
{"atmega103", AVR_ISA_MEGA_x03, bfd_mach_avr3},
|
{"atmega603", AVR_ISA_M603, bfd_mach_avr3},
|
||||||
{"atmega161", AVR_ISA_MEGA_161, bfd_mach_avr4},
|
{"atmega103", AVR_ISA_M103, bfd_mach_avr3},
|
||||||
|
{"atmega161", AVR_ISA_M161, bfd_mach_avr4},
|
||||||
|
{"at94k10", AVR_ISA_94K, bfd_mach_avr4},
|
||||||
|
{"at94k20", AVR_ISA_94K, bfd_mach_avr4},
|
||||||
|
{"at94k40", AVR_ISA_94K, bfd_mach_avr4},
|
||||||
{NULL, 0, 0}
|
{NULL, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,7 +109,11 @@ const pseudo_typeS md_pseudo_table[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define LDI_IMMEDIATE(x) (((x) & 0xf) | (((x) << 4) & 0xf00))
|
#define LDI_IMMEDIATE(x) (((x) & 0xf) | (((x) << 4) & 0xf00))
|
||||||
#define REGISTER_P(x) ((x) == 'r' || (x) == 'd' || (x) == 'w')
|
#define REGISTER_P(x) ((x) == 'r' \
|
||||||
|
|| (x) == 'd' \
|
||||||
|
|| (x) == 'w' \
|
||||||
|
|| (x) == 'a' \
|
||||||
|
|| (x) == 'v')
|
||||||
|
|
||||||
struct avr_opcodes_s
|
struct avr_opcodes_s
|
||||||
{
|
{
|
||||||
@ -105,24 +135,29 @@ static char *parse_exp (char *s, expressionS * op);
|
|||||||
static bfd_reloc_code_real_type avr_ldi_expression (expressionS *exp);
|
static bfd_reloc_code_real_type avr_ldi_expression (expressionS *exp);
|
||||||
long md_pcrel_from_section PARAMS ((fixS *, segT));
|
long md_pcrel_from_section PARAMS ((fixS *, segT));
|
||||||
|
|
||||||
|
|
||||||
/* constraint letters
|
/* constraint letters
|
||||||
r - any register
|
r - any register
|
||||||
d - `ldi' register (r16-r31)
|
d - `ldi' register (r16-r31)
|
||||||
|
v - `movw' even register (r0, r2, ..., r28, r30)
|
||||||
|
a - `fmul' register (r16-r23)
|
||||||
|
w - `adiw' register (r24,r26,r28,r30)
|
||||||
|
e - pointer registers (X,Y,Z)
|
||||||
|
b - base pointer register and displacement ([YZ]+disp)
|
||||||
|
z - Z pointer register (for [e]lpm Rd,Z[+])
|
||||||
M - immediate value from 0 to 255
|
M - immediate value from 0 to 255
|
||||||
n - immediate value from 0 to 255 ( n = ~M ). Relocation impossible
|
n - immediate value from 0 to 255 ( n = ~M ). Relocation impossible
|
||||||
w - `adiw' register (r24,r26,r28,r30)
|
|
||||||
s - immediate value from 0 to 7
|
s - immediate value from 0 to 7
|
||||||
P - Port address value from 0 to 64. (in, out)
|
P - Port address value from 0 to 64. (in, out)
|
||||||
p - Port address value from 0 to 32. (cbi, sbi, sbic, sbis)
|
p - Port address value from 0 to 32. (cbi, sbi, sbic, sbis)
|
||||||
K - immediate value from 0 to 64 (used in `adiw', `sbiw')
|
K - immediate value from 0 to 64 (used in `adiw', `sbiw')
|
||||||
e - pointer regegisters (X,Y,Z)
|
|
||||||
b - base pointer register and displacement ([YZ]+disp)
|
|
||||||
i - immediate value
|
i - immediate value
|
||||||
l - signed pc relative offset from -64 to 63
|
l - signed pc relative offset from -64 to 63
|
||||||
L - signed pc relative offset from -2048 to 2047
|
L - signed pc relative offset from -2048 to 2047
|
||||||
h - absolut code address (call, jmp)
|
h - absolut code address (call, jmp)
|
||||||
S - immediate value from 0 to 7 (S = s << 4)
|
S - immediate value from 0 to 7 (S = s << 4)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct avr_opcodes_s avr_opcodes[] =
|
struct avr_opcodes_s avr_opcodes[] =
|
||||||
{
|
{
|
||||||
{"adc", "r,r", "000111rdddddrrrr", 1, AVR_ISA_1200, 0x1c00},
|
{"adc", "r,r", "000111rdddddrrrr", 1, AVR_ISA_1200, 0x1c00},
|
||||||
@ -133,7 +168,7 @@ struct avr_opcodes_s avr_opcodes[] =
|
|||||||
{"cpse", "r,r", "000100rdddddrrrr", 1, AVR_ISA_1200, 0x1000},
|
{"cpse", "r,r", "000100rdddddrrrr", 1, AVR_ISA_1200, 0x1000},
|
||||||
{"eor", "r,r", "001001rdddddrrrr", 1, AVR_ISA_1200, 0x2400},
|
{"eor", "r,r", "001001rdddddrrrr", 1, AVR_ISA_1200, 0x2400},
|
||||||
{"mov", "r,r", "001011rdddddrrrr", 1, AVR_ISA_1200, 0x2c00},
|
{"mov", "r,r", "001011rdddddrrrr", 1, AVR_ISA_1200, 0x2c00},
|
||||||
{"mul", "r,r", "100111rdddddrrrr", 1, AVR_ISA_MEGA_161, 0x9c00},
|
{"mul", "r,r", "100111rdddddrrrr", 1, AVR_ISA_MUL, 0x9c00},
|
||||||
{"or", "r,r", "001010rdddddrrrr", 1, AVR_ISA_1200, 0x2800},
|
{"or", "r,r", "001010rdddddrrrr", 1, AVR_ISA_1200, 0x2800},
|
||||||
{"sbc", "r,r", "000010rdddddrrrr", 1, AVR_ISA_1200, 0x0800},
|
{"sbc", "r,r", "000010rdddddrrrr", 1, AVR_ISA_1200, 0x0800},
|
||||||
{"sub", "r,r", "000110rdddddrrrr", 1, AVR_ISA_1200, 0x1800},
|
{"sub", "r,r", "000110rdddddrrrr", 1, AVR_ISA_1200, 0x1800},
|
||||||
@ -230,7 +265,7 @@ struct avr_opcodes_s avr_opcodes[] =
|
|||||||
{"clz", "", "1001010010011000", 1, AVR_ISA_1200, 0x9498},
|
{"clz", "", "1001010010011000", 1, AVR_ISA_1200, 0x9498},
|
||||||
{"icall","", "1001010100001001", 1, AVR_ISA_2xxx, 0x9509},
|
{"icall","", "1001010100001001", 1, AVR_ISA_2xxx, 0x9509},
|
||||||
{"ijmp", "", "1001010000001001", 1, AVR_ISA_2xxx, 0x9409},
|
{"ijmp", "", "1001010000001001", 1, AVR_ISA_2xxx, 0x9409},
|
||||||
{"lpm", "", "1001010111001000", 1, AVR_ISA_2xxx, 0x95c8},
|
{"lpm", "", "1001010111001000", 1, AVR_ISA_TINY1,0x95c8},
|
||||||
{"nop", "", "0000000000000000", 1, AVR_ISA_1200, 0x0000},
|
{"nop", "", "0000000000000000", 1, AVR_ISA_1200, 0x0000},
|
||||||
{"ret", "", "1001010100001000", 1, AVR_ISA_1200, 0x9508},
|
{"ret", "", "1001010100001000", 1, AVR_ISA_1200, 0x9508},
|
||||||
{"reti", "", "1001010100011000", 1, AVR_ISA_1200, 0x9518},
|
{"reti", "", "1001010100011000", 1, AVR_ISA_1200, 0x9518},
|
||||||
@ -244,7 +279,22 @@ struct avr_opcodes_s avr_opcodes[] =
|
|||||||
{"sez", "", "1001010000011000", 1, AVR_ISA_1200, 0x9418},
|
{"sez", "", "1001010000011000", 1, AVR_ISA_1200, 0x9418},
|
||||||
{"sleep","", "1001010110001000", 1, AVR_ISA_1200, 0x9588},
|
{"sleep","", "1001010110001000", 1, AVR_ISA_1200, 0x9588},
|
||||||
{"wdr", "", "1001010110101000", 1, AVR_ISA_1200, 0x95a8},
|
{"wdr", "", "1001010110101000", 1, AVR_ISA_1200, 0x95a8},
|
||||||
{"elpm", "", "1001010111011000", 1, AVR_ISA_MEGA_x03, 0x95d8},
|
{"elpm", "", "1001010111011000", 1, AVR_ISA_ELPM, 0x95d8},
|
||||||
|
{"spm", "", "1001010111101000", 1, AVR_ISA_SPM, 0x95e8},
|
||||||
|
{"movw", "v,v", "00000001ddddrrrr", 1, AVR_ISA_MUL, 0x0100},
|
||||||
|
{"muls", "d,d", "00000010ddddrrrr", 1, AVR_ISA_MUL, 0x0200},
|
||||||
|
{"mulsu","a,a", "000000110ddd0rrr", 1, AVR_ISA_MUL, 0x0300},
|
||||||
|
{"fmul", "a,a", "000000110ddd1rrr", 1, AVR_ISA_MUL, 0x0308},
|
||||||
|
{"fmuls","a,a", "000000111ddd0rrr", 1, AVR_ISA_MUL, 0x0380},
|
||||||
|
{"fmulsu","a,a","000000111ddd1rrr", 1, AVR_ISA_MUL, 0x0388},
|
||||||
|
{"lpmx", "r,z", "1001000ddddd010+", 1, AVR_ISA_LPMX, 0x9004},
|
||||||
|
/* these are for devices that don't exists yet */
|
||||||
|
/* >64K program memory, new core */
|
||||||
|
{"elpmx","r,z", "1001000ddddd011+", 1, AVR_ISA_ELPMX,0x9006},
|
||||||
|
{"espm", "", "1001010111111000", 1, AVR_ISA_ESPM, 0x95f8},
|
||||||
|
/* >128K program memory (PC = EIND:Z) */
|
||||||
|
{"eicall", "", "1001010100011001", 1, AVR_ISA_EIND, 0x9519},
|
||||||
|
{"eijmp", "", "1001010000011001", 1, AVR_ISA_EIND, 0x9419},
|
||||||
{NULL, NULL, NULL, 0, 0, 0}
|
{NULL, NULL, NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -387,8 +437,8 @@ md_parse_option (c, arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
symbolS *
|
symbolS *
|
||||||
md_undefined_symbol (name)
|
md_undefined_symbol(name)
|
||||||
char *name;
|
char *name;
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -464,9 +514,16 @@ md_begin ()
|
|||||||
for (i = 0; i < sizeof (exp_mod) / sizeof (exp_mod[0]); ++i)
|
for (i = 0; i < sizeof (exp_mod) / sizeof (exp_mod[0]); ++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));
|
||||||
|
|
||||||
|
/* Construct symbols for each register */
|
||||||
|
/* FIXME: register names are in the same namespace as labels.
|
||||||
|
This means that C functions or global variables with the same
|
||||||
|
name as a register will cause assembler errors, even though
|
||||||
|
such names (r0-r31) are perfectly valid in C. I'd suggest to
|
||||||
|
put '%' or "." in front of register names both here and in avr-gcc. */
|
||||||
|
|
||||||
for (i = 0; i < 32; i++)
|
for (i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
char buf[5];
|
char buf[10];
|
||||||
|
|
||||||
sprintf (buf, "r%d", i);
|
sprintf (buf, "r%d", i);
|
||||||
symbol_table_insert (symbol_new (buf, reg_section, i,
|
symbol_table_insert (symbol_new (buf, reg_section, i,
|
||||||
@ -475,7 +532,7 @@ md_begin ()
|
|||||||
symbol_table_insert (symbol_new (buf, reg_section, i,
|
symbol_table_insert (symbol_new (buf, reg_section, i,
|
||||||
&zero_address_frag));
|
&zero_address_frag));
|
||||||
}
|
}
|
||||||
|
|
||||||
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
|
bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +547,7 @@ avr_operands (opcode, line)
|
|||||||
char *frag = frag_more (opcode->insn_size * 2);
|
char *frag = frag_more (opcode->insn_size * 2);
|
||||||
char *str = *line;
|
char *str = *line;
|
||||||
int where = frag - frag_now->fr_literal;
|
int where = frag - frag_now->fr_literal;
|
||||||
|
static unsigned int prev = 0; /* previous opcode */
|
||||||
|
|
||||||
/* Opcode have operands. */
|
/* Opcode have operands. */
|
||||||
if (*op)
|
if (*op)
|
||||||
@ -537,14 +595,29 @@ avr_operands (opcode, line)
|
|||||||
reg1 <<= 4;
|
reg1 <<= 4;
|
||||||
bin |= reg1 | reg2;
|
bin |= reg1 | reg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* detect undefined combinations (like lpm r31,Z+) */
|
||||||
|
if (((bin & 0xFDEF) == 0x91AD) || ((bin & 0xFDEF) == 0x91AE) ||
|
||||||
|
((bin & 0xFDEF) == 0x91C9) || ((bin & 0xFDEF) == 0x91CA) ||
|
||||||
|
((bin & 0xFDEF) == 0x91E1) || ((bin & 0xFDEF) == 0x91E2) ||
|
||||||
|
((bin & 0xFFED) == 0x91E5))
|
||||||
|
as_warn( _("undefined combination of operands"));
|
||||||
|
|
||||||
if (opcode->insn_size == 2)
|
if (opcode->insn_size == 2)
|
||||||
{
|
{
|
||||||
|
/* warn if previous opcode was cpse/sbic/sbis/sbrc/sbrs
|
||||||
|
(AVR core bug) */
|
||||||
|
if ((prev & 0xFC00) == 0x1000
|
||||||
|
|| (prev & 0xFD00) == 0x9900
|
||||||
|
|| (prev & 0xFC08) == 0xFC00)
|
||||||
|
as_warn (_("skipping two-word instruction"));
|
||||||
|
|
||||||
bfd_putl32 ((bfd_vma)bin, frag);
|
bfd_putl32 ((bfd_vma)bin, frag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
bfd_putl16 ((bfd_vma)bin, frag);
|
||||||
bfd_putl16 ((bfd_vma)bin, frag);
|
|
||||||
}
|
prev = bin;
|
||||||
*line = str;
|
*line = str;
|
||||||
return bin;
|
return bin;
|
||||||
}
|
}
|
||||||
@ -585,30 +658,62 @@ avr_operand (opcode, where, op, line)
|
|||||||
case 'w':
|
case 'w':
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'r':
|
case 'r':
|
||||||
|
case 'a':
|
||||||
|
case 'v':
|
||||||
{
|
{
|
||||||
char r_name[256];
|
char r_name[256];
|
||||||
|
op_mask = -1;
|
||||||
|
|
||||||
str = extract_word (str, r_name, sizeof (r_name));
|
str = extract_word (str, r_name, sizeof (r_name));
|
||||||
parse_exp (r_name, &op_expr);
|
if (r_name[0] == 'r' || r_name[0] == 'R')
|
||||||
if (op_expr.X_op == O_register)
|
|
||||||
{
|
{
|
||||||
op_mask = op_expr.X_add_number;
|
if (isdigit(r_name[1]))
|
||||||
if (op_mask <= 31)
|
|
||||||
{
|
{
|
||||||
if (*op == 'd')
|
if (r_name[2] == '\0')
|
||||||
{
|
op_mask = r_name[1] - '0';
|
||||||
if (op_mask < 16)
|
else if (r_name[1] != '0'
|
||||||
as_bad (_ ("register number above 15 required"));
|
&& isdigit(r_name[2])
|
||||||
op_mask -= 16;
|
&& r_name[3] == '\0')
|
||||||
}
|
op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
|
||||||
if (*op == 'w')
|
}
|
||||||
{
|
}
|
||||||
op_mask -= 24;
|
else
|
||||||
if (op_mask & 1 || op_mask > 6)
|
{
|
||||||
as_bad (_ ("register r24,r26,r28 or r30 required"));
|
parse_exp (r_name, &op_expr);
|
||||||
op_mask >>= 1;
|
if (op_expr.X_op == O_register)
|
||||||
}
|
op_mask = op_expr.X_add_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op_mask <= 31 && op_mask >= 0)
|
||||||
|
{
|
||||||
|
switch (*op)
|
||||||
|
{
|
||||||
|
case 'a':
|
||||||
|
if (op_mask < 16 || op_mask > 23)
|
||||||
|
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':
|
||||||
|
op_mask -= 24;
|
||||||
|
if (op_mask & 1 || op_mask > 6)
|
||||||
|
as_bad (_ ("register r24,r26,r28 or r30 required"));
|
||||||
|
op_mask >>= 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
as_bad (_ ("register required"));
|
as_bad (_ ("register required"));
|
||||||
}
|
}
|
||||||
@ -641,6 +746,23 @@ avr_operand (opcode, where, op, line)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
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 == '+')
|
||||||
|
{
|
||||||
|
++str;
|
||||||
|
op_mask |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
{
|
{
|
||||||
char c = tolower (*str++);
|
char c = tolower (*str++);
|
||||||
@ -877,11 +999,10 @@ md_apply_fix3 (fixp, valuep, seg)
|
|||||||
/* Instruction addresses are always right-shifted by 1. */
|
/* Instruction addresses are always right-shifted by 1. */
|
||||||
value >>= 1;
|
value >>= 1;
|
||||||
--value; /* Correct PC. */
|
--value; /* Correct PC. */
|
||||||
/* XXX AT90S8515 must have WRAP here. */
|
|
||||||
|
|
||||||
if (value < -2048 || value > 2047)
|
if (value < -2048 || value > 2047)
|
||||||
{
|
{
|
||||||
if (avr_mcu->mach == bfd_mach_avr2)
|
if (avr_mcu->isa & AVR_ISA_WRAP)
|
||||||
{
|
{
|
||||||
if (value > 2047)
|
if (value > 2047)
|
||||||
value -= 4096;
|
value -= 4096;
|
||||||
@ -1076,6 +1197,22 @@ md_assemble (str)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Special case for opcodes with optional operands (lpm, elpm) -
|
||||||
|
version with operands is listed in avr_opcodes[] with "x" suffix. */
|
||||||
|
|
||||||
|
if (*str && !(*opcode->constraints))
|
||||||
|
{
|
||||||
|
struct avr_opcodes_s *opc1;
|
||||||
|
|
||||||
|
/* known opcode, so strlen(op) <= 6 and strcat() should be safe */
|
||||||
|
strcat(op, "x");
|
||||||
|
opc1 = (struct avr_opcodes_s *) hash_find (avr_hash, op);
|
||||||
|
|
||||||
|
/* if unknown, just forget it and use the original opcode */
|
||||||
|
if (opc1)
|
||||||
|
opcode = opc1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((opcode->isa & avr_mcu->isa) != opcode->isa)
|
if ((opcode->isa & avr_mcu->isa) != opcode->isa)
|
||||||
as_bad (_ ("illegal opcode %s for mcu %s"), opcode->name, avr_mcu->name);
|
as_bad (_ ("illegal opcode %s for mcu %s"), opcode->name, avr_mcu->name);
|
||||||
|
|
||||||
@ -1084,7 +1221,7 @@ md_assemble (str)
|
|||||||
{
|
{
|
||||||
char *t = input_line_pointer;
|
char *t = input_line_pointer;
|
||||||
avr_operands (opcode, &str);
|
avr_operands (opcode, &str);
|
||||||
if (*str)
|
if (*skip_space (str))
|
||||||
as_bad (_ ("garbage at end of line"));
|
as_bad (_ ("garbage at end of line"));
|
||||||
input_line_pointer = t;
|
input_line_pointer = t;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user