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