1 /* tc-txvu.c -- Assembler for the TX VU.
2 Copyright (C) 1997 Free Software Foundation.
4 This file is part of GAS, the GNU Assembler.
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)
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.
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. */
25 /* Needed by opcode/txvu.h. */
27 #include "opcode/txvu.h"
30 static TXVU_INSN txvu_insert_operand
31 PARAMS ((TXVU_INSN
, const struct txvu_operand
*, int, offsetT
,
32 char *, unsigned int));
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";
40 const char *md_shortopts
= "";
42 struct option md_longopts
[] =
44 /* insert options here */
46 {NULL
, no_argument
, NULL
, 0}
48 size_t md_longopts_size
= sizeof(md_longopts
);
51 md_parse_option (c
, arg
)
59 md_show_usage (stream
)
63 fprintf (stream
, "TX VU options:\n");
67 /* Set by md_assemble for use by txvu_fill_insn. */
68 static subsegT prev_subseg
;
71 /* The target specific pseudo-ops which we support. */
72 const pseudo_typeS md_pseudo_table
[] =
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. */
90 subseg_set (seg
, subseg
);
92 /* Initialize the opcode tables.
93 This involves computing the hash chains. */
94 txvu_opcode_init_tables (0);
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 ``.''. */
103 /* index into `txvu_operands' */
110 static char * assemble_insn
PARAMS ((char *, int, char *));
116 /* The lower instruction has the lower address.
117 Handle this by grabbing 8 bytes now, and then filling each word
119 char *f
= frag_more (8);
121 #ifdef VERTICAL_BAR_SEPARATOR
122 char *p
= strchr (str
, '|');
126 as_bad ("lower slot missing in `%s'", str
);
131 assemble_insn (str
, 0, f
+ 4);
133 assemble_insn (p
+ 1, 1, f
);
135 str
= assemble_insn (str
, 0, f
+ 4);
136 /* Don't assemble next one if we couldn't assemble the first. */
138 assemble_insn (str
, 1, f
);
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. */
150 assemble_insn (str
, lower_p
, buf
)
155 const struct txvu_opcode
*opcode
;
157 TXVU_INSN insn_buf
[2];
160 /* Skip leading white space. */
161 while (isspace (*str
))
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. */
168 opcode
= txvu_lower_opcode_lookup_asm (str
);
170 opcode
= txvu_upper_opcode_lookup_asm (str
);
172 /* Keep looking until we find a match. */
175 for ( ; opcode
!= NULL
; opcode
= TXVU_OPCODE_NEXT_ASM (opcode
))
177 int past_opcode_p
, fc
, num_suffixes
, num_operands
;
178 const unsigned char *syn
;
179 struct txvu_fixup fixups
[MAX_FIXUPS
];
181 /* Ensure the mnemonic part matches. */
182 for (str
= start
, syn
= opcode
->mnemonic
; *syn
!= '\0'; ++str
, ++syn
)
183 if (tolower (*str
) != tolower (*syn
))
190 /* Scan the syntax string. If it doesn't match, try the next one. */
192 txvu_opcode_init_parse ();
193 insn
= opcode
->value
;
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'; )
204 const struct txvu_operand
*operand
;
207 /* Non operand chars must match exactly. */
222 /* We have a suffix or an operand. Pick out any modifiers. */
224 index
= TXVU_OPERAND_INDEX (*syn
);
225 while (TXVU_MOD_P (txvu_operands
[index
].flags
))
227 mods
|= txvu_operands
[index
].flags
& TXVU_MOD_BITS
;
229 index
= TXVU_OPERAND_INDEX (*syn
);
231 operand
= txvu_operands
+ index
;
233 if (operand
->flags
& TXVU_OPERAND_FAKE
)
237 insn
= (*operand
->insert
) (insn
, operand
, mods
, 0, &errmsg
);
238 /* If we get an error, go on to try the next insn. */
244 /* Are we finished with suffixes? */
245 else if (!past_opcode_p
)
252 if (!(operand
->flags
& TXVU_OPERAND_SUFFIX
))
253 as_fatal ("bad opcode table, missing suffix flag");
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. */
266 /* Pick the suffix out and parse it. */
267 for (t
= *s
== '.' ? s
+ 1 : s
; *t
&& isalpha (*t
); ++t
)
271 suf_value
= (*operand
->parse
) (&s
, &errmsg
);
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. */
280 /* Insert the suffix's value into the insn. */
282 insn
= (*operand
->insert
) (insn
, operand
,
283 mods
, suf_value
, NULL
);
285 insn
|= suf_value
<< operand
->shift
;
291 /* This is an operand, either a register or an expression of
299 if (operand
->flags
& TXVU_OPERAND_SUFFIX
)
300 as_fatal ("bad opcode table, suffix wrong");
302 #if 0 /* commas are in the syntax string now */
303 /* If this is not the first, there must be a comma. */
304 if (num_operands
> 0)
312 /* Is there anything left to parse?
313 We don't check for this at the top because we want to parse
314 any trailing fake arguments in the syntax string. */
318 /* Parse the operand. */
321 value
= (*operand
->parse
) (&str
, &errmsg
);
327 hold
= input_line_pointer
;
328 input_line_pointer
= str
;
330 str
= input_line_pointer
;
331 input_line_pointer
= hold
;
333 if (exp
.X_op
== O_illegal
334 || exp
.X_op
== O_absent
)
336 else if (exp
.X_op
== O_constant
)
337 value
= exp
.X_add_number
;
338 else if (exp
.X_op
== O_register
)
339 as_fatal ("got O_register");
342 /* We need to generate a fixup for this expression. */
343 if (fc
>= MAX_FIXUPS
)
344 as_fatal ("too many fixups");
345 fixups
[fc
].exp
= exp
;
346 fixups
[fc
].opindex
= index
;
352 /* Insert the register or expression into the instruction. */
355 const char *errmsg
= NULL
;
356 insn
= (*operand
->insert
) (insn
, operand
, mods
,
359 if (errmsg
!= (const char *) NULL
)
362 /* FIXME: We want to try shimm insns for limm ones. But if
363 the constant won't fit, we must go on to try the next
364 possibility. Where do we issue warnings for constants
365 that are too big then? At present, we'll flag the insn
366 as unrecognizable! Maybe have the "bad instruction"
367 error message include our `errmsg'? */
368 if (errmsg
!= (const char *) NULL
)
372 insn
|= (value
& ((1 << operand
->bits
) - 1)) << operand
->shift
;
379 /* If we're at the end of the syntax string, we're done. */
380 /* FIXME: try to move this to a separate function. */
385 /* For the moment we assume a valid `str' can only contain blanks
386 now. IE: We needn't try again with a longer version of the
387 insn and it is assumed that longer versions of insns appear
388 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
390 while (isspace (*str
))
394 #ifndef VERTICAL_BAR_SEPARATOR
398 as_bad ("junk at end of line: `%s'", str
);
400 /* Write out the instruction.
401 Reminder: it is important to fetch enough space in one call to
402 `frag_more'. We use (f - frag_now->fr_literal) to compute where
403 we are and we don't want frag_now to change between calls. */
404 md_number_to_chars (buf
, insn
, 4);
406 /* Create any fixups. */
407 for (i
= 0; i
< fc
; ++i
)
409 int op_type
, reloc_type
;
410 const struct txvu_operand
*operand
;
412 /* Create a fixup for this operand.
413 At this point we do not use a bfd_reloc_code_real_type for
414 operands residing in the insn, but instead just use the
415 operand index. This lets us easily handle fixups for any
416 operand type, although that is admittedly not a very exciting
417 feature. We pick a BFD reloc type in md_apply_fix. */
419 op_type
= fixups
[i
].opindex
;
420 reloc_type
= op_type
+ (int) BFD_RELOC_UNUSED
;
421 operand
= &txvu_operands
[op_type
];
422 fix_new_exp (frag_now
, buf
- frag_now
->fr_literal
, 4,
424 (operand
->flags
& TXVU_OPERAND_RELATIVE_BRANCH
) != 0,
425 (bfd_reloc_code_real_type
) reloc_type
);
432 /* Try the next entry. */
435 as_bad ("bad instruction `%s'", start
);
440 md_operand (expressionP
)
441 expressionS
*expressionP
;
446 md_section_align (segment
, size
)
450 int align
= bfd_get_section_alignment (stdoutput
, segment
);
451 return ((size
+ (1 << align
) - 1) & (-1 << align
));
455 md_undefined_symbol (name
)
461 /* Functions concerning relocs. */
463 /* The location from which a PC relative jump should be calculated,
464 given a PC relative reloc. */
467 md_pcrel_from_section (fixP
, sec
)
471 if (fixP
->fx_addsy
!= (symbolS
*) NULL
472 && (! S_IS_DEFINED (fixP
->fx_addsy
)
473 || S_GET_SEGMENT (fixP
->fx_addsy
) != sec
))
475 /* The symbol is undefined (or is defined but not in this section).
476 Let the linker figure it out. */
480 /* FIXME: `& -16L'? */
481 return (fixP
->fx_frag
->fr_address
+ fixP
->fx_where
) & -8L;
484 /* Apply a fixup to the object code. This is called for all the
485 fixups we generated by calls to fix_new_exp. At this point all symbol
486 values should be fully resolved, and we attempt to completely resolve the
487 reloc. If we can not do that, we determine the correct reloc code and put
488 it back in the fixup. */
491 md_apply_fix3 (fixP
, valueP
, seg
)
496 char *where
= fixP
->fx_frag
->fr_literal
+ fixP
->fx_where
;
499 /* FIXME FIXME FIXME: The value we are passed in *valueP includes
500 the symbol values. Since we are using BFD_ASSEMBLER, if we are
501 doing this relocation the code in write.c is going to call
502 bfd_perform_relocation, which is also going to use the symbol
503 value. That means that if the reloc is fully resolved we want to
504 use *valueP since bfd_perform_relocation is not being used.
505 However, if the reloc is not fully resolved we do not want to use
506 *valueP, and must use fx_offset instead. However, if the reloc
507 is PC relative, we do want to use *valueP since it includes the
508 result of md_pcrel_from. This is confusing. */
510 if (fixP
->fx_addsy
== (symbolS
*) NULL
)
515 else if (fixP
->fx_pcrel
)
521 value
= fixP
->fx_offset
;
522 if (fixP
->fx_subsy
!= (symbolS
*) NULL
)
524 if (S_GET_SEGMENT (fixP
->fx_subsy
) == absolute_section
)
525 value
-= S_GET_VALUE (fixP
->fx_subsy
);
528 /* We can't actually support subtracting a symbol. */
529 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
530 "expression too complex");
535 /* Check for txvu_operand's. These are indicated with a reloc value
536 >= BFD_RELOC_UNUSED. */
538 if ((int) fixP
->fx_r_type
>= (int) BFD_RELOC_UNUSED
)
541 const struct txvu_operand
*operand
;
544 opindex
= (int) fixP
->fx_r_type
- (int) BFD_RELOC_UNUSED
;
546 operand
= &txvu_operands
[opindex
];
548 /* Fetch the instruction, insert the fully resolved operand
549 value, and stuff the instruction back again. */
550 insn
= bfd_getl32 ((unsigned char *) where
);
551 insn
= txvu_insert_operand (insn
, operand
, -1, (offsetT
) value
,
552 fixP
->fx_file
, fixP
->fx_line
);
553 bfd_putl32 ((bfd_vma
) insn
, (unsigned char *) where
);
557 /* Nothing else to do here. */
561 /* Determine a BFD reloc value based on the operand information.
562 We are only prepared to turn a few of the operands into relocs. */
563 /* FIXME: This test is a hack. */
564 if ((operand
->flags
& TXVU_OPERAND_RELATIVE_BRANCH
) != 0)
566 assert ((operand
->flags
& TXVU_OPERAND_RELATIVE_BRANCH
) != 0
567 && operand
->bits
== 11
568 && operand
->shift
== 0);
569 fixP
->fx_r_type
= BFD_RELOC_TXVU_11_PCREL
;
573 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
574 "unresolved expression that must be resolved");
581 switch (fixP
->fx_r_type
)
584 md_number_to_chars (where
, value
, 1);
587 md_number_to_chars (where
, value
, 2);
590 md_number_to_chars (where
, value
, 4);
597 fixP
->fx_addnumber
= value
;
602 /* Translate internal representation of relocation info to BFD target
606 tc_gen_reloc (section
, fixP
)
612 reloc
= (arelent
*) xmalloc (sizeof (arelent
));
614 reloc
->sym_ptr_ptr
= &fixP
->fx_addsy
->bsym
;
615 reloc
->address
= fixP
->fx_frag
->fr_address
+ fixP
->fx_where
;
616 reloc
->howto
= bfd_reloc_type_lookup (stdoutput
, fixP
->fx_r_type
);
617 if (reloc
->howto
== (reloc_howto_type
*) NULL
)
619 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
620 "internal error: can't export reloc type %d (`%s')",
621 fixP
->fx_r_type
, bfd_get_reloc_code_name (fixP
->fx_r_type
));
625 assert (!fixP
->fx_pcrel
== !reloc
->howto
->pc_relative
);
627 reloc
->addend
= fixP
->fx_addnumber
;
632 /* Write a value out to the object file, using the appropriate endianness. */
635 md_number_to_chars (buf
, val
, n
)
640 if (target_big_endian
)
641 number_to_chars_bigendian (buf
, val
, n
);
643 number_to_chars_littleendian (buf
, val
, n
);
646 /* Turn a string in input_line_pointer into a floating point constant of type
647 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
648 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
651 /* Equal to MAX_PRECISION in atof-ieee.c */
652 #define MAX_LITTLENUMS 6
655 md_atof (type
, litP
, sizeP
)
661 LITTLENUM_TYPE words
[MAX_LITTLENUMS
];
662 LITTLENUM_TYPE
*wordP
;
682 /* FIXME: Some targets allow other format chars for bigger sizes here. */
686 return "Bad call to md_atof()";
689 t
= atof_ieee (input_line_pointer
, type
, words
);
691 input_line_pointer
= t
;
692 *sizeP
= prec
* sizeof (LITTLENUM_TYPE
);
694 if (target_big_endian
)
696 for (i
= 0; i
< prec
; i
++)
698 md_number_to_chars (litP
, (valueT
) words
[i
], sizeof (LITTLENUM_TYPE
));
699 litP
+= sizeof (LITTLENUM_TYPE
);
704 for (i
= prec
- 1; i
>= 0; i
--)
706 md_number_to_chars (litP
, (valueT
) words
[i
], sizeof (LITTLENUM_TYPE
));
707 litP
+= sizeof (LITTLENUM_TYPE
);
714 /* Insert an operand value into an instruction. */
717 txvu_insert_operand (insn
, operand
, mods
, val
, file
, line
)
719 const struct txvu_operand
*operand
;
725 if (operand
->bits
!= 32)
730 if ((operand
->flags
& TXVU_OPERAND_RELATIVE_BRANCH
) != 0)
734 if (file
== (char *) NULL
)
735 as_warn ("branch to misaligned address");
737 as_warn_where (file
, line
, "branch to misaligned address");
742 if ((operand
->flags
& TXVU_OPERAND_SIGNED
) != 0)
744 if ((operand
->flags
& TXVU_OPERAND_SIGNOPT
) != 0)
745 max
= (1 << operand
->bits
) - 1;
747 max
= (1 << (operand
->bits
- 1)) - 1;
748 min
= - (1 << (operand
->bits
- 1));
752 max
= (1 << operand
->bits
) - 1;
756 if ((operand
->flags
& TXVU_OPERAND_NEGATIVE
) != 0)
761 if (test
< (offsetT
) min
|| test
> (offsetT
) max
)
764 "operand out of range (%s not between %ld and %ld)";
767 sprint_value (buf
, test
);
768 if (file
== (char *) NULL
)
769 as_warn (err
, buf
, min
, max
);
771 as_warn_where (file
, line
, err
, buf
, min
, max
);
780 insn
= (*operand
->insert
) (insn
, operand
, mods
, (long) val
, &errmsg
);
781 if (errmsg
!= (const char *) NULL
)
785 insn
|= (((long) val
& ((1 << operand
->bits
) - 1))