ac7ca12edec329009f83e550543a966bd7c772f2
[binutils-gdb.git] / gas / config / tc-txvu.c
1 /* tc-txvu.c -- Assembler for the TX VU.
2 Copyright (C) 1997 Free Software Foundation.
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "as.h"
24 #include "subsegs.h"
25 /* Needed by opcode/txvu.h. */
26 #include "dis-asm.h"
27 #include "opcode/txvu.h"
28 #include "elf/txvu.h"
29
30 static TXVU_INSN txvu_insert_operand
31 PARAMS ((TXVU_INSN, const struct txvu_operand *, int, offsetT,
32 char *, unsigned int));
33
34 const char comment_chars[] = ";";
35 const char line_comment_chars[] = "#";
36 const char line_separator_chars[] = "!";
37 const char EXP_CHARS[] = "eE";
38 const char FLT_CHARS[] = "dD";
39 \f
40 const char *md_shortopts = "";
41
42 struct option md_longopts[] =
43 {
44 /* insert options here */
45
46 {NULL, no_argument, NULL, 0}
47 };
48 size_t md_longopts_size = sizeof(md_longopts);
49
50 int
51 md_parse_option (c, arg)
52 int c;
53 char *arg;
54 {
55 return 0;
56 }
57
58 void
59 md_show_usage (stream)
60 FILE *stream;
61 {
62 #if 0
63 fprintf (stream, "TX VU options:\n");
64 #endif
65 }
66
67 /* Set by md_assemble for use by txvu_fill_insn. */
68 static subsegT prev_subseg;
69 static segT prev_seg;
70
71 /* The target specific pseudo-ops which we support. */
72 const pseudo_typeS md_pseudo_table[] =
73 {
74 { "word", cons, 4 },
75 { NULL, NULL, 0 }
76 };
77 \f
78 void
79 md_begin ()
80 {
81 flagword applicable;
82 segT seg;
83 subsegT subseg;
84
85 /* Save the current subseg so we can restore it [it's the default one and
86 we don't want the initial section to be .sbss. */
87 seg = now_seg;
88 subseg = now_subseg;
89
90 subseg_set (seg, subseg);
91
92 /* Initialize the opcode tables.
93 This involves computing the hash chains. */
94 txvu_opcode_init_tables (0);
95 }
96
97 /* We need to keep a list of fixups. We can't simply generate them as
98 we go, because that would require us to first create the frag, and
99 that would screw up references to ``.''. */
100
101 struct txvu_fixup
102 {
103 /* index into `txvu_operands' */
104 int opindex;
105 expressionS exp;
106 };
107
108 #define MAX_FIXUPS 5
109
110 static char * assemble_insn PARAMS ((char *, int, char *));
111
112 void
113 md_assemble (str)
114 char *str;
115 {
116 /* The lower instruction has the lower address.
117 Handle this by grabbing 8 bytes now, and then filling each word
118 as appropriate. */
119 char *f = frag_more (8);
120
121 #ifdef VERTICAL_BAR_SEPARATOR
122 char *p = strchr (str, '|');
123
124 if (p == NULL)
125 {
126 as_bad ("lower slot missing in `%s'", str);
127 return;
128 }
129
130 *p = 0;
131 assemble_insn (str, 0, f + 4);
132 *p = '|';
133 assemble_insn (p + 1, 1, f);
134 #else
135 str = assemble_insn (str, 0, f + 4);
136 /* Don't assemble next one if we couldn't assemble the first. */
137 if (str)
138 assemble_insn (str, 1, f);
139 #endif
140 }
141
142 /* Assemble one instruction.
143 LOWER_P is non-zero if assembling in the lower insn slot.
144 The result is a pointer to beyond the end of the scanned insn
145 or NULL if an error occured.
146 If this is the upper insn, the caller can pass back to result to us
147 parse the lower insn. */
148
149 static char *
150 assemble_insn (str, lower_p, buf)
151 char *str;
152 int lower_p;
153 char *buf;
154 {
155 const struct txvu_opcode *opcode;
156 char *start;
157 TXVU_INSN insn_buf[2];
158 TXVU_INSN insn;
159
160 /* Skip leading white space. */
161 while (isspace (*str))
162 str++;
163
164 /* The instructions are stored in lists hashed by the first letter (though
165 we needn't care how they're hashed). Get the first in the list. */
166
167 if (lower_p)
168 opcode = txvu_lower_opcode_lookup_asm (str);
169 else
170 opcode = txvu_upper_opcode_lookup_asm (str);
171
172 /* Keep looking until we find a match. */
173
174 start = str;
175 for ( ; opcode != NULL; opcode = TXVU_OPCODE_NEXT_ASM (opcode))
176 {
177 int past_opcode_p, fc, num_suffixes, num_operands;
178 const unsigned char *syn;
179 struct txvu_fixup fixups[MAX_FIXUPS];
180
181 /* Ensure the mnemonic part matches. */
182 for (str = start, syn = opcode->mnemonic; *syn != '\0'; ++str, ++syn)
183 if (tolower (*str) != tolower (*syn))
184 break;
185 if (*syn != '\0')
186 continue;
187 if (isalpha (*str))
188 continue;
189
190 /* Scan the syntax string. If it doesn't match, try the next one. */
191
192 txvu_opcode_init_parse ();
193 insn = opcode->value;
194 fc = 0;
195 past_opcode_p = 0;
196 num_suffixes = 0;
197 num_operands = 0;
198
199 /* We don't check for (*str != '\0') here because we want to parse
200 any trailing fake arguments in the syntax string. */
201 for (/*str = start, */ syn = opcode->syntax; *syn != '\0'; )
202 {
203 int mods,index;
204 const struct txvu_operand *operand;
205 const char *errmsg;
206
207 /* Non operand chars must match exactly. */
208 if (*syn < 128)
209 {
210 if (*str == *syn)
211 {
212 if (*syn == ' ')
213 past_opcode_p = 1;
214 ++syn;
215 ++str;
216 }
217 else
218 break;
219 continue;
220 }
221
222 /* We have a suffix or an operand. Pick out any modifiers. */
223 mods = 0;
224 index = TXVU_OPERAND_INDEX (*syn);
225 while (TXVU_MOD_P (txvu_operands[index].flags))
226 {
227 mods |= txvu_operands[index].flags & TXVU_MOD_BITS;
228 ++syn;
229 index = TXVU_OPERAND_INDEX (*syn);
230 }
231 operand = txvu_operands + index;
232
233 if (operand->flags & TXVU_OPERAND_FAKE)
234 {
235 if (operand->insert)
236 {
237 insn = (*operand->insert) (insn, operand, mods, 0, &errmsg);
238 /* If we get an error, go on to try the next insn. */
239 if (errmsg)
240 break;
241 }
242 ++syn;
243 }
244 /* Are we finished with suffixes? */
245 else if (!past_opcode_p)
246 {
247 int found;
248 char c;
249 char *s,*t;
250 long suf_value;
251
252 if (!(operand->flags & TXVU_OPERAND_SUFFIX))
253 as_fatal ("bad opcode table, missing suffix flag");
254
255 /* If we're at a space in the input string, we want to skip the
256 remaining suffixes. There may be some fake ones though, so
257 just go on to try the next one. */
258 if (*str == ' ')
259 {
260 ++syn;
261 continue;
262 }
263
264 s = str;
265
266 /* Pick the suffix out and parse it. */
267 for (t = *s == '.' ? s + 1 : s; *t && isalpha (*t); ++t)
268 continue;
269 c = *t;
270 *t = '\0';
271 suf_value = (*operand->parse) (&s, &errmsg);
272 *t = c;
273 if (errmsg)
274 {
275 /* This can happen in "blle foo" and we're currently using
276 the template "b%q%.n %j". The "bl" insn occurs later in
277 the table so "lle" isn't an illegal suffix. */
278 break;
279 }
280 /* Insert the suffix's value into the insn. */
281 if (operand->insert)
282 insn = (*operand->insert) (insn, operand,
283 mods, suf_value, NULL);
284 else
285 insn |= suf_value << operand->shift;
286
287 str = t;
288 ++syn;
289 }
290 else
291 /* This is an operand, either a register or an expression of
292 some kind. */
293 {
294 char c;
295 char *hold;
296 long value = 0;
297 expressionS exp;
298
299 if (operand->flags & TXVU_OPERAND_SUFFIX)
300 as_fatal ("bad opcode table, suffix wrong");
301
302 /* If this is not the first, there must be a comma. */
303 if (num_operands > 0)
304 {
305 if (*str != ',')
306 break;
307 ++str;
308 }
309
310 /* Is there anything left to parse?
311 We don't check for this at the top because we want to parse
312 any trailing fake arguments in the syntax string. */
313 if (*str == '\0')
314 break;
315
316 /* Parse the operand. */
317 if (operand->parse)
318 {
319 value = (*operand->parse) (&str, &errmsg);
320 if (errmsg)
321 break;
322 }
323 else
324 {
325 hold = input_line_pointer;
326 input_line_pointer = str;
327 expression (&exp);
328 str = input_line_pointer;
329 input_line_pointer = hold;
330
331 if (exp.X_op == O_illegal
332 || exp.X_op == O_absent)
333 break;
334 else if (exp.X_op == O_constant)
335 value = exp.X_add_number;
336 else if (exp.X_op == O_register)
337 as_fatal ("got O_register");
338 else
339 {
340 /* We need to generate a fixup for this expression. */
341 if (fc >= MAX_FIXUPS)
342 as_fatal ("too many fixups");
343 fixups[fc].exp = exp;
344 fixups[fc].opindex = index;
345 ++fc;
346 value = 0;
347 }
348 }
349
350 /* Insert the register or expression into the instruction. */
351 if (operand->insert)
352 {
353 const char *errmsg = NULL;
354 insn = (*operand->insert) (insn, operand, mods,
355 value, &errmsg);
356 #if 0
357 if (errmsg != (const char *) NULL)
358 as_warn (errmsg);
359 #endif
360 /* FIXME: We want to try shimm insns for limm ones. But if
361 the constant won't fit, we must go on to try the next
362 possibility. Where do we issue warnings for constants
363 that are too big then? At present, we'll flag the insn
364 as unrecognizable! Maybe have the "bad instruction"
365 error message include our `errmsg'? */
366 if (errmsg != (const char *) NULL)
367 break;
368 }
369 else
370 insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;
371
372 ++syn;
373 ++num_operands;
374 }
375 }
376
377 /* If we're at the end of the syntax string, we're done. */
378 /* FIXME: try to move this to a separate function. */
379 if (*syn == '\0')
380 {
381 int i;
382
383 /* For the moment we assume a valid `str' can only contain blanks
384 now. IE: We needn't try again with a longer version of the
385 insn and it is assumed that longer versions of insns appear
386 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
387
388 while (isspace (*str))
389 ++str;
390
391 if (*str != '\0'
392 #ifndef VERTICAL_BAR_SEPARATOR
393 && lower_p
394 #endif
395 )
396 as_bad ("junk at end of line: `%s'", str);
397
398 /* Write out the instruction.
399 Reminder: it is important to fetch enough space in one call to
400 `frag_more'. We use (f - frag_now->fr_literal) to compute where
401 we are and we don't want frag_now to change between calls. */
402 md_number_to_chars (buf, insn, 4);
403
404 /* Create any fixups. */
405 for (i = 0; i < fc; ++i)
406 {
407 int op_type, reloc_type;
408 const struct txvu_operand *operand;
409
410 /* Create a fixup for this operand.
411 At this point we do not use a bfd_reloc_code_real_type for
412 operands residing in the insn, but instead just use the
413 operand index. This lets us easily handle fixups for any
414 operand type, although that is admittedly not a very exciting
415 feature. We pick a BFD reloc type in md_apply_fix. */
416
417 op_type = fixups[i].opindex;
418 reloc_type = op_type + (int) BFD_RELOC_UNUSED;
419 operand = &txvu_operands[op_type];
420 fix_new_exp (frag_now, buf - frag_now->fr_literal, 4,
421 &fixups[i].exp,
422 (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0,
423 (bfd_reloc_code_real_type) reloc_type);
424 }
425
426 /* All done. */
427 return str;
428 }
429
430 /* Try the next entry. */
431 }
432
433 as_bad ("bad instruction `%s'", start);
434 return 0;
435 }
436
437 void
438 md_operand (expressionP)
439 expressionS *expressionP;
440 {
441 }
442
443 valueT
444 md_section_align (segment, size)
445 segT segment;
446 valueT size;
447 {
448 int align = bfd_get_section_alignment (stdoutput, segment);
449 return ((size + (1 << align) - 1) & (-1 << align));
450 }
451
452 symbolS *
453 md_undefined_symbol (name)
454 char *name;
455 {
456 return 0;
457 }
458 \f
459 /* Functions concerning relocs. */
460
461 /* The location from which a PC relative jump should be calculated,
462 given a PC relative reloc. */
463
464 long
465 md_pcrel_from_section (fixP, sec)
466 fixS *fixP;
467 segT sec;
468 {
469 if (fixP->fx_addsy != (symbolS *) NULL
470 && (! S_IS_DEFINED (fixP->fx_addsy)
471 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
472 {
473 /* The symbol is undefined (or is defined but not in this section).
474 Let the linker figure it out. */
475 return 0;
476 }
477
478 /* FIXME: `& -16L'? */
479 return (fixP->fx_frag->fr_address + fixP->fx_where) & -8L;
480 }
481
482 /* Apply a fixup to the object code. This is called for all the
483 fixups we generated by calls to fix_new_exp. At this point all symbol
484 values should be fully resolved, and we attempt to completely resolve the
485 reloc. If we can not do that, we determine the correct reloc code and put
486 it back in the fixup. */
487
488 int
489 md_apply_fix3 (fixP, valueP, seg)
490 fixS *fixP;
491 valueT *valueP;
492 segT seg;
493 {
494 char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
495 valueT value;
496
497 /* FIXME FIXME FIXME: The value we are passed in *valueP includes
498 the symbol values. Since we are using BFD_ASSEMBLER, if we are
499 doing this relocation the code in write.c is going to call
500 bfd_perform_relocation, which is also going to use the symbol
501 value. That means that if the reloc is fully resolved we want to
502 use *valueP since bfd_perform_relocation is not being used.
503 However, if the reloc is not fully resolved we do not want to use
504 *valueP, and must use fx_offset instead. However, if the reloc
505 is PC relative, we do want to use *valueP since it includes the
506 result of md_pcrel_from. This is confusing. */
507
508 if (fixP->fx_addsy == (symbolS *) NULL)
509 {
510 value = *valueP;
511 fixP->fx_done = 1;
512 }
513 else if (fixP->fx_pcrel)
514 {
515 value = *valueP;
516 }
517 else
518 {
519 value = fixP->fx_offset;
520 if (fixP->fx_subsy != (symbolS *) NULL)
521 {
522 if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
523 value -= S_GET_VALUE (fixP->fx_subsy);
524 else
525 {
526 /* We can't actually support subtracting a symbol. */
527 as_bad_where (fixP->fx_file, fixP->fx_line,
528 "expression too complex");
529 }
530 }
531 }
532
533 /* Check for txvu_operand's. These are indicated with a reloc value
534 >= BFD_RELOC_UNUSED. */
535
536 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
537 {
538 int opindex;
539 const struct txvu_operand *operand;
540 TXVU_INSN insn;
541
542 opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
543
544 operand = &txvu_operands[opindex];
545
546 /* Fetch the instruction, insert the fully resolved operand
547 value, and stuff the instruction back again. */
548 insn = bfd_getl32 ((unsigned char *) where);
549 insn = txvu_insert_operand (insn, operand, -1, (offsetT) value,
550 fixP->fx_file, fixP->fx_line);
551 bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
552
553 if (fixP->fx_done)
554 {
555 /* Nothing else to do here. */
556 return 1;
557 }
558
559 /* Determine a BFD reloc value based on the operand information.
560 We are only prepared to turn a few of the operands into relocs. */
561 /* FIXME: This test is a hack. */
562 if ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0)
563 {
564 assert ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0
565 && operand->bits == 11
566 && operand->shift == 0);
567 fixP->fx_r_type = BFD_RELOC_TXVU_11_PCREL;
568 }
569 else
570 {
571 as_bad_where (fixP->fx_file, fixP->fx_line,
572 "unresolved expression that must be resolved");
573 fixP->fx_done = 1;
574 return 1;
575 }
576 }
577 else
578 {
579 switch (fixP->fx_r_type)
580 {
581 case BFD_RELOC_8:
582 md_number_to_chars (where, value, 1);
583 break;
584 case BFD_RELOC_16:
585 md_number_to_chars (where, value, 2);
586 break;
587 case BFD_RELOC_32:
588 md_number_to_chars (where, value, 4);
589 break;
590 default:
591 abort ();
592 }
593 }
594
595 fixP->fx_addnumber = value;
596
597 return 1;
598 }
599
600 /* Translate internal representation of relocation info to BFD target
601 format. */
602
603 arelent *
604 tc_gen_reloc (section, fixP)
605 asection *section;
606 fixS *fixP;
607 {
608 arelent *reloc;
609
610 reloc = (arelent *) xmalloc (sizeof (arelent));
611
612 reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym;
613 reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
614 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
615 if (reloc->howto == (reloc_howto_type *) NULL)
616 {
617 as_bad_where (fixP->fx_file, fixP->fx_line,
618 "internal error: can't export reloc type %d (`%s')",
619 fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
620 return NULL;
621 }
622
623 assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
624
625 reloc->addend = fixP->fx_addnumber;
626
627 return reloc;
628 }
629 \f
630 /* Write a value out to the object file, using the appropriate endianness. */
631
632 void
633 md_number_to_chars (buf, val, n)
634 char *buf;
635 valueT val;
636 int n;
637 {
638 if (target_big_endian)
639 number_to_chars_bigendian (buf, val, n);
640 else
641 number_to_chars_littleendian (buf, val, n);
642 }
643
644 /* Turn a string in input_line_pointer into a floating point constant of type
645 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
646 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
647 */
648
649 /* Equal to MAX_PRECISION in atof-ieee.c */
650 #define MAX_LITTLENUMS 6
651
652 char *
653 md_atof (type, litP, sizeP)
654 char type;
655 char *litP;
656 int *sizeP;
657 {
658 int i,prec;
659 LITTLENUM_TYPE words[MAX_LITTLENUMS];
660 LITTLENUM_TYPE *wordP;
661 char *t;
662 char *atof_ieee ();
663
664 switch (type)
665 {
666 case 'f':
667 case 'F':
668 case 's':
669 case 'S':
670 prec = 2;
671 break;
672
673 case 'd':
674 case 'D':
675 case 'r':
676 case 'R':
677 prec = 4;
678 break;
679
680 /* FIXME: Some targets allow other format chars for bigger sizes here. */
681
682 default:
683 *sizeP = 0;
684 return "Bad call to md_atof()";
685 }
686
687 t = atof_ieee (input_line_pointer, type, words);
688 if (t)
689 input_line_pointer = t;
690 *sizeP = prec * sizeof (LITTLENUM_TYPE);
691
692 if (target_big_endian)
693 {
694 for (i = 0; i < prec; i++)
695 {
696 md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
697 litP += sizeof (LITTLENUM_TYPE);
698 }
699 }
700 else
701 {
702 for (i = prec - 1; i >= 0; i--)
703 {
704 md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
705 litP += sizeof (LITTLENUM_TYPE);
706 }
707 }
708
709 return 0;
710 }
711 \f
712 /* Insert an operand value into an instruction. */
713
714 static TXVU_INSN
715 txvu_insert_operand (insn, operand, mods, val, file, line)
716 TXVU_INSN insn;
717 const struct txvu_operand *operand;
718 int mods;
719 offsetT val;
720 char *file;
721 unsigned int line;
722 {
723 if (operand->bits != 32)
724 {
725 long min, max;
726 offsetT test;
727
728 if ((operand->flags & TXVU_OPERAND_RELATIVE_BRANCH) != 0)
729 {
730 if ((val & 7) != 0)
731 {
732 if (file == (char *) NULL)
733 as_warn ("branch to misaligned address");
734 else
735 as_warn_where (file, line, "branch to misaligned address");
736 }
737 val >>= 3;
738 }
739
740 if ((operand->flags & TXVU_OPERAND_SIGNED) != 0)
741 {
742 if ((operand->flags & TXVU_OPERAND_SIGNOPT) != 0)
743 max = (1 << operand->bits) - 1;
744 else
745 max = (1 << (operand->bits - 1)) - 1;
746 min = - (1 << (operand->bits - 1));
747 }
748 else
749 {
750 max = (1 << operand->bits) - 1;
751 min = 0;
752 }
753
754 if ((operand->flags & TXVU_OPERAND_NEGATIVE) != 0)
755 test = - val;
756 else
757 test = val;
758
759 if (test < (offsetT) min || test > (offsetT) max)
760 {
761 const char *err =
762 "operand out of range (%s not between %ld and %ld)";
763 char buf[100];
764
765 sprint_value (buf, test);
766 if (file == (char *) NULL)
767 as_warn (err, buf, min, max);
768 else
769 as_warn_where (file, line, err, buf, min, max);
770 }
771 }
772
773 if (operand->insert)
774 {
775 const char *errmsg;
776
777 errmsg = NULL;
778 insn = (*operand->insert) (insn, operand, mods, (long) val, &errmsg);
779 if (errmsg != (const char *) NULL)
780 as_warn (errmsg);
781 }
782 else
783 insn |= (((long) val & ((1 << operand->bits) - 1))
784 << operand->shift);
785
786 return insn;
787 }