aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorBarney Stratford <barney_stratford@fastmail.fm>2014-07-07 16:15:19 +0100
committerNick Clifton <nickc@redhat.com>2014-07-07 16:15:19 +0100
commit75f580857a7c65525a98a701c65d0814be04155f (patch)
tree48b3d0d2c727ec1d4cdfddb5d847fbf30bafdeb9 /gas/config
parent38e229b2b3b5cc28c40ae114146bcdb45f60fc46 (diff)
downloadgdb-75f580857a7c65525a98a701c65d0814be04155f.zip
gdb-75f580857a7c65525a98a701c65d0814be04155f.tar.gz
gdb-75f580857a7c65525a98a701c65d0814be04155f.tar.bz2
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.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-avr.c119
1 files changed, 69 insertions, 50 deletions
diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c
index 9ed7de8..dfe66c6 100644
--- a/gas/config/tc-avr.c
+++ b/gas/config/tc-avr.c
@@ -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;