Adds support for writing values to AVR system I/O registers.
* elf32-avr.c: Handle R_AVR_PORT5 and R_AVR_PORT6. * reloc.c: Add BFD_RELOC_AVR_PORT5 and BFD_RELOC_AVR_PORT6. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. * avr.h: Add R_AVR_PORT5 and R_AVR_PORT6. * config/tc-avr.c (avr_operand): Permit referring to r26-r31 by name as [xyz][hl]. Permit using a symbol whoes name begins with `r' to refer to a register. Allow arbitrary expressions for the P and p operators. (md_apply_fix): Check the BFD_RELOC_AVR_PORT5 and BFD_RELOC_AVR_PORT6 relocations.
This commit is contained in:
parent
38e229b2b3
commit
75f580857a
|
@ -1,3 +1,10 @@
|
|||
2014-07-07 Barney Stratford <barney_stratford@fastmail.fm>
|
||||
|
||||
* elf32-avr.c: Handle R_AVR_PORT5 and R_AVR_PORT6.
|
||||
* reloc.c: Add BFD_RELOC_AVR_PORT5 and BFD_RELOC_AVR_PORT6.
|
||||
* bfd-in2.h: Regenerate.
|
||||
* libbfd.h: Regenerate.
|
||||
|
||||
2014-07-04 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* Makefile.am: Update "configure.in" comments.
|
||||
|
|
|
@ -4480,6 +4480,14 @@ value. */
|
|||
lds and sts instructions supported only tiny core. */
|
||||
BFD_RELOC_AVR_LDS_STS_16,
|
||||
|
||||
/* This is a 6 bit reloc for the AVR that stores an I/O register
|
||||
number for the IN and OUT instructions */
|
||||
BFD_RELOC_AVR_PORT6,
|
||||
|
||||
/* This is a 5 bit reloc for the AVR that stores an I/O register
|
||||
number for the SBIC, SBIS, SBI and CBI instructions */
|
||||
BFD_RELOC_AVR_PORT5,
|
||||
|
||||
/* Renesas RL78 Relocations. */
|
||||
BFD_RELOC_RL78_NEG8,
|
||||
BFD_RELOC_RL78_NEG16,
|
||||
|
|
|
@ -613,7 +613,34 @@ static reloc_howto_type elf_avr_howto_table[] =
|
|||
FALSE, /* partial_inplace */
|
||||
0xffff, /* src_mask */
|
||||
0xffff, /* dst_mask */
|
||||
FALSE) /* pcrel_offset */
|
||||
FALSE), /* pcrel_offset */
|
||||
|
||||
HOWTO (R_AVR_PORT6, /* type */
|
||||
0, /* rightshift */
|
||||
0, /* size (0 = byte, 1 = short, 2 = long) */
|
||||
6, /* bitsize */
|
||||
FALSE, /* pc_relative */
|
||||
0, /* bitpos */
|
||||
complain_overflow_dont,/* complain_on_overflow */
|
||||
bfd_elf_generic_reloc, /* special_function */
|
||||
"R_AVR_PORT6", /* name */
|
||||
FALSE, /* partial_inplace */
|
||||
0xffffff, /* src_mask */
|
||||
0xffffff, /* dst_mask */
|
||||
FALSE), /* pcrel_offset */
|
||||
HOWTO (R_AVR_PORT5, /* type */
|
||||
0, /* rightshift */
|
||||
0, /* size (0 = byte, 1 = short, 2 = long) */
|
||||
5, /* bitsize */
|
||||
FALSE, /* pc_relative */
|
||||
0, /* bitpos */
|
||||
complain_overflow_dont,/* complain_on_overflow */
|
||||
bfd_elf_generic_reloc, /* special_function */
|
||||
"R_AVR_PORT5", /* name */
|
||||
FALSE, /* partial_inplace */
|
||||
0xffffff, /* src_mask */
|
||||
0xffffff, /* dst_mask */
|
||||
FALSE) /* pcrel_offset */
|
||||
};
|
||||
|
||||
/* Map BFD reloc types to AVR ELF reloc types. */
|
||||
|
@ -659,7 +686,9 @@ static const struct avr_reloc_map avr_reloc_map[] =
|
|||
{ BFD_RELOC_AVR_DIFF8, R_AVR_DIFF8 },
|
||||
{ BFD_RELOC_AVR_DIFF16, R_AVR_DIFF16 },
|
||||
{ BFD_RELOC_AVR_DIFF32, R_AVR_DIFF32 },
|
||||
{ BFD_RELOC_AVR_LDS_STS_16, R_AVR_LDS_STS_16}
|
||||
{ BFD_RELOC_AVR_LDS_STS_16, R_AVR_LDS_STS_16},
|
||||
{ BFD_RELOC_AVR_PORT6, R_AVR_PORT6},
|
||||
{ BFD_RELOC_AVR_PORT5, R_AVR_PORT5}
|
||||
};
|
||||
|
||||
/* Meant to be filled one day with the wrap around address for the
|
||||
|
@ -1248,6 +1277,26 @@ avr_final_link_relocate (reloc_howto_type * howto,
|
|||
bfd_put_16 (input_bfd, x, contents);
|
||||
break;
|
||||
|
||||
case R_AVR_PORT6:
|
||||
contents += rel->r_offset;
|
||||
srel = (bfd_signed_vma) relocation + rel->r_addend;
|
||||
if ((srel & 0xffff) > 0x3f)
|
||||
return bfd_reloc_outofrange;
|
||||
x = bfd_get_16 (input_bfd, contents);
|
||||
x = (x & 0xf9f0) | ((srel & 0x30) << 5) | (srel & 0x0f);
|
||||
bfd_put_16 (input_bfd, x, contents);
|
||||
break;
|
||||
|
||||
case R_AVR_PORT5:
|
||||
contents += rel->r_offset;
|
||||
srel = (bfd_signed_vma) relocation + rel->r_addend;
|
||||
if ((srel & 0xffff) > 0x1f)
|
||||
return bfd_reloc_outofrange;
|
||||
x = bfd_get_16 (input_bfd, contents);
|
||||
x = (x & 0xff07) | ((srel & 0x1f) << 3);
|
||||
bfd_put_16 (input_bfd, x, contents);
|
||||
break;
|
||||
|
||||
default:
|
||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||
contents, rel->r_offset,
|
||||
|
|
|
@ -2042,6 +2042,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
|
|||
"BFD_RELOC_AVR_DIFF16",
|
||||
"BFD_RELOC_AVR_DIFF32",
|
||||
"BFD_RELOC_AVR_LDS_STS_16",
|
||||
"BFD_RELOC_AVR_PORT6",
|
||||
"BFD_RELOC_AVR_PORT5",
|
||||
"BFD_RELOC_RL78_NEG8",
|
||||
"BFD_RELOC_RL78_NEG16",
|
||||
"BFD_RELOC_RL78_NEG24",
|
||||
|
|
10
bfd/reloc.c
10
bfd/reloc.c
|
@ -4794,6 +4794,16 @@ ENUM
|
|||
ENUMDOC
|
||||
This is a 7 bit reloc for the AVR that stores SRAM address for 16bit
|
||||
lds and sts instructions supported only tiny core.
|
||||
ENUM
|
||||
BFD_RELOC_AVR_PORT6
|
||||
ENUMDOC
|
||||
This is a 6 bit reloc for the AVR that stores an I/O register
|
||||
number for the IN and OUT instructions
|
||||
ENUM
|
||||
BFD_RELOC_AVR_PORT5
|
||||
ENUMDOC
|
||||
This is a 5 bit reloc for the AVR that stores an I/O register
|
||||
number for the SBIC, SBIS, SBI and CBI instructions
|
||||
ENUM
|
||||
BFD_RELOC_RL78_NEG8
|
||||
ENUMX
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2014-07-07 Barney Stratford <barney_stratford@fastmail.fm>
|
||||
|
||||
* config/tc-avr.c (avr_operand): Permit referring to r26-r31 by
|
||||
name as [xyz][hl]. Permit using a symbol whoes name begins with
|
||||
‘r’ to refer to a register.
|
||||
Allow arbitrary expressions for the P and p operators.
|
||||
(md_apply_fix): Check the BFD_RELOC_AVR_PORT5 and
|
||||
BFD_RELOC_AVR_PORT6 relocations.
|
||||
|
||||
2014-07-04 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* doc/internals.texi: Update "configure.in" comments.
|
||||
|
|
|
@ -345,8 +345,8 @@ 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 link_relax; /* -mlink-relax: generate relocations for linker
|
||||
relaxation. */
|
||||
int link_relax; /* -mlink-relax: generate relocations for linker
|
||||
relaxation. */
|
||||
};
|
||||
|
||||
static struct avr_opt_s avr_opt = { 0, 0, 0, 0 };
|
||||
|
@ -861,27 +861,40 @@ avr_operand (struct avr_opcodes_s *opcode,
|
|||
case 'r':
|
||||
case 'a':
|
||||
case 'v':
|
||||
if (*str == 'r' || *str == 'R')
|
||||
{
|
||||
char r_name[20];
|
||||
{
|
||||
char * old_str = str;
|
||||
char *lower;
|
||||
char r_name[20];
|
||||
|
||||
str = extract_word (str, r_name, sizeof (r_name));
|
||||
op_mask = 0xff;
|
||||
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])
|
||||
&& r_name[3] == '\0')
|
||||
op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
op_mask = avr_get_constant (str, 31);
|
||||
str = input_line_pointer;
|
||||
}
|
||||
str = extract_word (str, r_name, sizeof (r_name));
|
||||
for (lower = r_name; *lower; ++lower)
|
||||
{
|
||||
if (*lower >= 'A' && *lower <= 'Z')
|
||||
*lower += 'a' - 'A';
|
||||
}
|
||||
|
||||
if (r_name[0] == 'r' && ISDIGIT (r_name[1]) && r_name[2] == 0)
|
||||
/* Single-digit register number, ie r0-r9. */
|
||||
op_mask = r_name[1] - '0';
|
||||
else if (r_name[0] == 'r' && ISDIGIT (r_name[1])
|
||||
&& ISDIGIT (r_name[2]) && r_name[3] == 0)
|
||||
/* Double-digit register number, ie r10 - r32. */
|
||||
op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
|
||||
else if (r_name[0] >= 'x' && r_name[0] <= 'z'
|
||||
&& (r_name[1] == 'l' || r_name[1] == 'h') && r_name[2] == 0)
|
||||
/* Registers r26-r31 referred to by name, ie xl, xh, yl, yh, zl, zh. */
|
||||
op_mask = (r_name[0] - 'x') * 2 + (r_name[1] == 'h') + 26;
|
||||
else if ((*op == 'v' || *op == 'w')
|
||||
&& r_name[0] >= 'x' && r_name[0] <= 'z' && r_name[1] == 0)
|
||||
/* For the movw and addiw instructions, refer to registers x, y and z by name. */
|
||||
op_mask = (r_name[0] - 'x') * 2 + 26;
|
||||
else
|
||||
{
|
||||
/* Numeric or symbolic constant register number. */
|
||||
op_mask = avr_get_constant (old_str, 31);
|
||||
str = input_line_pointer;
|
||||
}
|
||||
}
|
||||
|
||||
if (avr_mcu->mach == bfd_mach_avrtiny)
|
||||
{
|
||||
|
@ -1080,23 +1093,15 @@ avr_operand (struct avr_opcodes_s *opcode,
|
|||
break;
|
||||
|
||||
case 'P':
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
x = avr_get_constant (str, 63);
|
||||
str = input_line_pointer;
|
||||
op_mask |= (x & 0xf) | ((x & 0x30) << 5);
|
||||
}
|
||||
str = parse_exp (str, &op_expr);
|
||||
fix_new_exp (frag_now, where, opcode->insn_size * 2,
|
||||
&op_expr, FALSE, BFD_RELOC_AVR_PORT6);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
x = avr_get_constant (str, 31);
|
||||
str = input_line_pointer;
|
||||
op_mask |= x << 3;
|
||||
}
|
||||
str = parse_exp (str, &op_expr);
|
||||
fix_new_exp (frag_now, where, opcode->insn_size * 2,
|
||||
&op_expr, FALSE, BFD_RELOC_AVR_PORT5);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
|
@ -1237,7 +1242,7 @@ relaxable_section (asection *sec)
|
|||
return (sec->flags & SEC_DEBUGGING) == 0;
|
||||
}
|
||||
|
||||
/* Does whatever the xtensa port does. */
|
||||
/* Does whatever the xtensa port does. */
|
||||
int
|
||||
avr_validate_fix_sub (fixS *fix)
|
||||
{
|
||||
|
@ -1267,7 +1272,7 @@ avr_validate_fix_sub (fixS *fix)
|
|||
|
||||
/* If linkrelax is turned on, and the symbol to relocate
|
||||
against is in a relaxable segment, don't compute the value -
|
||||
generate a relocation instead. */
|
||||
generate a relocation instead. */
|
||||
int
|
||||
avr_force_relocation (fixS *fix)
|
||||
{
|
||||
|
@ -1310,8 +1315,8 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
|
|||
expression. fixP->fx_addsy holds the section start symbol,
|
||||
fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
|
||||
holds sym1. Calculate the current difference and write value,
|
||||
but leave fx_offset as is - during relaxation,
|
||||
fx_offset - value gives sym1's value */
|
||||
but leave fx_offset as is - during relaxation,
|
||||
fx_offset - value gives sym1's value. */
|
||||
|
||||
switch (fixP->fx_r_type)
|
||||
{
|
||||
|
@ -1340,7 +1345,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
|
|||
|
||||
/* For the DIFF relocs, write the value into the object file while still
|
||||
keeping fx_done FALSE, as both the difference (recorded in the object file)
|
||||
and the sym offset (part of fixP) are needed at link relax time */
|
||||
and the sym offset (part of fixP) are needed at link relax time. */
|
||||
where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
|
||||
switch (fixP->fx_r_type)
|
||||
{
|
||||
|
@ -1548,6 +1553,20 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
|
|||
as_fatal (_("line %d: unknown relocation type: 0x%x"),
|
||||
fixP->fx_line, fixP->fx_r_type);
|
||||
break;
|
||||
|
||||
case BFD_RELOC_AVR_PORT6:
|
||||
if (value > 63)
|
||||
as_bad_where (fixP->fx_file, fixP->fx_line,
|
||||
_("operand out of range: %ld"), value);
|
||||
bfd_putl16 ((bfd_vma) insn | ((value & 0x30) << 5) | (value & 0x0f), where);
|
||||
break;
|
||||
|
||||
case BFD_RELOC_AVR_PORT5:
|
||||
if (value > 31)
|
||||
as_bad_where (fixP->fx_file, fixP->fx_line,
|
||||
_("operand out of range: %ld"), value);
|
||||
bfd_putl16 ((bfd_vma) insn | ((value & 0x1f) << 3), where);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1628,9 +1647,9 @@ md_assemble (char *str)
|
|||
|
||||
if (opcode && !avr_opt.all_opcodes)
|
||||
{
|
||||
/* Check if the instruction's ISA bit is ON in the ISA bits of the part
|
||||
/* Check if the instruction's ISA bit is ON in the ISA bits of the part
|
||||
specified by the user. If not look for other instructions
|
||||
specifications with same mnemonic who's ISA bits matches.
|
||||
specifications with same mnemonic who's ISA bits matches.
|
||||
|
||||
This requires include/opcode/avr.h to have the instructions with
|
||||
same mnenomic to be specified in sequence. */
|
||||
|
@ -1638,15 +1657,15 @@ md_assemble (char *str)
|
|||
while ((opcode->isa & avr_mcu->isa) != opcode->isa)
|
||||
{
|
||||
opcode++;
|
||||
|
||||
|
||||
if (opcode->name && strcmp(op, opcode->name))
|
||||
{
|
||||
as_bad (_("illegal opcode %s for mcu %s"),
|
||||
as_bad (_("illegal opcode %s for mcu %s"),
|
||||
opcode->name, avr_mcu->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opcode == NULL)
|
||||
{
|
||||
|
@ -1786,10 +1805,10 @@ avr_cons_fix_new (fragS *frag,
|
|||
static bfd_boolean
|
||||
mcu_has_3_byte_pc (void)
|
||||
{
|
||||
int mach = avr_mcu->mach;
|
||||
int mach = avr_mcu->mach;
|
||||
|
||||
return mach == bfd_mach_avr6
|
||||
|| mach == bfd_mach_avrxmega6
|
||||
return mach == bfd_mach_avr6
|
||||
|| mach == bfd_mach_avrxmega6
|
||||
|| mach == bfd_mach_avrxmega7;
|
||||
}
|
||||
|
||||
|
@ -1813,7 +1832,7 @@ avr_allow_local_subtract (expressionS * left,
|
|||
expressionS * right,
|
||||
segT section)
|
||||
{
|
||||
/* If we are not in relaxation mode, subtraction is OK. */
|
||||
/* If we are not in relaxation mode, subtraction is OK. */
|
||||
if (!linkrelax)
|
||||
return TRUE;
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2014-07-07 Barney Stratford <barney_stratford@fastmail.fm>
|
||||
|
||||
* avr.h: Add R_AVR_PORT5 and R_AVR_PORT6.
|
||||
|
||||
2014-07-01 Barney Stratford <barney_stratford@fastmail.fm>
|
||||
Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
|
||||
Pitchumani Sivanupandi <pitchumani.s@atmel.com>
|
||||
|
|
|
@ -85,6 +85,8 @@ START_RELOC_NUMBERS (elf_avr_reloc_type)
|
|||
RELOC_NUMBER (R_AVR_DIFF16, 31)
|
||||
RELOC_NUMBER (R_AVR_DIFF32, 32)
|
||||
RELOC_NUMBER (R_AVR_LDS_STS_16, 33)
|
||||
RELOC_NUMBER (R_AVR_PORT6, 34)
|
||||
RELOC_NUMBER (R_AVR_PORT5, 35)
|
||||
END_RELOC_NUMBERS (R_AVR_max)
|
||||
|
||||
#endif /* _ELF_AVR_H */
|
||||
|
|
Loading…
Reference in New Issue