tc-spu.c 27 KB

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