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:
Barney Stratford 2014-07-07 16:15:19 +01:00 committed by Nick Clifton
parent 38e229b2b3
commit 75f580857a
9 changed files with 162 additions and 52 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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,

View File

@ -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",

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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>

View File

@ -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 */