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