Upload Tizen:Base source
[external/binutils.git] / gas / config / tc-moxie.c
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 \f
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 }