xref: /netbsd-src/external/gpl3/binutils/dist/gas/config/tc-moxie.c (revision 1897181a7231d5fc7ab48994d1447fcbc4e13a49)
1 /* tc-moxie.c -- Assemble code for moxie
2    Copyright 2009
3    Free Software Foundation, Inc.
4 
5    This file is part of GAS, the GNU Assembler.
6 
7    GAS is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    GAS is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GAS; see the file COPYING.  If not, write to
19    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21 
22 /* Contributed by Anthony Green <green@moxielogic.com>.  */
23 
24 #include "as.h"
25 #include "safe-ctype.h"
26 #include "opcode/moxie.h"
27 #include "elf/moxie.h"
28 
29 extern const moxie_opc_info_t moxie_opc_info[128];
30 
31 const char comment_chars[]        = "#";
32 const char line_separator_chars[] = ";";
33 const char line_comment_chars[]   = "#";
34 
35 static int pending_reloc;
36 static struct hash_control *opcode_hash_control;
37 
38 const pseudo_typeS md_pseudo_table[] =
39 {
40   {0, 0, 0}
41 };
42 
43 const char FLT_CHARS[] = "rRsSfFdDxXpP";
44 const char EXP_CHARS[] = "eE";
45 
46 static int md_chars_to_number (char *val, int n);
47 
48 void
49 md_operand (expressionS *op __attribute__((unused)))
50 {
51   /* Empty for now. */
52 }
53 
54 /* This function is called once, at assembler startup time.  It sets
55    up the hash table with all the opcodes in it, and also initializes
56    some aliases for compatibility with other assemblers.  */
57 
58 void
59 md_begin (void)
60 {
61   int count;
62   const moxie_opc_info_t *opcode;
63   opcode_hash_control = hash_new ();
64 
65   /* Insert names into hash table.  */
66   for (count = 0, opcode = moxie_form1_opc_info; count++ < 64; opcode++)
67     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
68 
69   for (count = 0, opcode = moxie_form2_opc_info; count++ < 4; opcode++)
70     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
71 
72   for (count = 0, opcode = moxie_form3_opc_info; count++ < 10; opcode++)
73     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
74 
75   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
76 }
77 
78 /* Parse an expression and then restore the input line pointer.  */
79 
80 static char *
81 parse_exp_save_ilp (char *s, expressionS *op)
82 {
83   char *save = input_line_pointer;
84 
85   input_line_pointer = s;
86   expression (op);
87   s = input_line_pointer;
88   input_line_pointer = save;
89   return s;
90 }
91 
92 static int
93 parse_register_operand (char **ptr)
94 {
95   int reg;
96   char *s = *ptr;
97 
98   if (*s != '$')
99     {
100       as_bad (_("expecting register"));
101       ignore_rest_of_line ();
102       return -1;
103     }
104   if (s[1] == 'f' && s[2] == 'p')
105     {
106       *ptr += 3;
107       return 0;
108     }
109   if (s[1] == 's' && s[2] == 'p')
110     {
111       *ptr += 3;
112       return 1;
113     }
114   if (s[1] == 'r')
115     {
116       reg = s[2] - '0';
117       if ((reg < 0) || (reg > 9))
118 	{
119 	  as_bad (_("illegal register number"));
120 	  ignore_rest_of_line ();
121 	  return -1;
122 	}
123       if (reg == 1)
124 	{
125 	  int r2 = s[3] - '0';
126 	  if ((r2 >= 0) && (r2 <= 3))
127 	    {
128 	      reg = 10 + r2;
129 	      *ptr += 1;
130 	    }
131 	}
132     }
133   else
134     {
135       as_bad (_("illegal register number"));
136       ignore_rest_of_line ();
137       return -1;
138     }
139 
140   *ptr += 3;
141 
142   return reg + 2;
143 }
144 
145 /* This is the guts of the machine-dependent assembler.  STR points to
146    a machine dependent instruction.  This function is supposed to emit
147    the frags/bytes it assembles to.  */
148 
149 void
150 md_assemble (char *str)
151 {
152   char *op_start;
153   char *op_end;
154 
155   moxie_opc_info_t *opcode;
156   char *p;
157   char pend;
158 
159   unsigned short iword = 0;
160 
161   int nlen = 0;
162 
163   /* Drop leading whitespace.  */
164   while (*str == ' ')
165     str++;
166 
167   /* Find the op code end.  */
168   op_start = str;
169   for (op_end = str;
170        *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
171        op_end++)
172     nlen++;
173 
174   pend = *op_end;
175   *op_end = 0;
176 
177   if (nlen == 0)
178     as_bad (_("can't find opcode "));
179   opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start);
180   *op_end = pend;
181 
182   if (opcode == NULL)
183     {
184       as_bad (_("unknown opcode %s"), op_start);
185       return;
186     }
187 
188   p = frag_more (2);
189 
190   switch (opcode->itype)
191     {
192     case MOXIE_F2_A8V:
193       iword = (1<<15) | (opcode->opcode << 12);
194       while (ISSPACE (*op_end))
195 	op_end++;
196       {
197 	expressionS arg;
198 	int reg;
199 	reg = parse_register_operand (&op_end);
200 	iword += (reg << 8);
201 	if (*op_end != ',')
202 	  as_warn (_("expecting comma delimited register operands"));
203 	op_end++;
204 	op_end = parse_exp_save_ilp (op_end, &arg);
205 	fix_new_exp (frag_now,
206 		     ((p+1) - frag_now->fr_literal),
207 		     1,
208 		     &arg,
209 		     0,
210 		     BFD_RELOC_8);
211       }
212       break;
213     case MOXIE_F1_AB:
214       iword = opcode->opcode << 8;
215       while (ISSPACE (*op_end))
216 	op_end++;
217       {
218 	int dest, src;
219 	dest = parse_register_operand (&op_end);
220 	if (*op_end != ',')
221 	  as_warn (_("expecting comma delimited register operands"));
222 	op_end++;
223 	src  = parse_register_operand (&op_end);
224 	iword += (dest << 4) + src;
225 	while (ISSPACE (*op_end))
226 	  op_end++;
227 	if (*op_end != 0)
228 	  as_warn (_("extra stuff on line ignored"));
229       }
230       break;
231     case MOXIE_F1_A4:
232       iword = opcode->opcode << 8;
233       while (ISSPACE (*op_end))
234 	op_end++;
235       {
236 	expressionS arg;
237 	char *where;
238 	int regnum;
239 
240  	regnum = parse_register_operand (&op_end);
241 	while (ISSPACE (*op_end))
242 	  op_end++;
243 
244 	iword += (regnum << 4);
245 
246 	if (*op_end != ',')
247 	  {
248 	    as_bad (_("expecting comma delimited operands"));
249 	    ignore_rest_of_line ();
250 	    return;
251 	  }
252 	op_end++;
253 
254 	op_end = parse_exp_save_ilp (op_end, &arg);
255 	where = frag_more (4);
256 	fix_new_exp (frag_now,
257 		     (where - frag_now->fr_literal),
258 		     4,
259 		     &arg,
260 		     0,
261 		     BFD_RELOC_32);
262       }
263       break;
264     case MOXIE_F1_M:
265     case MOXIE_F1_4:
266       iword = opcode->opcode << 8;
267       while (ISSPACE (*op_end))
268 	op_end++;
269       {
270 	expressionS arg;
271 	char *where;
272 
273 	op_end = parse_exp_save_ilp (op_end, &arg);
274 	where = frag_more (4);
275 	fix_new_exp (frag_now,
276 		     (where - frag_now->fr_literal),
277 		     4,
278 		     &arg,
279 		     0,
280 		     BFD_RELOC_32);
281       }
282       break;
283     case MOXIE_F1_NARG:
284       iword = opcode->opcode << 8;
285       while (ISSPACE (*op_end))
286 	op_end++;
287       if (*op_end != 0)
288 	as_warn (_("extra stuff on line ignored"));
289       break;
290     case MOXIE_F1_A:
291       iword = opcode->opcode << 8;
292       while (ISSPACE (*op_end))
293 	op_end++;
294       {
295 	int reg;
296 	reg = parse_register_operand (&op_end);
297 	while (ISSPACE (*op_end))
298 	  op_end++;
299 	if (*op_end != 0)
300 	  as_warn (_("extra stuff on line ignored"));
301 	iword += (reg << 4);
302       }
303       break;
304     case MOXIE_F1_ABi:
305       iword = opcode->opcode << 8;
306       while (ISSPACE (*op_end))
307 	op_end++;
308       {
309 	int a, b;
310 	a = parse_register_operand (&op_end);
311 	if (*op_end != ',')
312 	  as_warn (_("expecting comma delimited register operands"));
313 	op_end++;
314 	if (*op_end != '(')
315 	  {
316 	    as_bad (_("expecting indirect register `($rA)'"));
317 	    ignore_rest_of_line ();
318 	    return;
319 	  }
320 	op_end++;
321 	b = parse_register_operand (&op_end);
322 	if (*op_end != ')')
323 	  {
324 	    as_bad (_("missing closing parenthesis"));
325 	    ignore_rest_of_line ();
326 	    return;
327 	  }
328 	op_end++;
329 	iword += (a << 4) + b;
330 	while (ISSPACE (*op_end))
331 	  op_end++;
332 	if (*op_end != 0)
333 	  as_warn (_("extra stuff on line ignored"));
334       }
335       break;
336     case MOXIE_F1_AiB:
337       iword = opcode->opcode << 8;
338       while (ISSPACE (*op_end))
339 	op_end++;
340       {
341 	int a, b;
342 	if (*op_end != '(')
343 	  {
344 	    as_bad (_("expecting indirect register `($rA)'"));
345 	    ignore_rest_of_line ();
346 	    return;
347 	  }
348 	op_end++;
349 	a = parse_register_operand (&op_end);
350 	if (*op_end != ')')
351 	  {
352 	    as_bad (_("missing closing parenthesis"));
353 	    ignore_rest_of_line ();
354 	    return;
355 	  }
356 	op_end++;
357 	if (*op_end != ',')
358 	  as_warn (_("expecting comma delimited register operands"));
359 	op_end++;
360 	b = parse_register_operand (&op_end);
361 	iword += (a << 4) + b;
362 	while (ISSPACE (*op_end))
363 	  op_end++;
364 	if (*op_end != 0)
365 	  as_warn (_("extra stuff on line ignored"));
366       }
367       break;
368     case MOXIE_F1_4A:
369       iword = opcode->opcode << 8;
370       while (ISSPACE (*op_end))
371 	op_end++;
372       {
373 	expressionS arg;
374 	char *where;
375 	int a;
376 
377 	op_end = parse_exp_save_ilp (op_end, &arg);
378 	where = frag_more (4);
379 	fix_new_exp (frag_now,
380 		     (where - frag_now->fr_literal),
381 		     4,
382 		     &arg,
383 		     0,
384 		     BFD_RELOC_32);
385 
386 	if (*op_end != ',')
387 	  {
388 	    as_bad (_("expecting comma delimited operands"));
389 	    ignore_rest_of_line ();
390 	    return;
391 	  }
392 	op_end++;
393 
394  	a = parse_register_operand (&op_end);
395 	while (ISSPACE (*op_end))
396 	  op_end++;
397 	if (*op_end != 0)
398 	  as_warn (_("extra stuff on line ignored"));
399 
400 	iword += (a << 4);
401       }
402       break;
403     case MOXIE_F1_ABi4:
404       iword = opcode->opcode << 8;
405       while (ISSPACE (*op_end))
406 	op_end++;
407       {
408 	expressionS arg;
409 	char *offset;
410 	int a, b;
411 
412  	a = parse_register_operand (&op_end);
413 	while (ISSPACE (*op_end))
414 	  op_end++;
415 
416 	if (*op_end != ',')
417 	  {
418 	    as_bad (_("expecting comma delimited operands"));
419 	    ignore_rest_of_line ();
420 	    return;
421 	  }
422 	op_end++;
423 
424 	op_end = parse_exp_save_ilp (op_end, &arg);
425 	offset = frag_more (4);
426 	fix_new_exp (frag_now,
427 		     (offset - frag_now->fr_literal),
428 		     4,
429 		     &arg,
430 		     0,
431 		     BFD_RELOC_32);
432 
433 	if (*op_end != '(')
434 	  {
435 	    as_bad (_("expecting indirect register `($rX)'"));
436 	    ignore_rest_of_line ();
437 	    return;
438 	  }
439 	op_end++;
440 	b = parse_register_operand (&op_end);
441 	if (*op_end != ')')
442 	  {
443 	    as_bad (_("missing closing parenthesis"));
444 	    ignore_rest_of_line ();
445 	    return;
446 	  }
447 	op_end++;
448 
449 	while (ISSPACE (*op_end))
450 	  op_end++;
451 	if (*op_end != 0)
452 	  as_warn (_("extra stuff on line ignored"));
453 
454 	iword += (a << 4) + b;
455       }
456       break;
457     case MOXIE_F1_AiB4:
458       iword = opcode->opcode << 8;
459       while (ISSPACE (*op_end))
460 	op_end++;
461       {
462 	expressionS arg;
463 	char *offset;
464 	int a, b;
465 
466 	op_end = parse_exp_save_ilp (op_end, &arg);
467 	offset = frag_more (4);
468 	fix_new_exp (frag_now,
469 		     (offset - frag_now->fr_literal),
470 		     4,
471 		     &arg,
472 		     0,
473 		     BFD_RELOC_32);
474 
475 	if (*op_end != '(')
476 	  {
477 	    as_bad (_("expecting indirect register `($rX)'"));
478 	    ignore_rest_of_line ();
479 	    return;
480 	  }
481 	op_end++;
482 	a = parse_register_operand (&op_end);
483 	if (*op_end != ')')
484 	  {
485 	    as_bad (_("missing closing parenthesis"));
486 	    ignore_rest_of_line ();
487 	    return;
488 	  }
489 	op_end++;
490 
491 	if (*op_end != ',')
492 	  {
493 	    as_bad (_("expecting comma delimited operands"));
494 	    ignore_rest_of_line ();
495 	    return;
496 	  }
497 	op_end++;
498 
499  	b = parse_register_operand (&op_end);
500 	while (ISSPACE (*op_end))
501 	  op_end++;
502 
503 	while (ISSPACE (*op_end))
504 	  op_end++;
505 	if (*op_end != 0)
506 	  as_warn (_("extra stuff on line ignored"));
507 
508 	iword += (a << 4) + b;
509       }
510       break;
511     case MOXIE_F2_NARG:
512       iword = opcode->opcode << 12;
513       while (ISSPACE (*op_end))
514 	op_end++;
515       if (*op_end != 0)
516 	as_warn (_("extra stuff on line ignored"));
517       break;
518     case MOXIE_F3_PCREL:
519       iword = (3<<14) | (opcode->opcode << 10);
520       while (ISSPACE (*op_end))
521 	op_end++;
522       {
523 	expressionS arg;
524 
525 	op_end = parse_exp_save_ilp (op_end, &arg);
526 	fix_new_exp (frag_now,
527 		     (p - frag_now->fr_literal),
528 		     2,
529 		     &arg,
530 		     TRUE,
531 		     BFD_RELOC_MOXIE_10_PCREL);
532       }
533       break;
534     default:
535       abort ();
536     }
537 
538   md_number_to_chars (p, iword, 2);
539 
540   while (ISSPACE (*op_end))
541     op_end++;
542 
543   if (*op_end != 0)
544     as_warn (_("extra stuff on line ignored"));
545 
546   if (pending_reloc)
547     as_bad (_("Something forgot to clean up\n"));
548 }
549 
550 /* Turn a string in input_line_pointer into a floating point constant
551    of type type, and store the appropriate bytes in *LITP.  The number
552    of LITTLENUMS emitted is stored in *SIZEP .  An error message is
553    returned, or NULL on OK.  */
554 
555 char *
556 md_atof (int type, char *litP, int *sizeP)
557 {
558   int prec;
559   LITTLENUM_TYPE words[4];
560   char *t;
561   int i;
562 
563   switch (type)
564     {
565     case 'f':
566       prec = 2;
567       break;
568 
569     case 'd':
570       prec = 4;
571       break;
572 
573     default:
574       *sizeP = 0;
575       return _("bad call to md_atof");
576     }
577 
578   t = atof_ieee (input_line_pointer, type, words);
579   if (t)
580     input_line_pointer = t;
581 
582   *sizeP = prec * 2;
583 
584   for (i = prec - 1; i >= 0; i--)
585     {
586       md_number_to_chars (litP, (valueT) words[i], 2);
587       litP += 2;
588     }
589 
590   return NULL;
591 }
592 
593 const char *md_shortopts = "";
594 
595 struct option md_longopts[] =
596 {
597   {NULL, no_argument, NULL, 0}
598 };
599 size_t md_longopts_size = sizeof (md_longopts);
600 
601 /* We have no target specific options yet, so these next
602    two functions are empty.  */
603 int
604 md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
605 {
606   return 0;
607 }
608 
609 void
610 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
611 {
612 }
613 
614 /* Apply a fixup to the object file.  */
615 
616 void
617 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
618 	      valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
619 {
620   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
621   long val = *valP;
622   long newval;
623   long max, min;
624 
625   max = min = 0;
626   switch (fixP->fx_r_type)
627     {
628     case BFD_RELOC_32:
629       *buf++ = val >> 24;
630       *buf++ = val >> 16;
631       *buf++ = val >> 8;
632       *buf++ = val >> 0;
633       break;
634 
635     case BFD_RELOC_16:
636       *buf++ = val >> 8;
637       *buf++ = val >> 0;
638       break;
639 
640     case BFD_RELOC_8:
641       *buf++ = val;
642       break;
643 
644     case BFD_RELOC_MOXIE_10_PCREL:
645       if (!val)
646 	break;
647       if (val < -1024 || val > 1022)
648 	as_bad_where (fixP->fx_file, fixP->fx_line,
649                       _("pcrel too far BFD_RELOC_MOXIE_10"));
650       /* 11 bit offset even numbered, so we remove right bit.  */
651       val >>= 1;
652       newval = md_chars_to_number (buf, 2);
653       newval |= val & 0x03ff;
654       md_number_to_chars (buf, newval, 2);
655       break;
656 
657     default:
658       abort ();
659     }
660 
661   if (max != 0 && (val < min || val > max))
662     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
663 
664   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
665     fixP->fx_done = 1;
666 }
667 
668 /* Put number into target byte order (big endian).  */
669 
670 void
671 md_number_to_chars (char *ptr, valueT use, int nbytes)
672 {
673   number_to_chars_bigendian (ptr, use, nbytes);
674 }
675 
676 /* Convert from target byte order to host byte order.  */
677 
678 static int
679 md_chars_to_number (char *val, int n)
680 {
681   int retval = 0;
682 
683   while (n--)
684     {
685       retval <<= 8;
686       retval |= (*val++ & 255);
687     }
688 
689   return retval;
690 }
691 
692 /* Generate a machine-dependent relocation.  */
693 arelent *
694 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
695 {
696   arelent *relP;
697   bfd_reloc_code_real_type code;
698 
699   switch (fixP->fx_r_type)
700     {
701     case BFD_RELOC_32:
702       code = fixP->fx_r_type;
703       break;
704     case BFD_RELOC_MOXIE_10_PCREL:
705       code = fixP->fx_r_type;
706       break;
707     default:
708       as_bad_where (fixP->fx_file, fixP->fx_line,
709 		    _("Semantics error.  This type of operand can not be relocated, it must be an assembly-time constant"));
710       return 0;
711     }
712 
713   relP = xmalloc (sizeof (arelent));
714   gas_assert (relP != 0);
715   relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
716   *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
717   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
718 
719   relP->addend = fixP->fx_offset;
720 
721   /* This is the standard place for KLUDGEs to work around bugs in
722      bfd_install_relocation (first such note in the documentation
723      appears with binutils-2.8).
724 
725      That function bfd_install_relocation does the wrong thing with
726      putting stuff into the addend of a reloc (it should stay out) for a
727      weak symbol.  The really bad thing is that it adds the
728      "segment-relative offset" of the symbol into the reloc.  In this
729      case, the reloc should instead be relative to the symbol with no
730      other offset than the assembly code shows; and since the symbol is
731      weak, any local definition should be ignored until link time (or
732      thereafter).
733      To wit:  weaksym+42  should be weaksym+42 in the reloc,
734      not weaksym+(offset_from_segment_of_local_weaksym_definition)
735 
736      To "work around" this, we subtract the segment-relative offset of
737      "known" weak symbols.  This evens out the extra offset.
738 
739      That happens for a.out but not for ELF, since for ELF,
740      bfd_install_relocation uses the "special function" field of the
741      howto, and does not execute the code that needs to be undone.  */
742 
743   if (OUTPUT_FLAVOR == bfd_target_aout_flavour
744       && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)
745       && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy)))
746     {
747       relP->addend -= S_GET_VALUE (fixP->fx_addsy);
748     }
749 
750   relP->howto = bfd_reloc_type_lookup (stdoutput, code);
751   if (! relP->howto)
752     {
753       const char *name;
754 
755       name = S_GET_NAME (fixP->fx_addsy);
756       if (name == NULL)
757 	name = _("<unknown>");
758       as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
759 		name, bfd_get_reloc_code_name (code));
760     }
761 
762   return relP;
763 }
764 
765 /* Decide from what point a pc-relative relocation is relative to,
766    relative to the pc-relative fixup.  Er, relatively speaking.  */
767 long
768 md_pcrel_from (fixS *fixP)
769 {
770   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
771 
772   switch (fixP->fx_r_type)
773     {
774     case BFD_RELOC_32:
775       return addr + 4;
776     case BFD_RELOC_MOXIE_10_PCREL:
777       return addr;
778     default:
779       abort ();
780       return addr;
781     }
782 }
783