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 this is not the first, there must be a comma. */
303 if (num_operands
> 0)
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. */
316 /* Parse the operand. */
319 value
= (*operand
->parse
) (&str
, &errmsg
);
325 hold
= input_line_pointer
;
326 input_line_pointer
= str
;
328 str
= input_line_pointer
;
329 input_line_pointer
= hold
;
331 if (exp
.X_op
== O_illegal
332 || exp
.X_op
== O_absent
)
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");
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
;
350 /* Insert the register or expression into the instruction. */
353 const char *errmsg
= NULL
;
354 insn
= (*operand
->insert
) (insn
, operand
, mods
,
357 if (errmsg
!= (const char *) NULL
)
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
)
370 insn
|= (value
& ((1 << operand
->bits
) - 1)) << operand
->shift
;
377 /* If we're at the end of the syntax string, we're done. */
378 /* FIXME: try to move this to a separate function. */
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). */
388 while (isspace (*str
))
392 #ifndef VERTICAL_BAR_SEPARATOR
396 as_bad ("junk at end of line: `%s'", str
);
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);
404 /* Create any fixups. */
405 for (i
= 0; i
< fc
; ++i
)
407 int op_type
, reloc_type
;
408 const struct txvu_operand
*operand
;
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. */
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,
422 (operand
->flags
& TXVU_OPERAND_RELATIVE_BRANCH
) != 0,
423 (bfd_reloc_code_real_type
) reloc_type
);
430 /* Try the next entry. */
433 as_bad ("bad instruction `%s'", start
);
438 md_operand (expressionP
)
439 expressionS
*expressionP
;
444 md_section_align (segment
, size
)
448 int align
= bfd_get_section_alignment (stdoutput
, segment
);
449 return ((size
+ (1 << align
) - 1) & (-1 << align
));
453 md_undefined_symbol (name
)
459 /* Functions concerning relocs. */
461 /* The location from which a PC relative jump should be calculated,
462 given a PC relative reloc. */
465 md_pcrel_from_section (fixP
, sec
)
469 if (fixP
->fx_addsy
!= (symbolS
*) NULL
470 && (! S_IS_DEFINED (fixP
->fx_addsy
)
471 || S_GET_SEGMENT (fixP
->fx_addsy
) != sec
))
473 /* The symbol is undefined (or is defined but not in this section).
474 Let the linker figure it out. */
478 /* FIXME: `& -16L'? */
479 return (fixP
->fx_frag
->fr_address
+ fixP
->fx_where
) & -8L;
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. */
489 md_apply_fix3 (fixP
, valueP
, seg
)
494 char *where
= fixP
->fx_frag
->fr_literal
+ fixP
->fx_where
;
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. */
508 if (fixP
->fx_addsy
== (symbolS
*) NULL
)
513 else if (fixP
->fx_pcrel
)
519 value
= fixP
->fx_offset
;
520 if (fixP
->fx_subsy
!= (symbolS
*) NULL
)
522 if (S_GET_SEGMENT (fixP
->fx_subsy
) == absolute_section
)
523 value
-= S_GET_VALUE (fixP
->fx_subsy
);
526 /* We can't actually support subtracting a symbol. */
527 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
528 "expression too complex");
533 /* Check for txvu_operand's. These are indicated with a reloc value
534 >= BFD_RELOC_UNUSED. */
536 if ((int) fixP
->fx_r_type
>= (int) BFD_RELOC_UNUSED
)
539 const struct txvu_operand
*operand
;
542 opindex
= (int) fixP
->fx_r_type
- (int) BFD_RELOC_UNUSED
;
544 operand
= &txvu_operands
[opindex
];
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
);
555 /* Nothing else to do here. */
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)
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
;
571 as_bad_where (fixP
->fx_file
, fixP
->fx_line
,
572 "unresolved expression that must be resolved");
579 switch (fixP
->fx_r_type
)
582 md_number_to_chars (where
, value
, 1);
585 md_number_to_chars (where
, value
, 2);
588 md_number_to_chars (where
, value
, 4);
595 fixP
->fx_addnumber
= value
;
600 /* Translate internal representation of relocation info to BFD target
604 tc_gen_reloc (section
, fixP
)
610 reloc
= (arelent
*) xmalloc (sizeof (arelent
));
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
)
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
));
623 assert (!fixP
->fx_pcrel
== !reloc
->howto
->pc_relative
);
625 reloc
->addend
= fixP
->fx_addnumber
;
630 /* Write a value out to the object file, using the appropriate endianness. */
633 md_number_to_chars (buf
, val
, n
)
638 if (target_big_endian
)
639 number_to_chars_bigendian (buf
, val
, n
);
641 number_to_chars_littleendian (buf
, val
, n
);
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.
649 /* Equal to MAX_PRECISION in atof-ieee.c */
650 #define MAX_LITTLENUMS 6
653 md_atof (type
, litP
, sizeP
)
659 LITTLENUM_TYPE words
[MAX_LITTLENUMS
];
660 LITTLENUM_TYPE
*wordP
;
680 /* FIXME: Some targets allow other format chars for bigger sizes here. */
684 return "Bad call to md_atof()";
687 t
= atof_ieee (input_line_pointer
, type
, words
);
689 input_line_pointer
= t
;
690 *sizeP
= prec
* sizeof (LITTLENUM_TYPE
);
692 if (target_big_endian
)
694 for (i
= 0; i
< prec
; i
++)
696 md_number_to_chars (litP
, (valueT
) words
[i
], sizeof (LITTLENUM_TYPE
));
697 litP
+= sizeof (LITTLENUM_TYPE
);
702 for (i
= prec
- 1; i
>= 0; i
--)
704 md_number_to_chars (litP
, (valueT
) words
[i
], sizeof (LITTLENUM_TYPE
));
705 litP
+= sizeof (LITTLENUM_TYPE
);
712 /* Insert an operand value into an instruction. */
715 txvu_insert_operand (insn
, operand
, mods
, val
, file
, line
)
717 const struct txvu_operand
*operand
;
723 if (operand
->bits
!= 32)
728 if ((operand
->flags
& TXVU_OPERAND_RELATIVE_BRANCH
) != 0)
732 if (file
== (char *) NULL
)
733 as_warn ("branch to misaligned address");
735 as_warn_where (file
, line
, "branch to misaligned address");
740 if ((operand
->flags
& TXVU_OPERAND_SIGNED
) != 0)
742 if ((operand
->flags
& TXVU_OPERAND_SIGNOPT
) != 0)
743 max
= (1 << operand
->bits
) - 1;
745 max
= (1 << (operand
->bits
- 1)) - 1;
746 min
= - (1 << (operand
->bits
- 1));
750 max
= (1 << operand
->bits
) - 1;
754 if ((operand
->flags
& TXVU_OPERAND_NEGATIVE
) != 0)
759 if (test
< (offsetT
) min
|| test
> (offsetT
) max
)
762 "operand out of range (%s not between %ld and %ld)";
765 sprint_value (buf
, test
);
766 if (file
== (char *) NULL
)
767 as_warn (err
, buf
, min
, max
);
769 as_warn_where (file
, line
, err
, buf
, min
, max
);
778 insn
= (*operand
->insert
) (insn
, operand
, mods
, (long) val
, &errmsg
);
779 if (errmsg
!= (const char *) NULL
)
783 insn
|= (((long) val
& ((1 << operand
->bits
) - 1))