#define U0x80000000 ((((unsigned long) 1 << 16) << 15))
static int sparc_ip (char *, const struct sparc_opcode **);
+static int parse_sparc_asi (char **, const sparc_asi **);
static int parse_keyword_arg (int (*) (const char *), char **, int *);
static int parse_const_expr_arg (char **, int *);
static int get_expression (char *);
{ "sparc4", "v9v", v9, 0, 1, 0, 0 },
{ "sparc5", "v9m", v9, 0, 1, 0, 0 },
+ { "sparc6", "m8", v9, 0, 1, 0, 0 },
{ "leon", "leon", leon, 32, 1, 0, 0 },
{ "sparclet", "sparclet", sparclet, 32, 1, 0, 0 },
{ "v8pluse", "v9e", v9, 0, 1, HWCAP_V8PLUS, 0 },
{ "v8plusv", "v9v", v9, 0, 1, HWCAP_V8PLUS, 0 },
{ "v8plusm", "v9m", v9, 0, 1, HWCAP_V8PLUS, 0 },
-
+ { "v8plusm8", "m8", v9, 0, 1, HWCAP_V8PLUS, 0 },
+
{ "v9", "v9", v9, 0, 1, 0, 0 },
{ "v9a", "v9a", v9, 0, 1, 0, 0 },
{ "v9b", "v9b", v9, 0, 1, 0, 0 },
{ "v9e", "v9e", v9, 0, 1, 0, 0 },
{ "v9v", "v9v", v9, 0, 1, 0, 0 },
{ "v9m", "v9m", v9, 0, 1, 0, 0 },
+ { "v9m8", "m8", v9, 0, 1, 0, 0 },
/* This exists to allow configure.tgt to pass one
value to specify both the default machine and default word size. */
p->pop = &pop_table[i];
}
- /* Last entry is the centinel. */
+ /* Last entry is the sentinel. */
perc_table[entry].type = perc_entry_none;
qsort (perc_table, sizeof (perc_table) / sizeof (perc_table[0]),
case SPARC_OPCODE_ARCH_V9E: mach = bfd_mach_sparc_v9e; break;
case SPARC_OPCODE_ARCH_V9V: mach = bfd_mach_sparc_v9v; break;
case SPARC_OPCODE_ARCH_V9M: mach = bfd_mach_sparc_v9m; break;
+ case SPARC_OPCODE_ARCH_M8: mach = bfd_mach_sparc_v9m8; break;
default: mach = bfd_mach_sparc_v9; break;
}
else
case SPARC_OPCODE_ARCH_V9E: mach = bfd_mach_sparc_v8pluse; break;
case SPARC_OPCODE_ARCH_V9V: mach = bfd_mach_sparc_v8plusv; break;
case SPARC_OPCODE_ARCH_V9M: mach = bfd_mach_sparc_v8plusm; break;
+ case SPARC_OPCODE_ARCH_M8: mach = bfd_mach_sparc_v8plusm8; break;
/* The sparclite is treated like a normal sparc. Perhaps it shouldn't
be but for now it is (since that's the way it's always been
treated). */
return "xmont";
if (mask & HWCAP2_NSEC)
return "nsec";
+ if (mask & HWCAP2_SPARC6)
+ return "sparc6";
+ if (mask & HWCAP2_ONADDSUB)
+ return "onaddsub";
+ if (mask & HWCAP2_ONMUL)
+ return "onmul";
+ if (mask & HWCAP2_ONDIV)
+ return "ondiv";
+ if (mask & HWCAP2_DICTUNP)
+ return "dictunp";
+ if (mask & HWCAP2_FPCMPSHL)
+ return "fpcmpshl";
+ if (mask & HWCAP2_RLE)
+ return "rle";
+ if (mask & HWCAP2_SHA3)
+ return "sha3";
return "UNKNOWN";
}
int comma = 0;
int v9_arg_p;
int special_case = SPECIAL_CASE_NONE;
+ const sparc_asi *sasi = NULL;
s = str;
if (ISLOWER (*s))
case 'e': /* next operand is a floating point register */
case 'v':
case 'V':
+ case ';':
case 'f':
case 'B':
case 'R':
+ case ':':
+ case '\'':
case '4':
case '5':
case 'H':
case 'J':
case '}':
+ case '^':
{
char format;
|| *args == 'B'
|| *args == '5'
|| *args == 'H'
+ || *args == '\''
|| format == 'd')
&& (mask & 1))
{
break;
}
+ if ((*args == ':'
+ || *args == ';'
+ || *args == '^')
+ && (mask & 7))
+ {
+ /* register must be multiple of 8 */
+ break;
+ }
+
+ if (*args == '\'' && mask < 48)
+ {
+ /* register must be higher or equal than %f48 */
+ break;
+ }
+
if (mask >= 64)
{
if (SPARC_OPCODE_ARCH_V9_P (max_architecture))
case 'v':
case 'V':
case 'e':
+ case ';':
opcode |= RS1 (mask);
continue;
case 'f':
case 'B':
case 'R':
+ case ':':
opcode |= RS2 (mask);
continue;
+ case '\'':
+ opcode |= RS2 (mask & 0xe);
+ continue;
+
case '4':
case '5':
opcode |= RS3 (mask);
case 'H':
case 'J':
case '}':
+ case '^':
opcode |= RD (mask);
continue;
} /* Pack it in. */
/* Parse an asi. */
if (*s == '#')
{
- if (! parse_keyword_arg (sparc_encode_asi, &s, &asi))
+ if (! parse_sparc_asi (&s, &sasi))
{
error_message = _(": invalid ASI name");
goto error;
}
+ asi = sasi->value;
}
else
{
s += 7;
continue;
+ case '&':
+ if (strncmp (s, "%entropy", 8) != 0)
+ break;
+ s += 8;
+ continue;
+
case 'E':
if (strncmp (s, "%ccr", 4) != 0)
break;
s += 4;
continue;
+ case '|':
+ {
+ int imm2 = 0;
+
+ /* Parse a 2-bit immediate. */
+ if (! parse_const_expr_arg (&s, &imm2))
+ {
+ error_message = _(": non-immdiate imm2 operand");
+ goto error;
+ }
+ if ((imm2 & ~0x3) != 0)
+ {
+ error_message = _(": imm2 immediate operand out of range (0-3)");
+ goto error;
+ }
+
+ opcode |= ((imm2 & 0x2) << 3) | (imm2 & 0x1);
+ continue;
+ }
+
case 'x':
{
char *push = input_line_pointer;
else
{
/* We have a match. Now see if the architecture is OK. */
+ /* String to use in case of architecture warning. */
+ const char *msg_str = str;
int needed_arch_mask = insn->architecture;
- bfd_uint64_t hwcaps
+
+ /* Include the ASI architecture needed as well */
+ if (sasi && needed_arch_mask > sasi->architecture)
+ {
+ needed_arch_mask = sasi->architecture;
+ msg_str = sasi->name;
+ }
+
+ bfd_uint64_t hwcaps
= (((bfd_uint64_t) insn->hwcaps2) << 32) | insn->hwcaps;
#if defined(OBJ_ELF) && !defined(TE_SOLARIS)
as_warn (_("architecture bumped from \"%s\" to \"%s\" on \"%s\""),
sparc_opcode_archs[current_architecture].name,
sparc_opcode_archs[needed_architecture].name,
- str);
+ msg_str);
warn_after_architecture = needed_architecture;
}
current_architecture = needed_architecture;
}
as_bad (_("Architecture mismatch on \"%s %s\"."), str, argsStart);
- as_tsktsk (_(" (Requires %s; requested architecture is %s.)"),
+ as_tsktsk (_("(Requires %s; requested architecture is %s.)"),
required_archs,
sparc_opcode_archs[max_architecture].name);
return special_case;
return special_case;
}
+static char *
+skip_over_keyword (char *q)
+{
+ for (q = q + (*q == '#' || *q == '%');
+ ISALNUM (*q) || *q == '_';
+ ++q)
+ continue;
+ return q;
+}
+
+static int
+parse_sparc_asi (char **input_pointer_p, const sparc_asi **value_p)
+{
+ const sparc_asi *value;
+ char c, *p, *q;
+
+ p = *input_pointer_p;
+ q = skip_over_keyword(p);
+ c = *q;
+ *q = 0;
+ value = sparc_encode_asi (p);
+ *q = c;
+ if (value == NULL)
+ return 0;
+ *value_p = value;
+ *input_pointer_p = q;
+ return 1;
+}
+
/* Parse an argument that can be expressed as a keyword.
(eg: #StoreStore or %ccfr).
The result is a boolean indicating success.
char c, *p, *q;
p = *input_pointerP;
- for (q = p + (*p == '#' || *p == '%');
- ISALNUM (*q) || *q == '_';
- ++q)
- continue;
+ q = skip_over_keyword(p);
c = *q;
*q = 0;
value = (*lookup_fn) (p);
insn |= val & 0x3fffffff;
- /* See if we have a delay slot. */
- if (sparc_relax && fixP->fx_where + 8 <= fixP->fx_frag->fr_fix)
+ /* See if we have a delay slot. In that case we attempt to
+ optimize several cases transforming CALL instructions
+ into branches. But we can only do that if the relocation
+ can be completely resolved here, i.e. if no undefined
+ symbol is associated with it. */
+ if (sparc_relax && fixP->fx_addsy == NULL
+ && fixP->fx_where + 8 <= fixP->fx_frag->fr_fix)
{
#define G0 0
#define O7 15
switch (fixp->fx_r_type)
{
+ case BFD_RELOC_8:
case BFD_RELOC_16:
case BFD_RELOC_32:
+ case BFD_RELOC_64:
+ if (fixp->fx_pcrel)
+ {
+ switch (fixp->fx_size)
+ {
+ default:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("can not do %d byte pc-relative relocation"),
+ fixp->fx_size);
+ code = fixp->fx_r_type;
+ fixp->fx_pcrel = 0;
+ break;
+ case 1: code = BFD_RELOC_8_PCREL; break;
+ case 2: code = BFD_RELOC_16_PCREL; break;
+ case 4: code = BFD_RELOC_32_PCREL; break;
+#ifdef BFD64
+ case 8: code = BFD_RELOC_64_PCREL; break;
+#endif
+ }
+ if (fixp->fx_pcrel)
+ fixp->fx_addnumber = fixp->fx_offset;
+ break;
+ }
+ /* Fall through. */
case BFD_RELOC_HI22:
case BFD_RELOC_LO10:
case BFD_RELOC_32_PCREL_S2:
case BFD_RELOC_SPARC_WDISP16:
case BFD_RELOC_SPARC_WDISP19:
case BFD_RELOC_SPARC_WDISP22:
- case BFD_RELOC_64:
case BFD_RELOC_SPARC_5:
case BFD_RELOC_SPARC_6:
case BFD_RELOC_SPARC_7: