/* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU)
- Copyright 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006-2015 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
unsigned int opcode;
expressionS exp[MAX_RELOCS];
int reloc_arg[MAX_RELOCS];
- int flag[MAX_RELOCS];
+ bfd_reloc_code_real_type reloc[MAX_RELOCS];
enum spu_insns tag;
};
int accept_expr);
static int calcop (struct spu_opcode *format, const char *param,
struct spu_insn *insn);
+static void spu_brinfo (int);
static void spu_cons (int);
extern char *myname;
const pseudo_typeS md_pseudo_table[] =
{
{"align", s_align_ptwo, 4},
+ {"brinfo", spu_brinfo, 0},
{"bss", s_lcomm_bytes, 1},
{"def", s_set, 0},
{"dfloat", float_cons, 'd'},
{"int", spu_cons, 4},
{"long", spu_cons, 4},
{"quad", spu_cons, 8},
- {"string", stringer, 1},
+ {"string", stringer, 8 + 1},
{"word", spu_cons, 4},
/* Force set to be treated as an instruction. */
{"set", NULL, 0},
/* Likewise for eqv. */
{"eqv", NULL, 0},
{".eqv", s_set, -1},
- {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
- {"loc", dwarf2_directive_loc, 0},
{0,0,0}
};
+/* Bits plugged into branch instruction offset field. */
+unsigned int brinfo;
+
void
md_begin (void)
{
{
/* hash each mnemonic and record its position */
- retval = hash_insert (op_hash, spu_opcodes[i].mnemonic, (PTR)&spu_opcodes[i]);
+ retval = hash_insert (op_hash, spu_opcodes[i].mnemonic,
+ (void *) &spu_opcodes[i]);
if (retval != NULL && strcmp (retval, "exists") != 0)
as_fatal (_("Can't hash instruction '%s':%s"),
struct spu_insn insn;
int i;
- assert (op);
+ gas_assert (op);
/* skip over instruction to find parameters */
insn.exp[i].X_add_number = 0;
insn.exp[i].X_op = O_illegal;
insn.reloc_arg[i] = -1;
- insn.flag[i] = 0;
+ insn.reloc[i] = BFD_RELOC_NONE;
}
insn.opcode = format->opcode;
insn.tag = (enum spu_insns) (format - spu_opcodes);
as_warn (_("Treating '%-*s' as a symbol."), (int)(syntax_error_param - d), d);
}
+ if (brinfo != 0
+ && (insn.tag <= M_BRASL
+ || (insn.tag >= M_BRZ && insn.tag <= M_BRHNZ))
+ && (insn.opcode & 0x7ff80) == 0
+ && (insn.reloc_arg[0] == A_R18
+ || insn.reloc_arg[0] == A_S18
+ || insn.reloc_arg[1] == A_R18
+ || insn.reloc_arg[1] == A_S18))
+ insn.opcode |= brinfo << 7;
+
/* grow the current frag and plop in the opcode */
thisfrag = frag_more (4);
if (insn.reloc_arg[i] >= 0)
{
fixS *fixP;
- bfd_reloc_code_real_type reloc = arg_encode[insn.reloc_arg[i]].reloc;
+ bfd_reloc_code_real_type reloc = insn.reloc[i];
int pcrel = 0;
- if (reloc == BFD_RELOC_SPU_PCREL9a
+ if (reloc == BFD_RELOC_SPU_PCREL9a
|| reloc == BFD_RELOC_SPU_PCREL9b
- || reloc == BFD_RELOC_SPU_PCREL16)
+ || reloc == BFD_RELOC_SPU_PCREL16)
pcrel = 1;
- if (insn.flag[i] == 1)
- reloc = BFD_RELOC_SPU_HI16;
- else if (insn.flag[i] == 2)
- reloc = BFD_RELOC_SPU_LO16;
fixP = fix_new_exp (frag_now,
thisfrag - frag_now->fr_literal,
4,
fixP->tc_fix_data.insn_tag = insn.tag;
}
dwarf2_emit_insn (4);
+
+ /* .brinfo lasts exactly one instruction. */
+ brinfo = 0;
}
static int
if (arg < A_P)
param = get_reg (param, insn, arg, 1);
else if (arg > A_P)
- param = get_imm (param, insn, arg);
+ param = get_imm (param, insn, arg);
else if (arg == A_P)
{
paren++;
insn->opcode |= (((val >> arg_encode[arg].rshift)
& ((1 << arg_encode[arg].size) - 1))
<< arg_encode[arg].pos);
- insn->reloc_arg[reloc_i] = -1;
- insn->flag[reloc_i] = 0;
}
else
{
insn->reloc_arg[reloc_i] = arg;
if (high)
- insn->flag[reloc_i] = 1;
+ insn->reloc[reloc_i] = BFD_RELOC_SPU_HI16;
else if (low)
- insn->flag[reloc_i] = 2;
+ insn->reloc[reloc_i] = BFD_RELOC_SPU_LO16;
+ else
+ insn->reloc[reloc_i] = arg_encode[arg].reloc;
}
return param;
}
-#define MAX_LITTLENUMS 6
-
-/* Turn a string in input_line_pointer into a floating point constant of type
- type, and store the appropriate bytes in *litP. The number of LITTLENUMS
- emitted is stored in *sizeP . An error message is returned, or NULL on OK.
- */
char *
md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[MAX_LITTLENUMS];
- LITTLENUM_TYPE *wordP;
- char *t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- case 's':
- case 'S':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- prec = 4;
- break;
-
- case 'x':
- case 'X':
- prec = 6;
- break;
-
- case 'p':
- case 'P':
- prec = 6;
- break;
-
- default:
- *sizeP = 0;
- return _("Bad call to MD_ATOF()");
- }
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * sizeof (LITTLENUM_TYPE);
- for (wordP = words; prec--;)
- {
- md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- return 0;
+ return ieee_md_atof (type, litP, sizeP, TRUE);
}
#ifndef WORKING_DOT_WORD
}
#endif
+/* Handle .brinfo <priority>,<lrlive>. */
+static void
+spu_brinfo (int ignore ATTRIBUTE_UNUSED)
+{
+ addressT priority;
+ addressT lrlive;
+
+ priority = get_absolute_expression ();
+ SKIP_WHITESPACE ();
+
+ lrlive = 0;
+ if (*input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ lrlive = get_absolute_expression ();
+ }
+
+ if (priority > 0x1fff)
+ {
+ as_bad (_("invalid priority '%lu'"), (unsigned long) priority);
+ priority = 0;
+ }
+
+ if (lrlive > 7)
+ {
+ as_bad (_("invalid lrlive '%lu'"), (unsigned long) lrlive);
+ lrlive = 0;
+ }
+
+ brinfo = (lrlive << 13) | priority;
+ demand_empty_rest_of_line ();
+}
+
/* Support @ppu on symbols referenced in .int/.long/.word/.quad. */
static void
spu_cons (int nbytes)
do
{
- expression (&exp);
- if (exp.X_op == O_symbol
+ deferred_expression (&exp);
+ if ((exp.X_op == O_symbol
+ || exp.X_op == O_constant)
&& strncasecmp (input_line_pointer, "@ppu", 4) == 0)
{
char *p = frag_more (nbytes);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
else if (fixp->fx_subsy)
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+ else
+ abort ();
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == (reloc_howto_type *) NULL)
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
unsigned int res;
+ unsigned int mask;
valueT val = *valP;
char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
fixP->fx_addnumber = val;
+ if (fixP->fx_r_type == BFD_RELOC_SPU_PPU32
+ || fixP->fx_r_type == BFD_RELOC_SPU_PPU64
+ || fixP->fx_r_type == BFD_RELOC_SPU_ADD_PIC)
+ return;
+
if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
{
fixP->fx_done = 1;
res = 0;
+ mask = 0;
if (fixP->tc_fix_data.arg_format > A_P)
{
int hi = arg_encode[fixP->tc_fix_data.arg_format].hi;
int lo = arg_encode[fixP->tc_fix_data.arg_format].lo;
if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi))
as_bad_where (fixP->fx_file, fixP->fx_line,
- "Relocation doesn't fit. (relocation value = 0x%lx)",
+ _("Relocation doesn't fit. (relocation value = 0x%lx)"),
(long) val);
}
switch (fixP->fx_r_type)
- {
- case BFD_RELOC_8:
+ {
+ case BFD_RELOC_8:
md_number_to_chars (place, val, 1);
return;
- case BFD_RELOC_16:
+ case BFD_RELOC_16:
md_number_to_chars (place, val, 2);
return;
- case BFD_RELOC_32:
+ case BFD_RELOC_32:
+ case BFD_RELOC_32_PCREL:
md_number_to_chars (place, val, 4);
return;
- case BFD_RELOC_64:
+ case BFD_RELOC_64:
md_number_to_chars (place, val, 8);
return;
- case BFD_RELOC_SPU_IMM7:
- res = (val & 0x7f) << 14;
- break;
-
- case BFD_RELOC_SPU_IMM8:
- res = (val & 0xff) << 14;
- break;
-
- case BFD_RELOC_SPU_IMM10:
- res = (val & 0x3ff) << 14;
- break;
-
- case BFD_RELOC_SPU_IMM10W:
- res = (val & 0x3ff0) << 10;
- break;
-
- case BFD_RELOC_SPU_IMM16:
- res = (val & 0xffff) << 7;
- break;
-
- case BFD_RELOC_SPU_IMM16W:
- res = (val & 0x3fffc) << 5;
- break;
-
- case BFD_RELOC_SPU_IMM18:
- res = (val & 0x3ffff) << 7;
- break;
-
- case BFD_RELOC_SPU_PCREL9a:
- res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14);
- break;
-
- case BFD_RELOC_SPU_PCREL9b:
- res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5);
- break;
-
- case BFD_RELOC_SPU_PCREL16:
- res = (val & 0x3fffc) << 5;
- break;
-
- default:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("reloc %d not supported by object file format"),
- (int) fixP->fx_r_type);
- }
-
- if (res != 0)
- {
- place[0] |= (res >> 24) & 0xff;
- place[1] |= (res >> 16) & 0xff;
- place[2] |= (res >> 8) & 0xff;
- place[3] |= (res) & 0xff;
- }
+ case BFD_RELOC_SPU_IMM7:
+ res = val << 14;
+ mask = 0x7f << 14;
+ break;
+
+ case BFD_RELOC_SPU_IMM8:
+ res = val << 14;
+ mask = 0xff << 14;
+ break;
+
+ case BFD_RELOC_SPU_IMM10:
+ res = val << 14;
+ mask = 0x3ff << 14;
+ break;
+
+ case BFD_RELOC_SPU_IMM10W:
+ res = val << 10;
+ mask = 0x3ff0 << 10;
+ break;
+
+ case BFD_RELOC_SPU_IMM16:
+ res = val << 7;
+ mask = 0xffff << 7;
+ break;
+
+ case BFD_RELOC_SPU_IMM16W:
+ res = val << 5;
+ mask = 0x3fffc << 5;
+ break;
+
+ case BFD_RELOC_SPU_IMM18:
+ res = val << 7;
+ mask = 0x3ffff << 7;
+ break;
+
+ case BFD_RELOC_SPU_PCREL9a:
+ res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14);
+ mask = (0x1fc >> 2) | (0x600 << 14);
+ break;
+
+ case BFD_RELOC_SPU_PCREL9b:
+ res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5);
+ mask = (0x1fc >> 2) | (0x600 << 5);
+ break;
+
+ case BFD_RELOC_SPU_PCREL16:
+ res = val << 5;
+ mask = 0x3fffc << 5;
+ break;
+
+ case BFD_RELOC_SPU_HI16:
+ res = val >> 9;
+ mask = 0xffff << 7;
+ break;
+
+ case BFD_RELOC_SPU_LO16:
+ res = val << 7;
+ mask = 0xffff << 7;
+ break;
+
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("reloc %d not supported by object file format"),
+ (int) fixP->fx_r_type);
+ }
+
+ res &= mask;
+ place[0] = (place[0] & (~mask >> 24)) | ((res >> 24) & 0xff);
+ place[1] = (place[1] & (~mask >> 16)) | ((res >> 16) & 0xff);
+ place[2] = (place[2] & (~mask >> 8)) | ((res >> 8) & 0xff);
+ place[3] = (place[3] & ~mask) | (res & 0xff);
}
}