Home | History | Annotate | Line # | Download | only in config
tc-spu.c revision 1.1
      1  1.1  skrll /* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU)
      2  1.1  skrll 
      3  1.1  skrll    Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
      4  1.1  skrll 
      5  1.1  skrll    This file is part of GAS, the GNU Assembler.
      6  1.1  skrll 
      7  1.1  skrll    GAS is free software; you can redistribute it and/or modify
      8  1.1  skrll    it under the terms of the GNU General Public License as published by
      9  1.1  skrll    the Free Software Foundation; either version 3, or (at your option)
     10  1.1  skrll    any later version.
     11  1.1  skrll 
     12  1.1  skrll    GAS is distributed in the hope that it will be useful,
     13  1.1  skrll    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  skrll    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  skrll    GNU General Public License for more details.
     16  1.1  skrll 
     17  1.1  skrll    You should have received a copy of the GNU General Public License
     18  1.1  skrll    along with GAS; see the file COPYING.  If not, write to the Free
     19  1.1  skrll    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
     20  1.1  skrll    02110-1301, USA.  */
     21  1.1  skrll 
     22  1.1  skrll #include "as.h"
     23  1.1  skrll #include "safe-ctype.h"
     24  1.1  skrll #include "subsegs.h"
     25  1.1  skrll #include "dwarf2dbg.h"
     26  1.1  skrll 
     27  1.1  skrll const struct spu_opcode spu_opcodes[] = {
     28  1.1  skrll #define APUOP(TAG,MACFORMAT,OPCODE,MNEMONIC,ASMFORMAT,DEP,PIPE) \
     29  1.1  skrll 	{ MACFORMAT, (OPCODE) << (32-11), MNEMONIC, ASMFORMAT },
     30  1.1  skrll #define APUOPFB(TAG,MACFORMAT,OPCODE,FB,MNEMONIC,ASMFORMAT,DEP,PIPE) \
     31  1.1  skrll 	{ MACFORMAT, ((OPCODE) << (32-11)) | ((FB) << (32-18)), MNEMONIC, ASMFORMAT },
     32  1.1  skrll #include "opcode/spu-insns.h"
     33  1.1  skrll #undef APUOP
     34  1.1  skrll #undef APUOPFB
     35  1.1  skrll };
     36  1.1  skrll 
     37  1.1  skrll static const int spu_num_opcodes =
     38  1.1  skrll   sizeof (spu_opcodes) / sizeof (spu_opcodes[0]);
     39  1.1  skrll 
     40  1.1  skrll #define MAX_RELOCS 2
     41  1.1  skrll 
     42  1.1  skrll struct spu_insn
     43  1.1  skrll {
     44  1.1  skrll   unsigned int opcode;
     45  1.1  skrll   expressionS exp[MAX_RELOCS];
     46  1.1  skrll   int reloc_arg[MAX_RELOCS];
     47  1.1  skrll   bfd_reloc_code_real_type reloc[MAX_RELOCS];
     48  1.1  skrll   enum spu_insns tag;
     49  1.1  skrll };
     50  1.1  skrll 
     51  1.1  skrll static const char *get_imm (const char *param, struct spu_insn *insn, int arg);
     52  1.1  skrll static const char *get_reg (const char *param, struct spu_insn *insn, int arg,
     53  1.1  skrll 			    int accept_expr);
     54  1.1  skrll static int calcop (struct spu_opcode *format, const char *param,
     55  1.1  skrll 		   struct spu_insn *insn);
     56  1.1  skrll static void spu_cons (int);
     57  1.1  skrll 
     58  1.1  skrll extern char *myname;
     59  1.1  skrll static struct hash_control *op_hash = NULL;
     60  1.1  skrll 
     61  1.1  skrll /* These bits should be turned off in the first address of every segment */
     62  1.1  skrll int md_seg_align = 7;
     63  1.1  skrll 
     64  1.1  skrll /* These chars start a comment anywhere in a source file (except inside
     65  1.1  skrll    another comment */
     66  1.1  skrll const char comment_chars[] = "#";
     67  1.1  skrll 
     68  1.1  skrll /* These chars only start a comment at the beginning of a line.  */
     69  1.1  skrll const char line_comment_chars[] = "#";
     70  1.1  skrll 
     71  1.1  skrll /* gods own line continuation char */
     72  1.1  skrll const char line_separator_chars[] = ";";
     73  1.1  skrll 
     74  1.1  skrll /* Chars that can be used to separate mant from exp in floating point nums */
     75  1.1  skrll const char EXP_CHARS[] = "eE";
     76  1.1  skrll 
     77  1.1  skrll /* Chars that mean this number is a floating point constant */
     78  1.1  skrll /* as in 0f123.456 */
     79  1.1  skrll /* or    0H1.234E-12 (see exp chars above) */
     80  1.1  skrll const char FLT_CHARS[] = "dDfF";
     81  1.1  skrll 
     82  1.1  skrll const pseudo_typeS md_pseudo_table[] =
     83  1.1  skrll {
     84  1.1  skrll   {"align", s_align_ptwo, 4},
     85  1.1  skrll   {"bss", s_lcomm_bytes, 1},
     86  1.1  skrll   {"def", s_set, 0},
     87  1.1  skrll   {"dfloat", float_cons, 'd'},
     88  1.1  skrll   {"ffloat", float_cons, 'f'},
     89  1.1  skrll   {"global", s_globl, 0},
     90  1.1  skrll   {"half", cons, 2},
     91  1.1  skrll   {"int", spu_cons, 4},
     92  1.1  skrll   {"long", spu_cons, 4},
     93  1.1  skrll   {"quad", spu_cons, 8},
     94  1.1  skrll   {"string", stringer, 8 + 1},
     95  1.1  skrll   {"word", spu_cons, 4},
     96  1.1  skrll   /* Force set to be treated as an instruction.  */
     97  1.1  skrll   {"set", NULL, 0},
     98  1.1  skrll   {".set", s_set, 0},
     99  1.1  skrll   /* Likewise for eqv.  */
    100  1.1  skrll   {"eqv", NULL, 0},
    101  1.1  skrll   {".eqv", s_set, -1},
    102  1.1  skrll   {"file", (void (*) (int)) dwarf2_directive_file, 0 },
    103  1.1  skrll   {"loc", dwarf2_directive_loc, 0},
    104  1.1  skrll   {0,0,0}
    105  1.1  skrll };
    106  1.1  skrll 
    107  1.1  skrll void
    108  1.1  skrll md_begin (void)
    109  1.1  skrll {
    110  1.1  skrll   const char *retval = NULL;
    111  1.1  skrll   int i;
    112  1.1  skrll 
    113  1.1  skrll   /* initialize hash table */
    114  1.1  skrll 
    115  1.1  skrll   op_hash = hash_new ();
    116  1.1  skrll 
    117  1.1  skrll   /* loop until you see the end of the list */
    118  1.1  skrll 
    119  1.1  skrll   for (i = 0; i < spu_num_opcodes; i++)
    120  1.1  skrll     {
    121  1.1  skrll       /* hash each mnemonic and record its position */
    122  1.1  skrll 
    123  1.1  skrll       retval = hash_insert (op_hash, spu_opcodes[i].mnemonic,
    124  1.1  skrll 			    (void *) &spu_opcodes[i]);
    125  1.1  skrll 
    126  1.1  skrll       if (retval != NULL && strcmp (retval, "exists") != 0)
    127  1.1  skrll 	as_fatal (_("Can't hash instruction '%s':%s"),
    128  1.1  skrll 		  spu_opcodes[i].mnemonic, retval);
    129  1.1  skrll     }
    130  1.1  skrll }
    131  1.1  skrll 
    132  1.1  skrll const char *md_shortopts = "";
    134  1.1  skrll struct option md_longopts[] = {
    135  1.1  skrll #define OPTION_APUASM (OPTION_MD_BASE)
    136  1.1  skrll   {"apuasm", no_argument, NULL, OPTION_APUASM},
    137  1.1  skrll #define OPTION_DD2 (OPTION_MD_BASE+1)
    138  1.1  skrll   {"mdd2.0", no_argument, NULL, OPTION_DD2},
    139  1.1  skrll #define OPTION_DD1 (OPTION_MD_BASE+2)
    140  1.1  skrll   {"mdd1.0", no_argument, NULL, OPTION_DD1},
    141  1.1  skrll #define OPTION_DD3 (OPTION_MD_BASE+3)
    142  1.1  skrll   {"mdd3.0", no_argument, NULL, OPTION_DD3},
    143  1.1  skrll   { NULL, no_argument, NULL, 0 }
    144  1.1  skrll };
    145  1.1  skrll size_t md_longopts_size = sizeof (md_longopts);
    146  1.1  skrll 
    147  1.1  skrll /* When set (by -apuasm) our assembler emulates the behaviour of apuasm.
    148  1.1  skrll  * e.g. don't add bias to float conversion and don't right shift
    149  1.1  skrll  * immediate values. */
    150  1.1  skrll static int emulate_apuasm;
    151  1.1  skrll 
    152  1.1  skrll /* Use the dd2.0 instructions set.  The only differences are some new
    153  1.1  skrll  * register names and the orx insn */
    154  1.1  skrll static int use_dd2 = 1;
    155  1.1  skrll 
    156  1.1  skrll int
    157  1.1  skrll md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
    158  1.1  skrll {
    159  1.1  skrll   switch (c)
    160  1.1  skrll     {
    161  1.1  skrll     case OPTION_APUASM:
    162  1.1  skrll       emulate_apuasm = 1;
    163  1.1  skrll       break;
    164  1.1  skrll     case OPTION_DD3:
    165  1.1  skrll       use_dd2 = 1;
    166  1.1  skrll       break;
    167  1.1  skrll     case OPTION_DD2:
    168  1.1  skrll       use_dd2 = 1;
    169  1.1  skrll       break;
    170  1.1  skrll     case OPTION_DD1:
    171  1.1  skrll       use_dd2 = 0;
    172  1.1  skrll       break;
    173  1.1  skrll     default:
    174  1.1  skrll       return 0;
    175  1.1  skrll     }
    176  1.1  skrll   return 1;
    177  1.1  skrll }
    178  1.1  skrll 
    179  1.1  skrll void
    180  1.1  skrll md_show_usage (FILE *stream)
    181  1.1  skrll {
    182  1.1  skrll   fputs (_("\
    183  1.1  skrll SPU options:\n\
    184  1.1  skrll   --apuasm		  emulate behaviour of apuasm\n"),
    185  1.1  skrll 	stream);
    186  1.1  skrll }
    187  1.1  skrll 
    188  1.1  skrll 
    190  1.1  skrll struct arg_encode {
    191  1.1  skrll   int size;
    192  1.1  skrll   int pos;
    193  1.1  skrll   int rshift;
    194  1.1  skrll   int lo, hi;
    195  1.1  skrll   int wlo, whi;
    196  1.1  skrll   bfd_reloc_code_real_type reloc;
    197  1.1  skrll };
    198  1.1  skrll 
    199  1.1  skrll static struct arg_encode arg_encode[A_MAX] = {
    200  1.1  skrll   {  7,  0, 0,       0,    127,    0,   -1,  0 }, /* A_T */
    201  1.1  skrll   {  7,  7, 0,       0,    127,    0,   -1,  0 }, /* A_A */
    202  1.1  skrll   {  7, 14, 0,       0,    127,    0,   -1,  0 }, /* A_B */
    203  1.1  skrll   {  7, 21, 0,       0,    127,    0,   -1,  0 }, /* A_C */
    204  1.1  skrll   {  7,  7, 0,       0,    127,    0,   -1,  0 }, /* A_S */
    205  1.1  skrll   {  7,  7, 0,       0,    127,    0,   -1,  0 }, /* A_H */
    206  1.1  skrll   {  0,  0, 0,       0,     -1,    0,   -1,  0 }, /* A_P */
    207  1.1  skrll   {  7, 14, 0,       0,     -1,    0,   -1,  BFD_RELOC_SPU_IMM7 }, /* A_S3 */
    208  1.1  skrll   {  7, 14, 0,     -32,     31,  -31,    0,  BFD_RELOC_SPU_IMM7 }, /* A_S6 */
    209  1.1  skrll   {  7, 14, 0,       0,     -1,    0,   -1,  BFD_RELOC_SPU_IMM7 }, /* A_S7N */
    210  1.1  skrll   {  7, 14, 0,     -64,     63,  -63,    0,  BFD_RELOC_SPU_IMM7 }, /* A_S7 */
    211  1.1  skrll   {  8, 14, 0,       0,    127,    0,   -1,  BFD_RELOC_SPU_IMM8 }, /* A_U7A */
    212  1.1  skrll   {  8, 14, 0,       0,    127,    0,   -1,  BFD_RELOC_SPU_IMM8 }, /* A_U7B */
    213  1.1  skrll   { 10, 14, 0,    -512,    511, -128,  255,  BFD_RELOC_SPU_IMM10 }, /* A_S10B */
    214  1.1  skrll   { 10, 14, 0,    -512,    511,    0,   -1,  BFD_RELOC_SPU_IMM10 }, /* A_S10 */
    215  1.1  skrll   {  2, 23, 9,   -1024,   1023,    0,   -1,  BFD_RELOC_SPU_PCREL9a }, /* A_S11 */
    216  1.1  skrll   {  2, 14, 9,   -1024,   1023,    0,   -1,  BFD_RELOC_SPU_PCREL9b }, /* A_S11I */
    217  1.1  skrll   { 10, 14, 4,   -8192,   8191,    0,   -1,  BFD_RELOC_SPU_IMM10W }, /* A_S14 */
    218  1.1  skrll   { 16,  7, 0,  -32768,  32767,    0,   -1,  BFD_RELOC_SPU_IMM16 }, /* A_S16 */
    219  1.1  skrll   { 16,  7, 2, -131072, 262143,    0,   -1,  BFD_RELOC_SPU_IMM16W }, /* A_S18 */
    220  1.1  skrll   { 16,  7, 2, -262144, 262143,    0,   -1,  BFD_RELOC_SPU_PCREL16 }, /* A_R18 */
    221  1.1  skrll   {  7, 14, 0,       0,     -1,    0,   -1,  BFD_RELOC_SPU_IMM7 }, /* A_U3 */
    222  1.1  skrll   {  7, 14, 0,       0,    127,    0,   31,  BFD_RELOC_SPU_IMM7 }, /* A_U5 */
    223  1.1  skrll   {  7, 14, 0,       0,    127,    0,   63,  BFD_RELOC_SPU_IMM7 }, /* A_U6 */
    224  1.1  skrll   {  7, 14, 0,       0,     -1,    0,   -1,  BFD_RELOC_SPU_IMM7 }, /* A_U7 */
    225  1.1  skrll   { 14,  0, 0,       0,  16383,    0,   -1,  0 }, /* A_U14 */
    226  1.1  skrll   { 16,  7, 0,  -32768,  65535,    0,   -1,  BFD_RELOC_SPU_IMM16 }, /* A_X16 */
    227  1.1  skrll   { 18,  7, 0,       0, 262143,    0,   -1,  BFD_RELOC_SPU_IMM18 }, /* A_U18 */
    228  1.1  skrll };
    229  1.1  skrll 
    230  1.1  skrll /* Some flags for handling errors.  This is very hackish and added after
    231  1.1  skrll  * the fact. */
    232  1.1  skrll static int syntax_error_arg;
    233  1.1  skrll static const char *syntax_error_param;
    234  1.1  skrll static int syntax_reg;
    235  1.1  skrll 
    236  1.1  skrll static char *
    237  1.1  skrll insn_fmt_string (struct spu_opcode *format)
    238  1.1  skrll {
    239  1.1  skrll   static char buf[64];
    240  1.1  skrll   int len = 0;
    241  1.1  skrll   int i;
    242  1.1  skrll 
    243  1.1  skrll   len += sprintf (&buf[len], "%s\t", format->mnemonic);
    244  1.1  skrll   for (i = 1; i <= format->arg[0]; i++)
    245  1.1  skrll     {
    246  1.1  skrll       int arg = format->arg[i];
    247  1.1  skrll       char *exp;
    248  1.1  skrll       if (i > 1 && arg != A_P && format->arg[i-1] != A_P)
    249  1.1  skrll 	buf[len++] =  ',';
    250  1.1  skrll       if (arg == A_P)
    251  1.1  skrll 	exp = "(";
    252  1.1  skrll       else if (arg < A_P)
    253  1.1  skrll 	exp = i == syntax_error_arg ? "REG" : "reg";
    254  1.1  skrll       else
    255  1.1  skrll 	exp = i == syntax_error_arg ? "IMM" : "imm";
    256  1.1  skrll       len += sprintf (&buf[len], "%s", exp);
    257  1.1  skrll       if (i > 1 && format->arg[i-1] == A_P)
    258  1.1  skrll 	buf[len++] =  ')';
    259  1.1  skrll     }
    260  1.1  skrll   buf[len] = 0;
    261  1.1  skrll   return buf;
    262  1.1  skrll }
    263  1.1  skrll 
    264  1.1  skrll void
    265  1.1  skrll md_assemble (char *op)
    266  1.1  skrll {
    267  1.1  skrll   char *param, *thisfrag;
    268  1.1  skrll   char c;
    269  1.1  skrll   struct spu_opcode *format;
    270  1.1  skrll   struct spu_insn insn;
    271  1.1  skrll   int i;
    272  1.1  skrll 
    273  1.1  skrll   assert (op);
    274  1.1  skrll 
    275  1.1  skrll   /* skip over instruction to find parameters */
    276  1.1  skrll 
    277  1.1  skrll   for (param = op; *param != 0 && !ISSPACE (*param); param++)
    278  1.1  skrll     ;
    279  1.1  skrll   c = *param;
    280  1.1  skrll   *param = 0;
    281  1.1  skrll 
    282  1.1  skrll   if (c != 0 && c != '\n')
    283  1.1  skrll     param++;
    284  1.1  skrll 
    285  1.1  skrll   /* try to find the instruction in the hash table */
    286  1.1  skrll 
    287  1.1  skrll   if ((format = (struct spu_opcode *) hash_find (op_hash, op)) == NULL)
    288  1.1  skrll     {
    289  1.1  skrll       as_bad (_("Invalid mnemonic '%s'"), op);
    290  1.1  skrll       return;
    291  1.1  skrll     }
    292  1.1  skrll 
    293  1.1  skrll   if (!use_dd2 && strcmp (format->mnemonic, "orx") == 0)
    294  1.1  skrll     {
    295  1.1  skrll       as_bad (_("'%s' is only available in DD2.0 or higher."), op);
    296  1.1  skrll       return;
    297  1.1  skrll     }
    298  1.1  skrll 
    299  1.1  skrll   while (1)
    300  1.1  skrll     {
    301  1.1  skrll       /* try parsing this instruction into insn */
    302  1.1  skrll       for (i = 0; i < MAX_RELOCS; i++)
    303  1.1  skrll 	{
    304  1.1  skrll 	  insn.exp[i].X_add_symbol = 0;
    305  1.1  skrll 	  insn.exp[i].X_op_symbol = 0;
    306  1.1  skrll 	  insn.exp[i].X_add_number = 0;
    307  1.1  skrll 	  insn.exp[i].X_op = O_illegal;
    308  1.1  skrll 	  insn.reloc_arg[i] = -1;
    309  1.1  skrll 	  insn.reloc[i] = BFD_RELOC_NONE;
    310  1.1  skrll 	}
    311  1.1  skrll       insn.opcode = format->opcode;
    312  1.1  skrll       insn.tag = (enum spu_insns) (format - spu_opcodes);
    313  1.1  skrll 
    314  1.1  skrll       syntax_error_arg = 0;
    315  1.1  skrll       syntax_error_param = 0;
    316  1.1  skrll       syntax_reg = 0;
    317  1.1  skrll       if (calcop (format, param, &insn))
    318  1.1  skrll 	break;
    319  1.1  skrll 
    320  1.1  skrll       /* if it doesn't parse try the next instruction */
    321  1.1  skrll       if (!strcmp (format[0].mnemonic, format[1].mnemonic))
    322  1.1  skrll 	format++;
    323  1.1  skrll       else
    324  1.1  skrll 	{
    325  1.1  skrll 	  int parg = format[0].arg[syntax_error_arg-1];
    326  1.1  skrll 
    327  1.1  skrll 	  as_fatal (_("Error in argument %d.  Expecting:  \"%s\""),
    328  1.1  skrll 		    syntax_error_arg - (parg == A_P),
    329  1.1  skrll 		    insn_fmt_string (format));
    330  1.1  skrll 	  return;
    331  1.1  skrll 	}
    332  1.1  skrll     }
    333  1.1  skrll 
    334  1.1  skrll   if ((syntax_reg & 4)
    335  1.1  skrll       && ! (insn.tag == M_RDCH
    336  1.1  skrll 	    || insn.tag == M_RCHCNT
    337  1.1  skrll 	    || insn.tag == M_WRCH))
    338  1.1  skrll     as_warn (_("Mixing register syntax, with and without '$'."));
    339  1.1  skrll   if (syntax_error_param)
    340  1.1  skrll     {
    341  1.1  skrll       const char *d = syntax_error_param;
    342  1.1  skrll       while (*d != '$')
    343  1.1  skrll 	d--;
    344  1.1  skrll       as_warn (_("Treating '%-*s' as a symbol."), (int)(syntax_error_param - d), d);
    345  1.1  skrll     }
    346  1.1  skrll 
    347  1.1  skrll   /* grow the current frag and plop in the opcode */
    348  1.1  skrll 
    349  1.1  skrll   thisfrag = frag_more (4);
    350  1.1  skrll   md_number_to_chars (thisfrag, insn.opcode, 4);
    351  1.1  skrll 
    352  1.1  skrll   /* if this instruction requires labels mark it for later */
    353  1.1  skrll 
    354  1.1  skrll   for (i = 0; i < MAX_RELOCS; i++)
    355  1.1  skrll     if (insn.reloc_arg[i] >= 0)
    356  1.1  skrll       {
    357  1.1  skrll         fixS *fixP;
    358  1.1  skrll         bfd_reloc_code_real_type reloc = insn.reloc[i];
    359  1.1  skrll 	int pcrel = 0;
    360  1.1  skrll 
    361  1.1  skrll 	if (reloc == BFD_RELOC_SPU_PCREL9a
    362  1.1  skrll 	    || reloc == BFD_RELOC_SPU_PCREL9b
    363  1.1  skrll 	    || reloc == BFD_RELOC_SPU_PCREL16)
    364  1.1  skrll 	  pcrel = 1;
    365  1.1  skrll 	fixP = fix_new_exp (frag_now,
    366  1.1  skrll 			    thisfrag - frag_now->fr_literal,
    367  1.1  skrll 			    4,
    368  1.1  skrll 			    &insn.exp[i],
    369  1.1  skrll 			    pcrel,
    370  1.1  skrll 			    reloc);
    371  1.1  skrll 	fixP->tc_fix_data.arg_format = insn.reloc_arg[i];
    372  1.1  skrll 	fixP->tc_fix_data.insn_tag = insn.tag;
    373  1.1  skrll       }
    374  1.1  skrll   dwarf2_emit_insn (4);
    375  1.1  skrll }
    376  1.1  skrll 
    377  1.1  skrll static int
    378  1.1  skrll calcop (struct spu_opcode *format, const char *param, struct spu_insn *insn)
    379  1.1  skrll {
    380  1.1  skrll   int i;
    381  1.1  skrll   int paren = 0;
    382  1.1  skrll   int arg;
    383  1.1  skrll 
    384  1.1  skrll   for (i = 1; i <= format->arg[0]; i++)
    385  1.1  skrll     {
    386  1.1  skrll       arg = format->arg[i];
    387  1.1  skrll       syntax_error_arg = i;
    388  1.1  skrll 
    389  1.1  skrll       while (ISSPACE (*param))
    390  1.1  skrll         param++;
    391  1.1  skrll       if (*param == 0 || *param == ',')
    392  1.1  skrll 	return 0;
    393  1.1  skrll       if (arg < A_P)
    394  1.1  skrll         param = get_reg (param, insn, arg, 1);
    395  1.1  skrll       else if (arg > A_P)
    396  1.1  skrll         param = get_imm (param, insn, arg);
    397  1.1  skrll       else if (arg == A_P)
    398  1.1  skrll 	{
    399  1.1  skrll 	  paren++;
    400  1.1  skrll 	  if ('(' != *param++)
    401  1.1  skrll 	    return 0;
    402  1.1  skrll 	}
    403  1.1  skrll 
    404  1.1  skrll       if (!param)
    405  1.1  skrll 	return 0;
    406  1.1  skrll 
    407  1.1  skrll       while (ISSPACE (*param))
    408  1.1  skrll         param++;
    409  1.1  skrll 
    410  1.1  skrll       if (arg != A_P && paren)
    411  1.1  skrll 	{
    412  1.1  skrll 	  paren--;
    413  1.1  skrll 	  if (')' != *param++)
    414  1.1  skrll 	    return 0;
    415  1.1  skrll 	}
    416  1.1  skrll       else if (i < format->arg[0]
    417  1.1  skrll 	       && format->arg[i] != A_P
    418  1.1  skrll 	       && format->arg[i+1] != A_P)
    419  1.1  skrll 	{
    420  1.1  skrll 	  if (',' != *param++)
    421  1.1  skrll 	    {
    422  1.1  skrll 	      syntax_error_arg++;
    423  1.1  skrll 	      return 0;
    424  1.1  skrll 	    }
    425  1.1  skrll 	}
    426  1.1  skrll     }
    427  1.1  skrll   while (ISSPACE (*param))
    428  1.1  skrll     param++;
    429  1.1  skrll   return !paren && (*param == 0 || *param == '\n');
    430  1.1  skrll }
    431  1.1  skrll 
    432  1.1  skrll struct reg_name {
    433  1.1  skrll     unsigned int regno;
    434  1.1  skrll     unsigned int length;
    435  1.1  skrll     char name[32];
    436  1.1  skrll };
    437  1.1  skrll 
    438  1.1  skrll #define REG_NAME(NO,NM) { NO, sizeof (NM) - 1, NM }
    439  1.1  skrll 
    440  1.1  skrll static struct reg_name reg_name[] = {
    441  1.1  skrll   REG_NAME (0, "lr"),  /* link register */
    442  1.1  skrll   REG_NAME (1, "sp"),  /* stack pointer */
    443  1.1  skrll   REG_NAME (0, "rp"),  /* link register */
    444  1.1  skrll   REG_NAME (127, "fp"),  /* frame pointer */
    445  1.1  skrll };
    446  1.1  skrll 
    447  1.1  skrll static struct reg_name sp_reg_name[] = {
    448  1.1  skrll };
    449  1.1  skrll 
    450  1.1  skrll static struct reg_name ch_reg_name[] = {
    451  1.1  skrll   REG_NAME (  0, "SPU_RdEventStat"),
    452  1.1  skrll   REG_NAME (  1, "SPU_WrEventMask"),
    453  1.1  skrll   REG_NAME (  2, "SPU_WrEventAck"),
    454  1.1  skrll   REG_NAME (  3, "SPU_RdSigNotify1"),
    455  1.1  skrll   REG_NAME (  4, "SPU_RdSigNotify2"),
    456  1.1  skrll   REG_NAME (  7, "SPU_WrDec"),
    457  1.1  skrll   REG_NAME (  8, "SPU_RdDec"),
    458  1.1  skrll   REG_NAME ( 11, "SPU_RdEventMask"), /* DD2.0 only */
    459  1.1  skrll   REG_NAME ( 13, "SPU_RdMachStat"),
    460  1.1  skrll   REG_NAME ( 14, "SPU_WrSRR0"),
    461  1.1  skrll   REG_NAME ( 15, "SPU_RdSRR0"),
    462  1.1  skrll   REG_NAME ( 28, "SPU_WrOutMbox"),
    463  1.1  skrll   REG_NAME ( 29, "SPU_RdInMbox"),
    464  1.1  skrll   REG_NAME ( 30, "SPU_WrOutIntrMbox"),
    465  1.1  skrll   REG_NAME (  9, "MFC_WrMSSyncReq"),
    466  1.1  skrll   REG_NAME ( 12, "MFC_RdTagMask"),   /* DD2.0 only */
    467  1.1  skrll   REG_NAME ( 16, "MFC_LSA"),
    468  1.1  skrll   REG_NAME ( 17, "MFC_EAH"),
    469  1.1  skrll   REG_NAME ( 18, "MFC_EAL"),
    470  1.1  skrll   REG_NAME ( 19, "MFC_Size"),
    471  1.1  skrll   REG_NAME ( 20, "MFC_TagID"),
    472  1.1  skrll   REG_NAME ( 21, "MFC_Cmd"),
    473  1.1  skrll   REG_NAME ( 22, "MFC_WrTagMask"),
    474  1.1  skrll   REG_NAME ( 23, "MFC_WrTagUpdate"),
    475  1.1  skrll   REG_NAME ( 24, "MFC_RdTagStat"),
    476  1.1  skrll   REG_NAME ( 25, "MFC_RdListStallStat"),
    477  1.1  skrll   REG_NAME ( 26, "MFC_WrListStallAck"),
    478  1.1  skrll   REG_NAME ( 27, "MFC_RdAtomicStat"),
    479  1.1  skrll };
    480  1.1  skrll #undef REG_NAME
    481  1.1  skrll 
    482  1.1  skrll static const char *
    483  1.1  skrll get_reg (const char *param, struct spu_insn *insn, int arg, int accept_expr)
    484  1.1  skrll {
    485  1.1  skrll   unsigned regno;
    486  1.1  skrll   int saw_prefix = 0;
    487  1.1  skrll 
    488  1.1  skrll   if (*param == '$')
    489  1.1  skrll     {
    490  1.1  skrll       saw_prefix = 1;
    491  1.1  skrll       param++;
    492  1.1  skrll     }
    493  1.1  skrll 
    494  1.1  skrll   if (arg == A_H) /* Channel */
    495  1.1  skrll     {
    496  1.1  skrll       if ((param[0] == 'c' || param[0] == 'C')
    497  1.1  skrll 	  && (param[1] == 'h' || param[1] == 'H')
    498  1.1  skrll 	  && ISDIGIT (param[2]))
    499  1.1  skrll         param += 2;
    500  1.1  skrll     }
    501  1.1  skrll   else if (arg == A_S) /* Special purpose register */
    502  1.1  skrll     {
    503  1.1  skrll       if ((param[0] == 's' || param[0] == 'S')
    504  1.1  skrll 	  && (param[1] == 'p' || param[1] == 'P')
    505  1.1  skrll 	  && ISDIGIT (param[2]))
    506  1.1  skrll         param += 2;
    507  1.1  skrll     }
    508  1.1  skrll 
    509  1.1  skrll   if (ISDIGIT (*param))
    510  1.1  skrll     {
    511  1.1  skrll       regno = 0;
    512  1.1  skrll       while (ISDIGIT (*param))
    513  1.1  skrll 	regno = regno * 10 + *param++ - '0';
    514  1.1  skrll     }
    515  1.1  skrll   else
    516  1.1  skrll     {
    517  1.1  skrll       struct reg_name *rn;
    518  1.1  skrll       unsigned int i, n, l = 0;
    519  1.1  skrll 
    520  1.1  skrll       if (arg == A_H) /* Channel */
    521  1.1  skrll 	{
    522  1.1  skrll 	  rn = ch_reg_name;
    523  1.1  skrll 	  n = sizeof (ch_reg_name) / sizeof (*ch_reg_name);
    524  1.1  skrll 	}
    525  1.1  skrll       else if (arg == A_S) /* Special purpose register */
    526  1.1  skrll 	{
    527  1.1  skrll 	  rn = sp_reg_name;
    528  1.1  skrll 	  n = sizeof (sp_reg_name) / sizeof (*sp_reg_name);
    529  1.1  skrll 	}
    530  1.1  skrll       else
    531  1.1  skrll 	{
    532  1.1  skrll 	  rn = reg_name;
    533  1.1  skrll 	  n = sizeof (reg_name) / sizeof (*reg_name);
    534  1.1  skrll 	}
    535  1.1  skrll       regno = 128;
    536  1.1  skrll       for (i = 0; i < n; i++)
    537  1.1  skrll 	if (rn[i].length > l
    538  1.1  skrll 	    && 0 == strncasecmp (param, rn[i].name, rn[i].length))
    539  1.1  skrll           {
    540  1.1  skrll 	    l = rn[i].length;
    541  1.1  skrll             regno = rn[i].regno;
    542  1.1  skrll           }
    543  1.1  skrll       param += l;
    544  1.1  skrll     }
    545  1.1  skrll 
    546  1.1  skrll   if (!use_dd2
    547  1.1  skrll       && arg == A_H)
    548  1.1  skrll     {
    549  1.1  skrll       if (regno == 11)
    550  1.1  skrll 	as_bad (_("'SPU_RdEventMask' (channel 11) is only available in DD2.0 or higher."));
    551  1.1  skrll       else if (regno == 12)
    552  1.1  skrll 	as_bad (_("'MFC_RdTagMask' (channel 12) is only available in DD2.0 or higher."));
    553  1.1  skrll     }
    554  1.1  skrll 
    555  1.1  skrll   if (regno < 128)
    556  1.1  skrll     {
    557  1.1  skrll       insn->opcode |= regno << arg_encode[arg].pos;
    558  1.1  skrll       if ((!saw_prefix && syntax_reg == 1)
    559  1.1  skrll 	  || (saw_prefix && syntax_reg == 2))
    560  1.1  skrll 	syntax_reg |= 4;
    561  1.1  skrll       syntax_reg |= saw_prefix ? 1 : 2;
    562  1.1  skrll       return param;
    563  1.1  skrll     }
    564  1.1  skrll 
    565  1.1  skrll   if (accept_expr)
    566  1.1  skrll     {
    567  1.1  skrll       char *save_ptr;
    568  1.1  skrll       expressionS ex;
    569  1.1  skrll       save_ptr = input_line_pointer;
    570  1.1  skrll       input_line_pointer = (char *)param;
    571  1.1  skrll       expression (&ex);
    572  1.1  skrll       param = input_line_pointer;
    573  1.1  skrll       input_line_pointer = save_ptr;
    574  1.1  skrll       if (ex.X_op == O_register || ex.X_op == O_constant)
    575  1.1  skrll 	{
    576  1.1  skrll 	  insn->opcode |= ex.X_add_number << arg_encode[arg].pos;
    577  1.1  skrll 	  return param;
    578  1.1  skrll 	}
    579  1.1  skrll     }
    580  1.1  skrll   return 0;
    581  1.1  skrll }
    582  1.1  skrll 
    583  1.1  skrll static const char *
    584  1.1  skrll get_imm (const char *param, struct spu_insn *insn, int arg)
    585  1.1  skrll {
    586  1.1  skrll   int val;
    587  1.1  skrll   char *save_ptr;
    588  1.1  skrll   int low = 0, high = 0;
    589  1.1  skrll   int reloc_i = insn->reloc_arg[0] >= 0 ? 1 : 0;
    590  1.1  skrll 
    591  1.1  skrll   if (strncasecmp (param, "%lo(", 4) == 0)
    592  1.1  skrll     {
    593  1.1  skrll       param += 3;
    594  1.1  skrll       low = 1;
    595  1.1  skrll       as_warn (_("Using old style, %%lo(expr), please change to PPC style, expr@l."));
    596  1.1  skrll     }
    597  1.1  skrll   else if (strncasecmp (param, "%hi(", 4) == 0)
    598  1.1  skrll     {
    599  1.1  skrll       param += 3;
    600  1.1  skrll       high = 1;
    601  1.1  skrll       as_warn (_("Using old style, %%hi(expr), please change to PPC style, expr@h."));
    602  1.1  skrll     }
    603  1.1  skrll   else if (strncasecmp (param, "%pic(", 5) == 0)
    604  1.1  skrll     {
    605  1.1  skrll       /* Currently we expect %pic(expr) == expr, so do nothing here.
    606  1.1  skrll 	 i.e. for code loaded at address 0 $toc will be 0.  */
    607  1.1  skrll       param += 4;
    608  1.1  skrll     }
    609  1.1  skrll 
    610  1.1  skrll   if (*param == '$')
    611  1.1  skrll     {
    612  1.1  skrll       /* Symbols can start with $, but if this symbol matches a register
    613  1.1  skrll 	 name, it's probably a mistake.  The only way to avoid this
    614  1.1  skrll 	 warning is to rename the symbol.  */
    615  1.1  skrll       struct spu_insn tmp_insn;
    616  1.1  skrll       const char *np = get_reg (param, &tmp_insn, arg, 0);
    617  1.1  skrll 
    618  1.1  skrll       if (np)
    619  1.1  skrll 	syntax_error_param = np;
    620  1.1  skrll     }
    621  1.1  skrll 
    622  1.1  skrll   save_ptr = input_line_pointer;
    623  1.1  skrll   input_line_pointer = (char *) param;
    624  1.1  skrll   expression (&insn->exp[reloc_i]);
    625  1.1  skrll   param = input_line_pointer;
    626  1.1  skrll   input_line_pointer = save_ptr;
    627  1.1  skrll 
    628  1.1  skrll   /* Similar to ppc_elf_suffix in tc-ppc.c.  We have so few cases to
    629  1.1  skrll      handle we do it inlined here. */
    630  1.1  skrll   if (param[0] == '@' && !ISALNUM (param[2]) && param[2] != '@')
    631  1.1  skrll     {
    632  1.1  skrll       if (param[1] == 'h' || param[1] == 'H')
    633  1.1  skrll 	{
    634  1.1  skrll 	  high = 1;
    635  1.1  skrll 	  param += 2;
    636  1.1  skrll 	}
    637  1.1  skrll       else if (param[1] == 'l' || param[1] == 'L')
    638  1.1  skrll 	{
    639  1.1  skrll 	  low = 1;
    640  1.1  skrll 	  param += 2;
    641  1.1  skrll 	}
    642  1.1  skrll     }
    643  1.1  skrll 
    644  1.1  skrll   if (insn->exp[reloc_i].X_op == O_constant)
    645  1.1  skrll     {
    646  1.1  skrll       val = insn->exp[reloc_i].X_add_number;
    647  1.1  skrll 
    648  1.1  skrll       if (emulate_apuasm)
    649  1.1  skrll 	{
    650  1.1  skrll 	  /* Convert the value to a format we expect. */
    651  1.1  skrll           val <<= arg_encode[arg].rshift;
    652  1.1  skrll 	  if (arg == A_U7A)
    653  1.1  skrll 	    val = 173 - val;
    654  1.1  skrll 	  else if (arg == A_U7B)
    655  1.1  skrll 	    val = 155 - val;
    656  1.1  skrll 	}
    657  1.1  skrll 
    658  1.1  skrll       if (high)
    659  1.1  skrll 	val = val >> 16;
    660  1.1  skrll       else if (low)
    661  1.1  skrll 	val = val & 0xffff;
    662  1.1  skrll 
    663  1.1  skrll       /* Warn about out of range expressions. */
    664  1.1  skrll       {
    665  1.1  skrll 	int hi = arg_encode[arg].hi;
    666  1.1  skrll 	int lo = arg_encode[arg].lo;
    667  1.1  skrll 	int whi = arg_encode[arg].whi;
    668  1.1  skrll 	int wlo = arg_encode[arg].wlo;
    669  1.1  skrll 
    670  1.1  skrll 	if (hi > lo && (val < lo || val > hi))
    671  1.1  skrll 	  as_fatal (_("Constant expression %d out of range, [%d, %d]."),
    672  1.1  skrll 		    val, lo, hi);
    673  1.1  skrll 	else if (whi > wlo && (val < wlo || val > whi))
    674  1.1  skrll 	  as_warn (_("Constant expression %d out of range, [%d, %d]."),
    675  1.1  skrll 		   val, wlo, whi);
    676  1.1  skrll       }
    677  1.1  skrll 
    678  1.1  skrll       if (arg == A_U7A)
    679  1.1  skrll         val = 173 - val;
    680  1.1  skrll       else if (arg == A_U7B)
    681  1.1  skrll         val = 155 - val;
    682  1.1  skrll 
    683  1.1  skrll       /* Branch hints have a split encoding.  Do the bottom part. */
    684  1.1  skrll       if (arg == A_S11 || arg == A_S11I)
    685  1.1  skrll 	insn->opcode |= ((val >> 2) & 0x7f);
    686  1.1  skrll 
    687  1.1  skrll       insn->opcode |= (((val >> arg_encode[arg].rshift)
    688  1.1  skrll 			& ((1 << arg_encode[arg].size) - 1))
    689  1.1  skrll 		       << arg_encode[arg].pos);
    690  1.1  skrll     }
    691  1.1  skrll   else
    692  1.1  skrll     {
    693  1.1  skrll       insn->reloc_arg[reloc_i] = arg;
    694  1.1  skrll       if (high)
    695  1.1  skrll 	insn->reloc[reloc_i] = BFD_RELOC_SPU_HI16;
    696  1.1  skrll       else if (low)
    697  1.1  skrll 	insn->reloc[reloc_i] = BFD_RELOC_SPU_LO16;
    698  1.1  skrll       else
    699  1.1  skrll 	insn->reloc[reloc_i] = arg_encode[arg].reloc;
    700  1.1  skrll     }
    701  1.1  skrll 
    702  1.1  skrll   return param;
    703  1.1  skrll }
    704  1.1  skrll 
    705  1.1  skrll char *
    706  1.1  skrll md_atof (int type, char *litP, int *sizeP)
    707  1.1  skrll {
    708  1.1  skrll   return ieee_md_atof (type, litP, sizeP, TRUE);
    709  1.1  skrll }
    710  1.1  skrll 
    711  1.1  skrll #ifndef WORKING_DOT_WORD
    712  1.1  skrll int md_short_jump_size = 4;
    713  1.1  skrll 
    714  1.1  skrll void
    715  1.1  skrll md_create_short_jump (char *ptr,
    716  1.1  skrll 		      addressT from_addr ATTRIBUTE_UNUSED,
    717  1.1  skrll 		      addressT to_addr ATTRIBUTE_UNUSED,
    718  1.1  skrll 		      fragS *frag,
    719  1.1  skrll 		      symbolS *to_symbol)
    720  1.1  skrll {
    721  1.1  skrll   ptr[0] = (char) 0xc0;
    722  1.1  skrll   ptr[1] = 0x00;
    723  1.1  skrll   ptr[2] = 0x00;
    724  1.1  skrll   ptr[3] = 0x00;
    725  1.1  skrll   fix_new (frag,
    726  1.1  skrll 	   ptr - frag->fr_literal,
    727  1.1  skrll 	   4,
    728  1.1  skrll 	   to_symbol,
    729  1.1  skrll 	   (offsetT) 0,
    730  1.1  skrll 	   0,
    731  1.1  skrll 	   BFD_RELOC_SPU_PCREL16);
    732  1.1  skrll }
    733  1.1  skrll 
    734  1.1  skrll int md_long_jump_size = 4;
    735  1.1  skrll 
    736  1.1  skrll void
    737  1.1  skrll md_create_long_jump (char *ptr,
    738  1.1  skrll 		     addressT from_addr ATTRIBUTE_UNUSED,
    739  1.1  skrll 		     addressT to_addr ATTRIBUTE_UNUSED,
    740  1.1  skrll 		     fragS *frag,
    741  1.1  skrll 		     symbolS *to_symbol)
    742  1.1  skrll {
    743  1.1  skrll   ptr[0] = (char) 0xc0;
    744  1.1  skrll   ptr[1] = 0x00;
    745  1.1  skrll   ptr[2] = 0x00;
    746  1.1  skrll   ptr[3] = 0x00;
    747  1.1  skrll   fix_new (frag,
    748  1.1  skrll 	   ptr - frag->fr_literal,
    749  1.1  skrll 	   4,
    750  1.1  skrll 	   to_symbol,
    751  1.1  skrll 	   (offsetT) 0,
    752  1.1  skrll 	   0,
    753  1.1  skrll 	   BFD_RELOC_SPU_PCREL16);
    754  1.1  skrll }
    755  1.1  skrll #endif
    756  1.1  skrll 
    757  1.1  skrll /* Support @ppu on symbols referenced in .int/.long/.word/.quad.  */
    758  1.1  skrll static void
    759  1.1  skrll spu_cons (int nbytes)
    760  1.1  skrll {
    761  1.1  skrll   expressionS exp;
    762  1.1  skrll 
    763  1.1  skrll   if (is_it_end_of_statement ())
    764  1.1  skrll     {
    765  1.1  skrll       demand_empty_rest_of_line ();
    766  1.1  skrll       return;
    767  1.1  skrll     }
    768  1.1  skrll 
    769  1.1  skrll   do
    770  1.1  skrll     {
    771  1.1  skrll       deferred_expression (&exp);
    772  1.1  skrll       if ((exp.X_op == O_symbol
    773  1.1  skrll 	   || exp.X_op == O_constant)
    774  1.1  skrll 	  && strncasecmp (input_line_pointer, "@ppu", 4) == 0)
    775  1.1  skrll 	{
    776  1.1  skrll 	  char *p = frag_more (nbytes);
    777  1.1  skrll 	  enum bfd_reloc_code_real reloc;
    778  1.1  skrll 
    779  1.1  skrll 	  /* Check for identifier@suffix+constant.  */
    780  1.1  skrll 	  input_line_pointer += 4;
    781  1.1  skrll 	  if (*input_line_pointer == '-' || *input_line_pointer == '+')
    782  1.1  skrll 	    {
    783  1.1  skrll 	      expressionS new_exp;
    784  1.1  skrll 
    785  1.1  skrll 	      expression (&new_exp);
    786  1.1  skrll 	      if (new_exp.X_op == O_constant)
    787  1.1  skrll 		exp.X_add_number += new_exp.X_add_number;
    788  1.1  skrll 	    }
    789  1.1  skrll 
    790  1.1  skrll 	  reloc = nbytes == 4 ? BFD_RELOC_SPU_PPU32 : BFD_RELOC_SPU_PPU64;
    791  1.1  skrll 	  fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes,
    792  1.1  skrll 		       &exp, 0, reloc);
    793  1.1  skrll 	}
    794  1.1  skrll       else
    795  1.1  skrll 	emit_expr (&exp, nbytes);
    796  1.1  skrll     }
    797  1.1  skrll   while (*input_line_pointer++ == ',');
    798  1.1  skrll 
    799  1.1  skrll   /* Put terminator back into stream.  */
    800  1.1  skrll   input_line_pointer--;
    801  1.1  skrll   demand_empty_rest_of_line ();
    802  1.1  skrll }
    803  1.1  skrll 
    804  1.1  skrll int
    805  1.1  skrll md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
    806  1.1  skrll 			       segT segment_type ATTRIBUTE_UNUSED)
    807  1.1  skrll {
    808  1.1  skrll   as_fatal (_("Relaxation should never occur"));
    809  1.1  skrll   return -1;
    810  1.1  skrll }
    811  1.1  skrll 
    812  1.1  skrll /* If while processing a fixup, a reloc really needs to be created,
    813  1.1  skrll    then it is done here.  */
    814  1.1  skrll 
    815  1.1  skrll arelent *
    816  1.1  skrll tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
    817  1.1  skrll {
    818  1.1  skrll   arelent *reloc;
    819  1.1  skrll   reloc = (arelent *) xmalloc (sizeof (arelent));
    820  1.1  skrll   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
    821  1.1  skrll   if (fixp->fx_addsy)
    822  1.1  skrll     *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
    823  1.1  skrll   else if (fixp->fx_subsy)
    824  1.1  skrll     *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
    825  1.1  skrll   else
    826  1.1  skrll     abort ();
    827  1.1  skrll   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
    828  1.1  skrll   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
    829  1.1  skrll   if (reloc->howto == (reloc_howto_type *) NULL)
    830  1.1  skrll     {
    831  1.1  skrll       as_bad_where (fixp->fx_file, fixp->fx_line,
    832  1.1  skrll 		    _("reloc %d not supported by object file format"),
    833  1.1  skrll 		    (int) fixp->fx_r_type);
    834  1.1  skrll       return NULL;
    835  1.1  skrll     }
    836  1.1  skrll   reloc->addend = fixp->fx_addnumber;
    837  1.1  skrll   return reloc;
    838  1.1  skrll }
    839  1.1  skrll 
    840  1.1  skrll /* Round up a section's size to the appropriate boundary.  */
    841  1.1  skrll 
    842  1.1  skrll valueT
    843  1.1  skrll md_section_align (segT seg, valueT size)
    844  1.1  skrll {
    845  1.1  skrll   int align = bfd_get_section_alignment (stdoutput, seg);
    846  1.1  skrll   valueT mask = ((valueT) 1 << align) - 1;
    847  1.1  skrll 
    848  1.1  skrll   return (size + mask) & ~mask;
    849  1.1  skrll }
    850  1.1  skrll 
    851  1.1  skrll /* Where a PC relative offset is calculated from.  On the spu they
    852  1.1  skrll    are calculated from the beginning of the branch instruction.  */
    853  1.1  skrll 
    854  1.1  skrll long
    855  1.1  skrll md_pcrel_from (fixS *fixp)
    856  1.1  skrll {
    857  1.1  skrll   return fixp->fx_frag->fr_address + fixp->fx_where;
    858  1.1  skrll }
    859  1.1  skrll 
    860  1.1  skrll /* Fill in rs_align_code fragments.  */
    861  1.1  skrll 
    862  1.1  skrll void
    863  1.1  skrll spu_handle_align (fragS *fragp)
    864  1.1  skrll {
    865  1.1  skrll   static const unsigned char nop_pattern[8] = {
    866  1.1  skrll     0x40, 0x20, 0x00, 0x00, /* even nop */
    867  1.1  skrll     0x00, 0x20, 0x00, 0x00, /* odd  nop */
    868  1.1  skrll   };
    869  1.1  skrll 
    870  1.1  skrll   int bytes;
    871  1.1  skrll   char *p;
    872  1.1  skrll 
    873  1.1  skrll   if (fragp->fr_type != rs_align_code)
    874  1.1  skrll     return;
    875  1.1  skrll 
    876  1.1  skrll   bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
    877  1.1  skrll   p = fragp->fr_literal + fragp->fr_fix;
    878  1.1  skrll 
    879  1.1  skrll   if (bytes & 3)
    880  1.1  skrll     {
    881  1.1  skrll       int fix = bytes & 3;
    882  1.1  skrll       memset (p, 0, fix);
    883  1.1  skrll       p += fix;
    884  1.1  skrll       bytes -= fix;
    885  1.1  skrll       fragp->fr_fix += fix;
    886  1.1  skrll     }
    887  1.1  skrll   if (bytes & 4)
    888  1.1  skrll     {
    889  1.1  skrll       memcpy (p, &nop_pattern[4], 4);
    890  1.1  skrll       p += 4;
    891  1.1  skrll       bytes -= 4;
    892  1.1  skrll       fragp->fr_fix += 4;
    893  1.1  skrll     }
    894  1.1  skrll 
    895  1.1  skrll   memcpy (p, nop_pattern, 8);
    896  1.1  skrll   fragp->fr_var = 8;
    897  1.1  skrll }
    898  1.1  skrll 
    899  1.1  skrll void
    900  1.1  skrll md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
    901  1.1  skrll {
    902  1.1  skrll   unsigned int res;
    903  1.1  skrll   valueT val = *valP;
    904  1.1  skrll   char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
    905  1.1  skrll 
    906  1.1  skrll   if (fixP->fx_subsy != (symbolS *) NULL)
    907  1.1  skrll     {
    908  1.1  skrll       /* We can't actually support subtracting a symbol.  */
    909  1.1  skrll       as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
    910  1.1  skrll     }
    911  1.1  skrll 
    912  1.1  skrll   if (fixP->fx_addsy != NULL)
    913  1.1  skrll     {
    914  1.1  skrll       if (fixP->fx_pcrel)
    915  1.1  skrll 	{
    916  1.1  skrll 	  /* Hack around bfd_install_relocation brain damage.  */
    917  1.1  skrll 	  val += fixP->fx_frag->fr_address + fixP->fx_where;
    918  1.1  skrll 
    919  1.1  skrll 	  switch (fixP->fx_r_type)
    920  1.1  skrll 	    {
    921  1.1  skrll 	    case BFD_RELOC_32:
    922  1.1  skrll 	      fixP->fx_r_type = BFD_RELOC_32_PCREL;
    923  1.1  skrll 	      break;
    924  1.1  skrll 
    925  1.1  skrll 	    case BFD_RELOC_SPU_PCREL16:
    926  1.1  skrll 	    case BFD_RELOC_SPU_PCREL9a:
    927  1.1  skrll 	    case BFD_RELOC_SPU_PCREL9b:
    928  1.1  skrll 	    case BFD_RELOC_32_PCREL:
    929  1.1  skrll 	      break;
    930  1.1  skrll 
    931  1.1  skrll 	    default:
    932  1.1  skrll 	      as_bad_where (fixP->fx_file, fixP->fx_line,
    933  1.1  skrll 			    _("expression too complex"));
    934  1.1  skrll 	      break;
    935  1.1  skrll 	    }
    936  1.1  skrll 	}
    937  1.1  skrll     }
    938  1.1  skrll 
    939  1.1  skrll   fixP->fx_addnumber = val;
    940  1.1  skrll 
    941  1.1  skrll   if (fixP->fx_r_type == BFD_RELOC_SPU_PPU32
    942  1.1  skrll       || fixP->fx_r_type == BFD_RELOC_SPU_PPU64)
    943  1.1  skrll     return;
    944  1.1  skrll 
    945  1.1  skrll   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
    946  1.1  skrll     {
    947  1.1  skrll       fixP->fx_done = 1;
    948  1.1  skrll       res = 0;
    949  1.1  skrll       if (fixP->tc_fix_data.arg_format > A_P)
    950  1.1  skrll 	{
    951  1.1  skrll 	  int hi = arg_encode[fixP->tc_fix_data.arg_format].hi;
    952  1.1  skrll 	  int lo = arg_encode[fixP->tc_fix_data.arg_format].lo;
    953  1.1  skrll 	  if (hi > lo && ((offsetT) val < lo || (offsetT) val > hi))
    954  1.1  skrll 	    as_bad_where (fixP->fx_file, fixP->fx_line,
    955  1.1  skrll 			  "Relocation doesn't fit. (relocation value = 0x%lx)",
    956  1.1  skrll 			  (long) val);
    957  1.1  skrll 	}
    958  1.1  skrll 
    959  1.1  skrll       switch (fixP->fx_r_type)
    960  1.1  skrll         {
    961  1.1  skrll         case BFD_RELOC_8:
    962  1.1  skrll 	  md_number_to_chars (place, val, 1);
    963  1.1  skrll 	  return;
    964  1.1  skrll 
    965  1.1  skrll         case BFD_RELOC_16:
    966  1.1  skrll 	  md_number_to_chars (place, val, 2);
    967  1.1  skrll 	  return;
    968  1.1  skrll 
    969  1.1  skrll         case BFD_RELOC_32:
    970  1.1  skrll 	case BFD_RELOC_32_PCREL:
    971  1.1  skrll 	  md_number_to_chars (place, val, 4);
    972  1.1  skrll 	  return;
    973  1.1  skrll 
    974  1.1  skrll         case BFD_RELOC_64:
    975  1.1  skrll 	  md_number_to_chars (place, val, 8);
    976  1.1  skrll 	  return;
    977  1.1  skrll 
    978  1.1  skrll         case BFD_RELOC_SPU_IMM7:
    979  1.1  skrll           res = (val & 0x7f) << 14;
    980  1.1  skrll           break;
    981  1.1  skrll 
    982  1.1  skrll         case BFD_RELOC_SPU_IMM8:
    983  1.1  skrll           res = (val & 0xff) << 14;
    984  1.1  skrll           break;
    985  1.1  skrll 
    986  1.1  skrll         case BFD_RELOC_SPU_IMM10:
    987  1.1  skrll           res = (val & 0x3ff) << 14;
    988  1.1  skrll           break;
    989  1.1  skrll 
    990  1.1  skrll         case BFD_RELOC_SPU_IMM10W:
    991  1.1  skrll           res = (val & 0x3ff0) << 10;
    992  1.1  skrll           break;
    993  1.1  skrll 
    994  1.1  skrll         case BFD_RELOC_SPU_IMM16:
    995  1.1  skrll           res = (val & 0xffff) << 7;
    996  1.1  skrll           break;
    997  1.1  skrll 
    998  1.1  skrll         case BFD_RELOC_SPU_IMM16W:
    999  1.1  skrll           res = (val & 0x3fffc) << 5;
   1000  1.1  skrll           break;
   1001  1.1  skrll 
   1002  1.1  skrll         case BFD_RELOC_SPU_IMM18:
   1003  1.1  skrll           res = (val & 0x3ffff) << 7;
   1004  1.1  skrll           break;
   1005  1.1  skrll 
   1006  1.1  skrll         case BFD_RELOC_SPU_PCREL9a:
   1007  1.1  skrll           res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14);
   1008  1.1  skrll           break;
   1009  1.1  skrll 
   1010  1.1  skrll         case BFD_RELOC_SPU_PCREL9b:
   1011  1.1  skrll           res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5);
   1012  1.1  skrll           break;
   1013  1.1  skrll 
   1014  1.1  skrll         case BFD_RELOC_SPU_PCREL16:
   1015  1.1  skrll           res = (val & 0x3fffc) << 5;
   1016  1.1  skrll           break;
   1017  1.1  skrll 
   1018  1.1  skrll 	case BFD_RELOC_SPU_HI16:
   1019  1.1  skrll 	  res = (val >> 9) & 0x7fff80;
   1020  1.1  skrll 	  break;
   1021  1.1  skrll 
   1022  1.1  skrll 	case BFD_RELOC_SPU_LO16:
   1023  1.1  skrll 	  res = (val << 7) & 0x7fff80;
   1024  1.1  skrll 	  break;
   1025  1.1  skrll 
   1026  1.1  skrll         default:
   1027  1.1  skrll           as_bad_where (fixP->fx_file, fixP->fx_line,
   1028  1.1  skrll                         _("reloc %d not supported by object file format"),
   1029  1.1  skrll                         (int) fixP->fx_r_type);
   1030  1.1  skrll         }
   1031  1.1  skrll 
   1032  1.1  skrll       if (res != 0)
   1033  1.1  skrll         {
   1034  1.1  skrll           place[0] |= (res >> 24) & 0xff;
   1035  1.1  skrll           place[1] |= (res >> 16) & 0xff;
   1036  1.1  skrll           place[2] |= (res >> 8) & 0xff;
   1037  1.1  skrll           place[3] |= (res) & 0xff;
   1038  1.1  skrll         }
   1039                 }
   1040             }
   1041