/* tc-epiphany.c -- Assembler for the Adapteva EPIPHANY
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2019 Free Software Foundation, Inc.
Contributed by Embecosm on behalf of Adapteva, Inc.
This file is part of GAS, the GNU Assembler.
#include "elf/common.h"
#include "elf/epiphany.h"
#include "dwarf2dbg.h"
-#include "libbfd.h"
/* Structure to hold all of the different components describing
an individual instruction. */
if (force_code_align)
{
- /* The s_align_ptwo function expects that we are just after a .align
- directive and it will either try and read the align value or stop
- if end of line so we must fake it out so it thinks we are at the
- end of the line. */
- char *old_input_line_pointer = input_line_pointer;
-
- input_line_pointer = "\n";
- s_align_ptwo (1);
+ do_align (1, NULL, 0, 0);
force_code_align = FALSE;
-
- /* Restore. */
- input_line_pointer = old_input_line_pointer;
}
}
static void
epiphany_elf_section_text (int i)
{
- char *old_input_line_pointer;
-
obj_elf_text (i);
- /* The s_align_ptwo function expects that we are just after a .align
- directive and it will either try and read the align value or stop if
- end of line so we must fake it out so it thinks we are at the end of
- the line. */
- old_input_line_pointer = input_line_pointer;
- input_line_pointer = "\n";
- s_align_ptwo (1);
+ do_align (1, NULL, 0, 0);
force_code_align = FALSE;
- /* Restore. */
- input_line_pointer = old_input_line_pointer;
}
/* The target specific pseudo-ops which we support. */
const char * md_shortopts = "";
int
-md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED)
{
return 0; /* No target-specific options. */
}
/* Set the machine type. */
bfd_default_set_arch_mach (stdoutput, bfd_arch_epiphany, bfd_mach_epiphany32);
+
+ literal_prefix_dollar_hex = TRUE;
}
valueT
md_section_align (segT segment, valueT size)
{
- int align = bfd_get_section_alignment (stdoutput, segment);
+ int align = bfd_section_alignment (segment);
- return ((size + (1 << align) - 1) & (-1 << align));
+ return ((size + (1 << align) - 1) & -(1 << align));
}
\f
case BFD_RELOC_EPIPHANY_HIGH:
value >>= 16;
- /* fall thru */
+ /* fallthru */
case BFD_RELOC_EPIPHANY_LOW:
value = (((value & 0xff) << 5) | insn[0])
| (insn[1] << 8)
}
\f
/* Read a comma separated incrementing list of register names
- and form a bit mask of upto 15 registers 0..14. */
+ and form a bit mask of up to 15 registers 0..14. */
static const char *
parse_reglist (const char * s, int * mask)
}
\f
-void
-md_assemble (char *str)
-{
+/* Assemble an instruction, push and pop pseudo instructions should have
+ already been expanded. */
+
+static void
+epiphany_assemble (const char *str)
+ {
epiphany_insn insn;
char *errmsg = 0;
- const char * pperr = 0;
- int regmask=0, push=0, pop=0;
memset (&insn, 0, sizeof (insn));
- /* Special-case push/pop instruction macros. */
- if (0 == strncmp (str, "push {", 6))
- {
- char * s = str + 6;
- push = 1;
- pperr = parse_reglist (s, ®mask);
- }
- else if (0 == strncmp (str, "pop {", 5))
- {
- char * s = str + 5;
- pop = 1;
- pperr = parse_reglist (s, ®mask);
- }
-
- if (pperr)
- {
- as_bad ("%s", pperr);
- return;
- }
-
- if (push && regmask)
- {
- char buff[20];
- int i,p ATTRIBUTE_UNUSED;
-
- md_assemble ("mov r15,4");
- md_assemble ("sub sp,sp,r15");
-
- for (i = 0, p = 1; i <= 15; ++i, regmask >>= 1)
- {
- if (regmask == 1)
- sprintf (buff, "str r%d,[sp]", i); /* Last one. */
- else if (regmask & 1)
- sprintf (buff, "str r%d,[sp],-r15", i);
- else
- continue;
- md_assemble (buff);
- }
- return;
- }
- else if (pop && regmask)
- {
- char buff[20];
- int i,p;
-
- md_assemble ("mov r15,4");
-
- for (i = 15, p = 1 << 15; i >= 0; --i, p >>= 1)
- if (regmask & p)
- {
- sprintf (buff, "ldr r%d,[sp],+r15", i);
- md_assemble (buff);
- }
- return;
- }
-
/* Initialize GAS's cgen interface for a new instruction. */
gas_cgen_init_parse ();
#define DISPMOD _("destination register modified by displacement-post-modified address")
#define LDSTODD _("ldrd/strd requires even:odd register pair")
- /* Helper macros for spliting apart instruction fields. */
+ /* Helper macros for splitting apart instruction fields. */
#define ADDR_POST_MODIFIED(i) (((i) >> 25) & 0x1)
#define ADDR_SIZE(i) (((i) >> 5) & 3)
#define ADDR_LOADSTORE(i) (((i) >> 4) & 0x1)
return;
}
}
- /* fall-thru. */
+ /* fallthru */
case OP4_LDSTRX:
{
}
}
+void
+md_assemble (char *str)
+{
+ const char * pperr = 0;
+ int regmask=0, push=0, pop=0;
+
+ /* Special-case push/pop instruction macros. */
+ if (0 == strncmp (str, "push {", 6))
+ {
+ char * s = str + 6;
+ push = 1;
+ pperr = parse_reglist (s, ®mask);
+ }
+ else if (0 == strncmp (str, "pop {", 5))
+ {
+ char * s = str + 5;
+ pop = 1;
+ pperr = parse_reglist (s, ®mask);
+ }
+
+ if (pperr)
+ {
+ as_bad ("%s", pperr);
+ return;
+ }
+
+ if (push && regmask)
+ {
+ char buff[20];
+ int i,p ATTRIBUTE_UNUSED;
+
+ epiphany_assemble ("mov r15,4");
+ epiphany_assemble ("sub sp,sp,r15");
+
+ for (i = 0, p = 1; i <= 15; ++i, regmask >>= 1)
+ {
+ if (regmask == 1)
+ sprintf (buff, "str r%d,[sp]", i); /* Last one. */
+ else if (regmask & 1)
+ sprintf (buff, "str r%d,[sp],-r15", i);
+ else
+ continue;
+ epiphany_assemble (buff);
+ }
+ return;
+ }
+ else if (pop && regmask)
+ {
+ char buff[20];
+ int i,p;
+
+ epiphany_assemble ("mov r15,4");
+
+ for (i = 15, p = 1 << 15; i >= 0; --i, p >>= 1)
+ if (regmask & p)
+ {
+ sprintf (buff, "ldr r%d,[sp],+r15", i);
+ epiphany_assemble (buff);
+ }
+ return;
+ }
+
+ epiphany_assemble (str);
+}
+
/* The syntax in the manual says constants begin with '#'.
We just ignore it. */
handling to md_convert_frag. */
EPIPHANY_RELAX_TYPES subtype;
+ const CGEN_INSN *insn;
+ int i;
/* We haven't relaxed this at all, so the relaxation type may be
completely wrong. Set the subtype correctly. */
epiphany_relax_frag (segment, fragP, 0);
fragP->fr_subtype = subtype;
- {
- const CGEN_INSN *insn;
- int i;
-
- /* Update the recorded insn. */
+ /* Update the recorded insn. */
+ for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
+ {
+ if (strcmp (CGEN_INSN_MNEMONIC (insn),
+ CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn)) == 0
+ && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
+ break;
+ }
- for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
- {
- if ((strcmp (CGEN_INSN_MNEMONIC (insn),
- CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
- == 0)
- && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
- break;
- }
+ if (i == 4)
+ abort ();
- if (i == 4)
- abort ();
+ /* When changing from a 2-byte to 4-byte insn, don't leave
+ opcode bytes uninitialised. */
+ if (CGEN_INSN_BITSIZE (fragP->fr_cgen.insn) < CGEN_INSN_BITSIZE (insn))
+ {
+ gas_assert (CGEN_INSN_BITSIZE (fragP->fr_cgen.insn) == 16);
+ gas_assert (CGEN_INSN_BITSIZE (insn) == 32);
+ fragP->fr_opcode[2] = 0;
+ fragP->fr_opcode[3] = 0;
+ }
- fragP->fr_cgen.insn = insn;
- }
+ fragP->fr_cgen.insn = insn;
}
return md_relax_table[fragP->fr_subtype].rlx_length;
return BFD_RELOC_EPIPHANY_LOW;
else
as_bad ("unknown imm16 operand");
- /* fall-thru */
+ /* fallthru */
default:
break;
of LITTLENUMS emitted is stored in *SIZEP. An error message is
returned, or NULL on OK. */
-/* Equal to MAX_PRECISION in atof-ieee.c. */
-#define MAX_LITTLENUMS 6
-
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
return ieee_md_atof (type, litP, sizeP, FALSE);
return FALSE;
/* Since we don't use partial_inplace, we must not reduce symbols in
- mergable sections to their section symbol. */
+ mergeable sections to their section symbol. */
if ((S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0)
return FALSE;