--- /dev/null
+/* This is the machine dependent code of the Visium Assembler.
+
+ Copyright (C) 2005-2014 Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "obstack.h"
+
+#include "opcode/visium.h"
+#include "elf/visium.h"
+#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
+
+/* Relocations and fixups:
+
+ There are two different cases where an instruction or data
+ directive operand requires relocation, or fixup.
+
+ 1. Relative branch instructions, take an 16-bit signed word
+ offset. The formula for computing the offset is this:
+
+ offset = (destination - pc) / 4
+
+ Branch instructions never branch to a label not declared
+ locally, so the actual offset can always be computed by the assembler.
+ However, we provide a relocation type to support this.
+
+ 2. Load literal instructions, such as MOVIU, which take a 16-bit
+ literal operand. The literal may be the top or bottom half of
+ a 32-bit value computed by the assembler, or by the linker. We provide
+ two relocation types here.
+
+ 3. Data items (long, word and byte) preset with a value computed by
+ the linker. */
+
+
+/* This string holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful. The macro
+ tc_comment_chars points to this. */
+const char *visium_comment_chars = "!;";
+
+/* This array holds the chars that only start a comment at the beginning
+ of a line. If the line seems to have the form '# 123 filename' .line
+ and .file directives will appear in the pre-processed output. Note that
+ input_file.c hand checks for '#' at the beginning of the first line of
+ the input file. This is because the compiler outputs #NO_APP at the
+ beginning of its output. Also note that comments like this one will
+ always work. */
+const char line_comment_chars[] = "#!;";
+const char line_separator_chars[] = "";
+
+/* Chars that can be used to separate mantissa from exponent in floating point
+ numbers. */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant, as in
+ "0f12.456" or "0d1.2345e12".
+
+ ...Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c. Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here. */
+const char FLT_CHARS[] = "rRsSfFdDxXeE";
+
+/* The size of a relocation record. */
+const int md_reloc_size = 8;
+
+/* The architecture for which we are assembling. */
+enum visium_arch_val
+{
+ VISIUM_ARCH_DEF,
+ VISIUM_ARCH_MCM24,
+ VISIUM_ARCH_MCM,
+ VISIUM_ARCH_GR6
+};
+
+static enum visium_arch_val visium_arch = VISIUM_ARCH_DEF;
+
+/* The opcode architecture for which we are assembling. In contrast to the
+ previous one, this only determines which instructions are supported. */
+static enum visium_opcode_arch_val visium_opcode_arch = VISIUM_OPCODE_ARCH_DEF;
+
+/* Flags to set in the ELF header e_flags field. */
+static flagword visium_flags = 0;
+
+/* More than this number of nops in an alignment op gets a branch instead. */
+static unsigned int nop_limit = 5;
+
+
+/* Translate internal representation of relocation info to BFD target
+ format. */
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
+{
+ arelent *reloc;
+ bfd_reloc_code_real_type code;
+
+ reloc = (arelent *) xmalloc (sizeof (arelent));
+
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ switch (fixp->fx_r_type)
+ {
+ case BFD_RELOC_8:
+ case BFD_RELOC_16:
+ case BFD_RELOC_32:
+ case BFD_RELOC_8_PCREL:
+ case BFD_RELOC_16_PCREL:
+ case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_VISIUM_HI16:
+ case BFD_RELOC_VISIUM_LO16:
+ case BFD_RELOC_VISIUM_IM16:
+ case BFD_RELOC_VISIUM_REL16:
+ case BFD_RELOC_VISIUM_HI16_PCREL:
+ case BFD_RELOC_VISIUM_LO16_PCREL:
+ case BFD_RELOC_VISIUM_IM16_PCREL:
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ code = fixp->fx_r_type;
+ break;
+ default:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "internal error: unknown relocation type %d (`%s')",
+ fixp->fx_r_type,
+ bfd_get_reloc_code_name (fixp->fx_r_type));
+ return 0;
+ }
+
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (reloc->howto == 0)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "internal error: can't export reloc type %d (`%s')",
+ fixp->fx_r_type, bfd_get_reloc_code_name (code));
+ return 0;
+ }
+
+ /* Write the addend. */
+ if (reloc->howto->pc_relative == 0)
+ reloc->addend = fixp->fx_addnumber;
+ else
+ reloc->addend = fixp->fx_offset;
+
+ return reloc;
+}
+
+extern char *input_line_pointer;
+
+
+static void s_bss (int);
+static void visium_rdata (int);
+
+static void visium_update_parity_bit (char *);
+static char *parse_exp (char *, expressionS *);
+
+/* These are the back-ends for the various machine dependent pseudo-ops. */
+void demand_empty_rest_of_line (void);
+
+
+static void
+s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+ /* We don't support putting frags in the BSS segment, we fake it
+ by marking in_bss, then looking at s_skip for clues. */
+
+ subseg_set (bss_section, 0);
+ demand_empty_rest_of_line ();
+}
+
+
+/* This table describes all the machine specific pseudo-ops the assembler
+ has to support. The fields are:
+
+ 1: Pseudo-op name without dot.
+ 2: Function to call to execute this pseudo-op.
+ 3: Integer arg to pass to the function. */
+const pseudo_typeS md_pseudo_table[] =
+{
+ {"bss", s_bss, 0},
+ {"skip", s_space, 0},
+ {"align", s_align_bytes, 0},
+ {"noopt", s_ignore, 0},
+ {"optim", s_ignore, 0},
+ {"rdata", visium_rdata, 0},
+ {"rodata", visium_rdata, 0},
+ {0, 0, 0}
+};
+
+
+static void
+visium_rdata (int xxx)
+{
+ char *save_line = input_line_pointer;
+ static char section[] = ".rodata\n";
+
+ /* Just pretend this is .section .rodata */
+ input_line_pointer = section;
+ obj_elf_section (xxx);
+ input_line_pointer = save_line;
+}
+
+/* Align a section. */
+valueT
+md_section_align (asection *seg, valueT addr)
+{
+ int align = bfd_get_section_alignment (stdoutput, seg);
+
+ return ((addr + (1 << align) - 1) & (-1 << align));
+}
+
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+ number_to_chars_bigendian (buf, val, n);
+}
+
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* The parse options. */
+const char *md_shortopts = "m:";
+
+struct option md_longopts[] =
+{
+ {NULL, no_argument, NULL, 0}
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+struct visium_option_table
+{
+ char *option; /* Option name to match. */
+ char *help; /* Help information. */
+ int *var; /* Variable to change. */
+ int value; /* To what to change it. */
+ char *deprecated; /* If non-null, print this message. */
+};
+
+static struct visium_option_table visium_opts[] =
+{
+ {NULL, NULL, NULL, 0, NULL}
+};
+
+struct visium_arch_option_table
+{
+ char *name;
+ enum visium_arch_val value;
+};
+
+static struct visium_arch_option_table visium_archs[] =
+{
+ {"mcm24", VISIUM_ARCH_MCM24},
+ {"mcm", VISIUM_ARCH_MCM},
+ {"gr5", VISIUM_ARCH_MCM},
+ {"gr6", VISIUM_ARCH_GR6},
+ {NULL, 0}
+};
+
+struct visium_long_option_table
+{
+ char *option; /* Substring to match. */
+ char *help; /* Help information. */
+ int (*func) (char *subopt); /* Function to decode sub-option. */
+ char *deprecated; /* If non-null, print this message. */
+};
+
+static int
+visium_parse_arch (char *str)
+{
+ struct visium_arch_option_table *opt;
+
+ if (strlen (str) == 0)
+ {
+ as_bad ("missing architecture name `%s'", str);
+ return 0;
+ }
+
+
+ for (opt = visium_archs; opt->name != NULL; opt++)
+ if (strcmp (opt->name, str) == 0)
+ {
+ visium_arch = opt->value;
+ return 1;
+ }
+
+ as_bad ("unknown architecture `%s'\n", str);
+ return 0;
+}
+
+static struct visium_long_option_table visium_long_opts[] =
+{
+ {"mtune=", "<arch_name>\t assemble for architecture <arch name>",
+ visium_parse_arch, NULL},
+ {NULL, NULL, NULL, NULL}
+};
+
+int
+md_parse_option (int c, char *arg)
+{
+ struct visium_option_table *opt;
+ struct visium_long_option_table *lopt;
+
+ switch (c)
+ {
+ case 'a':
+ /* Listing option. Just ignore these, we don't support additional
+ ones. */
+ return 0;
+
+ default:
+ for (opt = visium_opts; opt->option != NULL; opt++)
+ {
+ if (c == opt->option[0]
+ && ((arg == NULL && opt->option[1] == 0)
+ || strcmp (arg, opt->option + 1) == 0))
+ {
+ /* If the option is deprecated, tell the user. */
+ if (opt->deprecated != NULL)
+ as_tsktsk ("option `-%c%s' is deprecated: %s", c,
+ arg ? arg : "", opt->deprecated);
+
+ if (opt->var != NULL)
+ *opt->var = opt->value;
+
+ return 1;
+ }
+ }
+
+ for (lopt = visium_long_opts; lopt->option != NULL; lopt++)
+ {
+ /* These options are expected to have an argument. */
+ if (c == lopt->option[0]
+ && arg != NULL
+ && strncmp (arg, lopt->option + 1,
+ strlen (lopt->option + 1)) == 0)
+ {
+ /* If the option is deprecated, tell the user. */
+ if (lopt->deprecated != NULL)
+ as_tsktsk ("option `-%c%s' is deprecated: %s", c, arg,
+ lopt->deprecated);
+
+ /* Call the sup-option parser. */
+ return lopt->func (arg + strlen (lopt->option) - 1);
+ }
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+md_show_usage (FILE * fp)
+{
+ struct visium_option_table *opt;
+ struct visium_long_option_table *lopt;
+
+ fprintf (fp, " Visium-specific assembler options:\n");
+
+ for (opt = visium_opts; opt->option != NULL; opt++)
+ if (opt->help != NULL)
+ fprintf (fp, " -%-23s%s\n", opt->option, opt->help);
+
+ for (lopt = visium_long_opts; lopt->option != NULL; lopt++)
+ if (lopt->help != NULL)
+ fprintf (fp, " -%s%s\n", lopt->option, lopt->help);
+
+}
+
+/* Interface to relax_segment. */
+
+/* Return the estimate of the size of a machine dependent frag
+ before any relaxing is done. It may also create any necessary
+ relocations. */
+int
+md_estimate_size_before_relax (fragS * fragP,
+ segT segment ATTRIBUTE_UNUSED)
+{
+ fragP->fr_var = 4;
+ return 4;
+}
+
+/* Get the address of a symbol during relaxation. From tc-arm.c. */
+static addressT
+relaxed_symbol_addr (fragS *fragp, long stretch)
+{
+ fragS *sym_frag;
+ addressT addr;
+ symbolS *sym;
+
+ sym = fragp->fr_symbol;
+ sym_frag = symbol_get_frag (sym);
+ know (S_GET_SEGMENT (sym) != absolute_section
+ || sym_frag == &zero_address_frag);
+ addr = S_GET_VALUE (sym) + fragp->fr_offset;
+
+ /* If frag has yet to be reached on this pass, assume it will
+ move by STRETCH just as we did. If this is not so, it will
+ be because some frag between grows, and that will force
+ another pass. */
+ if (stretch != 0
+ && sym_frag->relax_marker != fragp->relax_marker)
+ {
+ fragS *f;
+
+ /* Adjust stretch for any alignment frag. Note that if have
+ been expanding the earlier code, the symbol may be
+ defined in what appears to be an earlier frag. FIXME:
+ This doesn't handle the fr_subtype field, which specifies
+ a maximum number of bytes to skip when doing an
+ alignment. */
+ for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
+ {
+ if (f->fr_type == rs_align || f->fr_type == rs_align_code)
+ {
+ if (stretch < 0)
+ stretch = - ((- stretch)
+ & ~ ((1 << (int) f->fr_offset) - 1));
+ else
+ stretch &= ~ ((1 << (int) f->fr_offset) - 1);
+ if (stretch == 0)
+ break;
+ }
+ }
+ if (f != NULL)
+ addr += stretch;
+ }
+
+ return addr;
+}
+
+/* Relax a machine dependent frag. This returns the amount by which
+ the current size of the frag should change. */
+int
+visium_relax_frag (asection *sec, fragS *fragP, long stretch)
+{
+ int old_size, new_size;
+ addressT addr;
+
+ /* We only handle relaxation for the BRR instruction. */
+ gas_assert (fragP->fr_subtype == mode_ci);
+
+ if (!S_IS_DEFINED (fragP->fr_symbol)
+ || sec != S_GET_SEGMENT (fragP->fr_symbol)
+ || S_IS_WEAK (fragP->fr_symbol))
+ return 0;
+
+ old_size = fragP->fr_var;
+ addr = relaxed_symbol_addr (fragP, stretch);
+
+ /* If the target is the address of the instruction, we'll insert a NOP. */
+ if (addr == fragP->fr_address + fragP->fr_fix)
+ new_size = 8;
+ else
+ new_size = 4;
+
+ fragP->fr_var = new_size;
+ return new_size - old_size;
+}
+
+/* Convert a machine dependent frag. */
+void
+md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED,
+ fragS * fragP)
+{
+ char *buf = fragP->fr_literal + fragP->fr_fix;
+ expressionS exp;
+ fixS *fixP;
+
+ /* We only handle relaxation for the BRR instruction. */
+ gas_assert (fragP->fr_subtype == mode_ci);
+
+ /* Insert the NOP if requested. */
+ if (fragP->fr_var == 8)
+ {
+ memcpy (buf + 4, buf, 4);
+ memset (buf, 0, 4);
+ fragP->fr_fix += 4;
+ }
+
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = fragP->fr_symbol;
+ exp.X_add_number = fragP->fr_offset;
+
+ /* Now we can create the relocation at the correct offset. */
+ fixP = fix_new_exp (fragP, fragP->fr_fix, 4, &exp, 1, BFD_RELOC_VISIUM_REL16);
+ fixP->fx_file = fragP->fr_file;
+ fixP->fx_line = fragP->fr_line;
+ fragP->fr_fix += 4;
+ fragP->fr_var = 0;
+}
+
+/* The location from which a PC relative jump should be calculated,
+ given a PC relative jump reloc. */
+long
+visium_pcrel_from_section (fixS *fixP, segT sec)
+{
+ if (fixP->fx_addsy != (symbolS *) NULL
+ && (!S_IS_DEFINED (fixP->fx_addsy)
+ || S_GET_SEGMENT (fixP->fx_addsy) != sec))
+ {
+ /* The symbol is undefined (or is defined but not in this section).
+ Let the linker figure it out. */
+ return 0;
+ }
+
+ /* Return the address of the instruction. */
+ return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/* Indicate whether a fixup against a locally defined
+ symbol should be adjusted to be against the section
+ symbol. */
+bfd_boolean
+visium_fix_adjustable (fixS *fix)
+{
+ /* We need the symbol name for the VTABLE entries. */
+ return (fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
+ && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY);
+}
+
+/* Update the parity bit of the 4-byte instruction in BUF. */
+static void
+visium_update_parity_bit (char *buf)
+{
+ int p1 = (buf[0] & 0x7f) ^ buf[1] ^ buf[2] ^ buf[3];
+ int p2 = 0;
+ int i;
+
+ for (i = 1; i <= 8; i++)
+ {
+ p2 ^= (p1 & 1);
+ p1 >>= 1;
+ }
+
+ buf[0] = (buf[0] & 0x7f) | ((p2 << 7) & 0x80);
+}
+
+/* This is called from HANDLE_ALIGN in write.c. Fill in the contents
+ of an rs_align_code fragment. */
+void
+visium_handle_align (fragS *fragP)
+{
+ valueT count
+ = fragP->fr_next->fr_address - (fragP->fr_address + fragP->fr_fix);
+ valueT fix = count & 3;
+ char *p = fragP->fr_literal + fragP->fr_fix;
+
+ if (fix)
+ {
+ memset (p, 0, fix);
+ p += fix;
+ count -= fix;
+ fragP->fr_fix += fix;
+ }
+
+ if (count == 0)
+ return;
+
+ fragP->fr_var = 4;
+
+ if (count > 4 * nop_limit && count <= 131068)
+ {
+ struct frag *rest;
+
+ /* Make a branch, then follow with nops. Insert another
+ frag to handle the nops. */
+ md_number_to_chars (p, 0x78000000 + (count >> 2), 4);
+ visium_update_parity_bit (p);
+
+ rest = xmalloc (SIZEOF_STRUCT_FRAG + 4);
+ memcpy (rest, fragP, SIZEOF_STRUCT_FRAG);
+ fragP->fr_next = rest;
+ rest->fr_address += rest->fr_fix + 4;
+ rest->fr_fix = 0;
+ /* If we leave the next frag as rs_align_code we'll come here
+ again, resulting in a bunch of branches rather than a
+ branch followed by nops. */
+ rest->fr_type = rs_align;
+ p = rest->fr_literal;
+ }
+
+ memset (p, 0, 4);
+}
+
+/* Apply a fixS to the frags, now that we know the value it ought to
+ hold. */
+void
+md_apply_fix (fixS * fixP, valueT * value, segT segment)
+{
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+ offsetT val;
+ long insn;
+
+ val = *value;
+
+ gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+
+ /* Remember value for tc_gen_reloc. */
+ fixP->fx_addnumber = val;
+
+ /* Since DIFF_EXPR_OK is defined, .-foo gets turned into PC
+ relative relocs. If this has happened, a non-PC relative
+ reloc must be reinstalled with its PC relative version here. */
+ if (fixP->fx_pcrel)
+ {
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_8:
+ fixP->fx_r_type = BFD_RELOC_8_PCREL;
+ break;
+ case BFD_RELOC_16:
+ fixP->fx_r_type = BFD_RELOC_16_PCREL;
+ break;
+ case BFD_RELOC_32:
+ fixP->fx_r_type = BFD_RELOC_32_PCREL;
+ break;
+ case BFD_RELOC_VISIUM_HI16:
+ fixP->fx_r_type = BFD_RELOC_VISIUM_HI16_PCREL;
+ break;
+ case BFD_RELOC_VISIUM_LO16:
+ fixP->fx_r_type = BFD_RELOC_VISIUM_LO16_PCREL;
+ break;
+ case BFD_RELOC_VISIUM_IM16:
+ fixP->fx_r_type = BFD_RELOC_VISIUM_IM16_PCREL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* If this is a data relocation, just output VAL. */
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_8:
+ case BFD_RELOC_8_PCREL:
+ md_number_to_chars (buf, val, 1);
+ break;
+ case BFD_RELOC_16:
+ case BFD_RELOC_16_PCREL:
+ md_number_to_chars (buf, val, 2);
+ break;
+ case BFD_RELOC_32:
+ case BFD_RELOC_32_PCREL:
+ md_number_to_chars (buf, val, 4);
+ break;
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixP->fx_done = 0;
+ break;
+ default:
+ /* It's a relocation against an instruction. */
+ insn = bfd_getb32 ((unsigned char *) buf);
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_VISIUM_REL16:
+ if (fixP->fx_addsy == NULL
+ || (S_IS_DEFINED (fixP->fx_addsy)
+ && S_GET_SEGMENT (fixP->fx_addsy) == segment))
+ {
+ if (val > 0x1fffc || val < -0x20000)
+ as_bad_where
+ (fixP->fx_file, fixP->fx_line,
+ "16-bit word displacement out of range: value = %d",
+ (int) val);
+ val = (val >> 2);
+
+ insn = (insn & 0xffff0000) | (val & 0x0000ffff);
+ }
+ break;
+
+ case BFD_RELOC_VISIUM_HI16:
+ case BFD_RELOC_VISIUM_HI16_PCREL:
+ if (fixP->fx_addsy == NULL)
+ insn = (insn & 0xffff0000) | ((val >> 16) & 0x0000ffff);
+ break;
+
+ case BFD_RELOC_VISIUM_LO16:
+ case BFD_RELOC_VISIUM_LO16_PCREL:
+ if (fixP->fx_addsy == NULL)
+ insn = (insn & 0xffff0000) | (val & 0x0000ffff);
+ break;
+
+ case BFD_RELOC_VISIUM_IM16:
+ case BFD_RELOC_VISIUM_IM16_PCREL:
+ if (fixP->fx_addsy == NULL)
+ {
+ if ((val & 0xffff0000) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "16-bit immediate out of range: value = %d",
+ (int) val);
+
+ insn = (insn & 0xffff0000) | val;
+ }
+ break;
+
+ case BFD_RELOC_NONE:
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "bad or unhandled relocation type: 0x%02x",
+ fixP->fx_r_type);
+ break;
+ }
+
+ bfd_putb32 (insn, (unsigned char *) buf);
+ visium_update_parity_bit (buf);
+ break;
+ }
+
+ /* Are we finished with this relocation now? */
+ if (fixP->fx_addsy == NULL)
+ fixP->fx_done = 1;
+}
+
+char *
+parse_exp (char *s, expressionS * op)
+{
+ char *save = input_line_pointer;
+ char *new;
+
+ if (!s)
+ {
+ return s;
+ }
+
+ input_line_pointer = s;
+ expression (op);
+ new = input_line_pointer;
+ input_line_pointer = save;
+ return new;
+}
+
+/* If the given string is a Visium opcode mnemonic return the code
+ otherwise return -1. Use binary chop to find matching entry. */
+static int
+get_opcode (int *code, enum addressing_mode *mode, char *flags, char *mnem)
+{
+ int l = 0;
+ int r = sizeof (opcode_table) / sizeof (struct opcode_entry) - 1;
+
+ do
+ {
+ int mid = (l + r) / 2;
+ int ans = strcmp (mnem, opcode_table[mid].mnem);
+
+ if (ans < 0)
+ r = mid - 1;
+ else if (ans > 0)
+ l = mid + 1;
+ else
+ {
+ *code = opcode_table[mid].code;
+ *mode = opcode_table[mid].mode;
+ *flags = opcode_table[mid].flags;
+
+ return 0;
+ }
+ }
+ while (l <= r);
+
+ return -1;
+}
+
+/* This function is called when the assembler starts up. It is called
+ after the options have been parsed and the output file has been
+ opened. */
+void
+md_begin (void)
+{
+ switch (visium_arch)
+ {
+ case VISIUM_ARCH_DEF:
+ break;
+ case VISIUM_ARCH_MCM24:
+ visium_opcode_arch = VISIUM_OPCODE_ARCH_GR5;
+ visium_flags |= EF_VISIUM_ARCH_MCM24;
+ break;
+ case VISIUM_ARCH_MCM:
+ visium_opcode_arch = VISIUM_OPCODE_ARCH_GR5;
+ visium_flags |= EF_VISIUM_ARCH_MCM;
+ break;
+ case VISIUM_ARCH_GR6:
+ visium_opcode_arch = VISIUM_OPCODE_ARCH_GR6;
+ visium_flags |= EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_GR6;
+ nop_limit = 2;
+ break;
+ default:
+ gas_assert (0);
+ }
+
+ bfd_set_private_flags (stdoutput, visium_flags);
+}
+
+/* This is identical to the md_atof in m68k.c. I think this is right,
+ but I'm not sure.
+
+ Turn a string in input_line_pointer into a floating point constant of type
+ type, and store the appropriate bytes in *litP. The number of LITTLENUMS
+ emitted is stored in *sizeP . An error message is returned,
+ or NULL on OK. */
+
+/* Equal to MAX_PRECISION in atof-ieee.c. */
+#define MAX_LITTLENUMS 6
+
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ int i, prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ char *t;
+
+ switch (type)
+ {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+
+ case 'x':
+ case 'X':
+ prec = 6;
+ break;
+
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+
+ default:
+ *sizeP = 0;
+ return "Bad call to MD_ATOF()";
+ }
+
+ t = atof_ieee (input_line_pointer, type, words);
+ if (t)
+ input_line_pointer = t;
+ *sizeP = prec * sizeof (LITTLENUM_TYPE);
+
+ if (target_big_endian)
+ {
+ for (i = 0; i < prec; i++)
+ {
+ md_number_to_chars (litP, (valueT) words[i],
+ sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
+ }
+ }
+ else
+ {
+ for (i = prec - 1; i >= 0; i--)
+ {
+ md_number_to_chars (litP, (valueT) words[i],
+ sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
+ }
+ }
+
+ return 0;
+}
+
+static inline char *
+skip_space (char *s)
+{
+ while (*s == ' ' || *s == '\t')
+ ++s;
+
+ return s;
+}
+
+static int
+parse_gen_reg (char **sptr, int *rptr)
+{
+ char *s = skip_space (*sptr);
+ char buf[10];
+ int cnt;
+ int l, r;
+
+ cnt = 0;
+ memset (buf, '\0', 10);
+ while ((ISALNUM (*s)) && cnt < 10)
+ buf[cnt++] = TOLOWER (*s++);
+
+ l = 0;
+ r = sizeof (gen_reg_table) / sizeof (struct reg_entry) - 1;
+
+ do
+ {
+ int mid = (l + r) / 2;
+ int ans = strcmp (buf, gen_reg_table[mid].name);
+
+ if (ans < 0)
+ r = mid - 1;
+ else if (ans > 0)
+ l = mid + 1;
+ else
+ {
+ *rptr = gen_reg_table[mid].code;
+ *sptr = s;
+ return 0;
+ }
+ }
+ while (l <= r);
+
+ return -1;
+}
+
+static int
+parse_fp_reg (char **sptr, int *rptr)
+{
+ char *s = skip_space (*sptr);
+ char buf[10];
+ int cnt;
+ int l, r;
+
+ cnt = 0;
+ memset (buf, '\0', 10);
+ while ((ISALNUM (*s)) && cnt < 10)
+ buf[cnt++] = TOLOWER (*s++);
+
+ l = 0;
+ r = sizeof (fp_reg_table) / sizeof (struct reg_entry) - 1;
+
+ do
+ {
+ int mid = (l + r) / 2;
+ int ans = strcmp (buf, fp_reg_table[mid].name);
+
+ if (ans < 0)
+ r = mid - 1;
+ else if (ans > 0)
+ l = mid + 1;
+ else
+ {
+ *rptr = fp_reg_table[mid].code;
+ *sptr = s;
+ return 0;
+ }
+ }
+ while (l <= r);
+
+ return -1;
+}
+
+static int
+parse_cc (char **sptr, int *rptr)
+{
+ char *s = skip_space (*sptr);
+ char buf[10];
+ int cnt;
+ int l, r;
+
+ cnt = 0;
+ memset (buf, '\0', 10);
+ while ((ISALNUM (*s)) && cnt < 10)
+ buf[cnt++] = TOLOWER (*s++);
+
+ l = 0;
+ r = sizeof (cc_table) / sizeof (struct cc_entry) - 1;
+
+ do
+ {
+ int mid = (l + r) / 2;
+ int ans = strcmp (buf, cc_table[mid].name);
+
+ if (ans < 0)
+ r = mid - 1;
+ else if (ans > 0)
+ l = mid + 1;
+ else
+ {
+ *rptr = cc_table[mid].code;
+ *sptr = s;
+ return 0;
+ }
+ }
+ while (l <= r);
+
+ return -1;
+}
+
+/* Previous dest is the destination register number of the instruction
+ before the current one. */
+static int previous_dest = 0;
+static int previous_mode = 0;
+static int condition_code = 0;
+static int this_dest = 0;
+static int this_mode = 0;
+
+
+/* This is the main function in this file. It takes a line of assembly language
+ source code and assembles it. Note, labels and pseudo ops have already
+ been removed, so too has leading white space. */
+void
+md_assemble (char *str0)
+{
+ char *str = str0;
+ int cnt;
+ char mnem[10];
+ int opcode;
+ enum addressing_mode amode;
+ char arch_flags;
+ int ans;
+
+ char *output;
+ int reloc = 0;
+ relax_substateT relax = 0;
+ expressionS e1;
+ int r1, r2, r3;
+ int cc;
+ int indx;
+
+ /* Initialize the expression. */
+ e1.X_op = O_absent;
+
+ /* Initialize destination register.
+ If the instruction we just looked at is in the delay slot of an
+ unconditional branch, then there is no index hazard. */
+ if ((previous_mode == mode_cad || previous_mode == mode_ci)
+ && condition_code == 15)
+ this_dest = 0;
+
+ previous_dest = this_dest;
+ previous_mode = this_mode;
+ this_dest = 0;
+
+ /* Drop leading whitespace (probably not required). */
+ while (*str == ' ')
+ str++;
+
+ /* Get opcode mnemonic and make sure it's in lower case. */
+ cnt = 0;
+ memset (mnem, '\0', 10);
+ while ((ISALNUM (*str) || *str == '.' || *str == '_') && cnt < 10)
+ mnem[cnt++] = TOLOWER (*str++);
+
+ /* Look up mnemonic in opcode table, and get the code,
+ the instruction format, and the flags that indicate
+ which family members support this mnenonic. */
+ if (get_opcode (&opcode, &amode, &arch_flags, mnem) < 0)
+ {
+ as_bad ("Unknown instruction mnenonic `%s'", mnem);
+ return;
+ }
+
+ if ((VISIUM_OPCODE_ARCH_MASK (visium_opcode_arch) & arch_flags) == 0)
+ {
+ as_bad ("Architecture mismatch on `%s'", mnem);
+ return;
+ }
+
+ this_mode = amode;
+
+ switch (amode)
+ {
+ case mode_d:
+ /* register :=
+ Example:
+ readmda r1 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ opcode |= (r1 << 10);
+ this_dest = r1;
+ break;
+
+ case mode_a:
+ /* op= register
+ Example: asld r1 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ opcode |= (r1 << 16);
+ break;
+
+ case mode_ab:
+ /* register * register
+ Example:
+ mults r1,r2 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+ opcode |= (r1 << 16) | (r2 << 4);
+ }
+ else
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+ break;
+
+ case mode_da:
+ /* register := register
+ Example:
+ extb.l r1,r2 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ opcode |= (r1 << 10) | (r2 << 16);
+ }
+ else
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+ this_dest = r1;
+ break;
+
+ case mode_dab:
+ /* register := register * register
+ Example:
+ add.l r1,r2,r3 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+
+ /* Got three regs, assemble instruction. */
+ opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+ }
+ else
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ this_dest = r1;
+ break;
+
+ case mode_iab:
+ /* 5-bit immediate * register * register
+ Example:
+ eamwrite 3,r1,r2 */
+ str = parse_exp (str, &e1);
+ str = skip_space (str);
+ if (e1.X_op != O_absent && *str == ',')
+ {
+ int eam_op = e1.X_add_number;
+
+ str = skip_space (str + 1);
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+
+ /* Got three operands, assemble instruction. */
+ if (eam_op < 0 || eam_op > 31)
+ {
+ as_bad ("eam_op out of range");
+ }
+ opcode |= ((eam_op & 0x1f) << 10) | (r2 << 16) | (r3 << 4);
+ }
+ }
+ else
+ {
+ as_bad ("EAM_OP required");
+ return;
+ }
+ break;
+
+ case mode_0ab:
+ /* zero * register * register
+ Example:
+ cmp.l r1,r2 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+ opcode |= (r1 << 16) | (r2 << 4);
+ }
+ else
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+ break;
+
+ case mode_da0:
+ /* register * register * zero
+ Example:
+ move.l r1,r2 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ opcode |= (r1 << 10) | (r2 << 16);
+ }
+ else
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ this_dest = r1;
+ break;
+
+ case mode_cad:
+ /* condition * register * register
+ Example:
+ bra tr,r1,r2 */
+ ans = parse_cc (&str, &cc);
+ if (ans < 0)
+ {
+ as_bad ("condition code required");
+ return;
+ }
+
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str = skip_space (str + 1);
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+
+ /* Got three operands, assemble instruction. */
+ opcode |= (cc << 27) | (r2 << 16) | (r3 << 10);
+ }
+ else
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+
+ if (previous_mode == mode_cad || previous_mode == mode_ci)
+ as_bad ("branch instruction in delay slot");
+
+ this_dest = r3;
+ condition_code = cc;
+ break;
+
+ case mode_das:
+ /* register := register * 5-bit imediate/register shift count
+ Example:
+ asl.l r1,r2,4 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r3);
+ if (ans == 0)
+ {
+ opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+ }
+ else
+ {
+ str = parse_exp (str, &e1);
+ if (e1.X_op == O_constant)
+ {
+ int imm = e1.X_add_number;
+
+ if (imm < 0 || imm > 31)
+ as_bad ("immediate value out of range");
+
+ opcode |=
+ (r1 << 10) | (r2 << 16) | (1 << 9) | ((imm & 0x1f) <<
+ 4);
+ }
+ else
+ {
+ as_bad ("immediate operand required");
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ this_dest = r1;
+ break;
+
+ case mode_di:
+ /* register := 5-bit immediate
+ Example:
+ eamread r1,3 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ str = parse_exp (str, &e1);
+ if (e1.X_op == O_constant)
+ {
+ int opnd2 = e1.X_add_number;
+
+ if (opnd2 < 0 || opnd2 > 31)
+ {
+ as_bad ("immediate operand out of range");
+ return;
+ }
+ opcode |= (r1 << 10) | ((opnd2 & 0x1f) << 4);
+ }
+ else
+ {
+ as_bad ("immediate operand required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("immediate operand required");
+ return;
+ }
+ this_dest = r1;
+ break;
+
+ case mode_ir:
+ /* 5-bit immediate * register, e.g. trace 1,r1 */
+ str = parse_exp (str, &e1);
+ str = skip_space (str);
+ if (e1.X_op == O_constant && *str == ',')
+ {
+ int opnd1 = e1.X_add_number;
+
+ str = skip_space (str + 1);
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+
+ /* Got two operands, assemble instruction. */
+ if (opnd1 < 0 || opnd1 > 31)
+ {
+ as_bad ("1st operand out of range");
+ }
+ opcode |= ((opnd1 & 0x1f) << 10) | (r2 << 16);
+ }
+ else
+ {
+ as_bad ("Immediate operand required");
+ return;
+ }
+ break;
+
+ case mode_ai:
+ /* register *= 16-bit unsigned immediate
+ Example:
+ addi r1,123 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ opcode |= (r1 << 16);
+
+ str = skip_space (str);
+ if (*str != ',')
+ {
+ as_bad ("immediate value missing");
+ return;
+ }
+ this_dest = r1;
+
+ /* fall through... */
+
+ case mode_i:
+ /* MOVIL/WRTL traditionally get an implicit "%l" applied
+ to their immediate value. For other opcodes, unless
+ the immediate value is decorated with "%u" or "%l"
+ it must be in the range 0 .. 65535. */
+ if ((opcode & 0x7fe00000) == 0x04800000
+ || (opcode & 0x7fe00000) == 0x05000000)
+ reloc = BFD_RELOC_VISIUM_LO16;
+ else
+ reloc = BFD_RELOC_VISIUM_IM16;
+
+ str = skip_space (str + 1);
+
+ if (*str == '%')
+ {
+ if (str[1] == 'u')
+ reloc = BFD_RELOC_VISIUM_HI16;
+ else if (str[1] == 'l')
+ reloc = BFD_RELOC_VISIUM_LO16;
+ else
+ {
+ as_bad ("bad char after %%");
+ return;
+ }
+
+ str += 2;
+ }
+ str = parse_exp (str, &e1);
+ if (e1.X_op != O_absent)
+ {
+ if (e1.X_op == O_constant)
+ {
+ int imm = e1.X_add_number;
+
+ if (reloc == BFD_RELOC_VISIUM_HI16)
+ opcode |= ((imm >> 16) & 0xffff);
+ else if (reloc == BFD_RELOC_VISIUM_LO16)
+ opcode |= (imm & 0xffff);
+ else
+ {
+ if (imm < 0 || imm > 0xffff)
+ as_bad ("immediate value out of range");
+
+ opcode |= (imm & 0xffff);
+ }
+ /* No relocation is needed. */
+ reloc = 0;
+ }
+ }
+ else
+ {
+ as_bad ("immediate value missing");
+ return;
+ }
+ break;
+
+ case mode_bax:
+ /* register * register * 5-bit immediate,
+ SourceB * SourceA * Index
+ Examples
+ write.l (r1),r2
+ write.l 3(r1),r2 */
+ str = skip_space (str);
+
+ indx = 0;
+ if (*str != '(')
+ {
+ str = parse_exp (str, &e1);
+ if (e1.X_op == O_constant)
+ {
+ indx = e1.X_add_number;
+
+ if (indx < 0 || indx > 31)
+ {
+ as_bad ("Index out of range");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("Index(SourceA) required");
+ return;
+ }
+ }
+
+ str = skip_space (str);
+
+ if (*str != '(')
+ {
+ as_bad ("Index(SourceA) required");
+ return;
+ }
+
+ str = skip_space (str + 1);
+
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str != ')')
+ {
+ as_bad ("(SourceA) required");
+ return;
+ }
+ str = skip_space (str + 1);
+
+ if (*str == ',')
+ {
+ str = skip_space (str + 1);
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("SourceB register required");
+ return;
+ }
+
+ opcode |= (r1 << 16) | (r2 << 4) | ((indx & 0x1f) << 10);
+
+ if (indx != 0 && previous_mode == mode_cad)
+ {
+ /* We're in a delay slot.
+ If the base reg is the destination of the branch, then issue
+ an error message.
+ Otherwise it is safe to use the base and index. */
+ if (previous_dest != 0 && r1 == previous_dest)
+ {
+ as_bad ("base register not ready");
+ return;
+ }
+ }
+ else if (previous_dest != 0
+ && r1 == previous_dest
+ && (visium_arch == VISIUM_ARCH_MCM
+ || visium_arch == VISIUM_ARCH_MCM24
+ || (visium_arch == VISIUM_ARCH_DEF && indx != 0)))
+ {
+ as_warn ("base register not ready, NOP inserted.");
+ /* Insert a NOP before the write instruction. */
+ output = frag_more (4);
+ memset (output, 0, 4);
+ }
+ break;
+
+ case mode_dax:
+ /* register := register * 5-bit immediate
+ Examples:
+ read.b r1,(r2)
+ read.w r1,3(r2) */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str != ',')
+ {
+ as_bad ("SourceA required");
+ return;
+ }
+ str = skip_space (str + 1);
+
+ indx = 0;
+ if (*str != '(')
+ {
+ str = parse_exp (str, &e1);
+ if (e1.X_op == O_constant)
+ {
+ indx = e1.X_add_number;
+
+ if (indx < 0 || indx > 31)
+ {
+ as_bad ("Index out of range");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("Immediate 0 to 31 required");
+ return;
+ }
+ }
+ if (*str != '(')
+ {
+ as_bad ("(SourceA) required");
+ return;
+ }
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str != ')')
+ {
+ as_bad ("(SourceA) required");
+ return;
+ }
+ str++;
+ opcode |= (r1 << 10) | (r2 << 16) | ((indx & 0x1f) << 4);
+ this_dest = r1;
+
+ if (indx != 0 && previous_mode == mode_cad)
+ {
+ /* We're in a delay slot.
+ If the base reg is the destination of the branch, then issue
+ an error message.
+ Otherwise it is safe to use the base and index. */
+ if (previous_dest != 0 && r2 == previous_dest)
+ {
+ as_bad ("base register not ready");
+ return;
+ }
+ }
+ else if (previous_dest != 0
+ && r2 == previous_dest
+ && (visium_arch == VISIUM_ARCH_MCM
+ || visium_arch == VISIUM_ARCH_MCM24
+ || (visium_arch == VISIUM_ARCH_DEF && indx != 0)))
+ {
+ as_warn ("base register not ready, NOP inserted.");
+ /* Insert a NOP before the read instruction. */
+ output = frag_more (4);
+ memset (output, 0, 4);
+ }
+ break;
+
+ case mode_s:
+ /* special mode
+ Example:
+ nop */
+ str = skip_space (str);
+ break;
+
+ case mode_ci:
+ /* condition * 16-bit signed word displacement
+ Example:
+ brr L1 */
+ ans = parse_cc (&str, &cc);
+ if (ans < 0)
+ {
+ as_bad ("condition code required");
+ return;
+ }
+ opcode |= (cc << 27);
+
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str = skip_space (str + 1);
+ str = parse_exp (str, &e1);
+ if (e1.X_op != O_absent)
+ {
+ if (e1.X_op == O_constant)
+ {
+ int imm = e1.X_add_number;
+
+ if (imm < -32768 || imm > 32767)
+ as_bad ("immediate value out of range");
+
+ /* The GR6 doesn't correctly handle a 0 displacement
+ so we insert a NOP and change it to -1. */
+ if (imm == 0 && cc != 0 && visium_arch == VISIUM_ARCH_GR6)
+ {
+ output = frag_more (4);
+ memset (output, 0, 4);
+ imm = -1;
+ }
+
+ opcode |= (imm & 0xffff);
+ }
+ else if (e1.X_op == O_symbol)
+ {
+ /* The GR6 doesn't correctly handle a 0 displacement
+ so the instruction requires relaxation. */
+ if (cc != 0 && visium_arch == VISIUM_ARCH_GR6)
+ relax = amode;
+ else
+ reloc = BFD_RELOC_VISIUM_REL16;
+ }
+ else
+ {
+ as_bad ("immediate value missing");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("immediate value missing");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("immediate value missing");
+ return;
+ }
+
+ if (previous_mode == mode_cad || previous_mode == mode_ci)
+ as_bad ("branch instruction in delay slot");
+
+ condition_code = cc;
+ break;
+
+ case mode_fdab:
+ /* float := float * float
+ Example
+ fadd f4,f3,f2 */
+ ans = parse_fp_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("floating point destination register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+
+ /* Got 3 floating regs, assemble instruction. */
+ opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+ }
+ else
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ break;
+
+ case mode_ifdab:
+ /* 4-bit immediate * float * float * float
+ Example
+ fpinst 10,f1,f2,f3 */
+ str = parse_exp (str, &e1);
+ str = skip_space (str);
+ if (e1.X_op != O_absent && *str == ',')
+ {
+ int finst = e1.X_add_number;
+
+ str = skip_space (str + 1);
+ ans = parse_fp_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("floating point destination register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+
+ /* Got immediate and 3 floating regs,
+ assemble instruction. */
+ if (finst < 0 || finst > 15)
+ as_bad ("finst out of range");
+
+ opcode |=
+ ((finst & 0xf) << 27) | (r1 << 10) | (r2 << 16) | (r3 <<
+ 4);
+ }
+ else
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("finst missing");
+ return;
+ }
+ break;
+
+ case mode_idfab:
+ /* 4-bit immediate * register * float * float
+ Example
+ fpuread 4,r25,f2,f3 */
+ str = parse_exp (str, &e1);
+ str = skip_space (str);
+ if (e1.X_op != O_absent && *str == ',')
+ {
+ int finst = e1.X_add_number;
+
+ str = skip_space (str + 1);
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("destination general register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+
+ /* Got immediate and 3 floating regs,
+ assemble instruction. */
+ if (finst < 0 || finst > 15)
+ as_bad ("finst out of range");
+
+ opcode |=
+ ((finst & 0xf) << 27) | (r1 << 10) | (r2 << 16) | (r3 <<
+ 4);
+ }
+ else
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("finst missing");
+ return;
+ }
+ break;
+
+ case mode_fda:
+ /* float := float
+ Example
+ fsqrt f4,f3 */
+ ans = parse_fp_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("floating point destination register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("floating point source register required");
+ return;
+ }
+
+ /* Got 2 floating regs, assemble instruction. */
+ opcode |= (r1 << 10) | (r2 << 16);
+ }
+ else
+ {
+ as_bad ("floating point source register required");
+ return;
+ }
+ break;
+
+ case mode_fdra:
+ /* float := register
+ Example
+ fload f15,r6 */
+ ans = parse_fp_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("floating point destination register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("SourceA general register required");
+ return;
+ }
+
+ /* Got 2 regs, assemble instruction. */
+ opcode |= (r1 << 10) | (r2 << 16);
+ }
+ else
+ {
+ as_bad ("SourceA general register required");
+ return;
+ }
+ break;
+
+ case mode_rdfab:
+ /* register := float * float
+ Example
+ fcmp r0,f4,f8
+ For the GR6, register must be r0 and can be omitted. */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ if (visium_opcode_arch == VISIUM_OPCODE_ARCH_GR5)
+ {
+ as_bad ("Dest general register required");
+ return;
+ }
+ r1 = 0;
+ }
+ else
+ {
+ if (r1 != 0 && visium_opcode_arch != VISIUM_OPCODE_ARCH_GR5)
+ {
+ as_bad ("FCMP/FCMPE can only use r0 as Dest register");
+ return;
+ }
+
+ str = skip_space (str);
+ if (*str == ',')
+ str++;
+ else
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ }
+
+ ans = parse_fp_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceA register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("floating point SourceB register required");
+ return;
+ }
+
+ /* Got 3 regs, assemble instruction. */
+ opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+ }
+
+ this_dest = r1;
+ break;
+
+ case mode_rdfa:
+ /* register := float
+ Example
+ fstore r5,f12 */
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("Dest general register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_fp_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("floating point source register required");
+ return;
+ }
+
+ /* Got 2 regs, assemble instruction. */
+ opcode |= (r1 << 10) | (r2 << 16);
+ }
+ else
+ {
+ as_bad ("floating point source register required");
+ return;
+ }
+
+ this_dest = r1;
+ break;
+
+ case mode_rrr:
+ /* register register register, all sources and destinations
+ Example:
+ bmd r1,r2,r3 */
+
+ ans = parse_gen_reg (&str, &r1);
+ if (ans < 0)
+ {
+ as_bad ("destination address register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r2);
+ if (ans < 0)
+ {
+ as_bad ("source address register required");
+ return;
+ }
+ str = skip_space (str);
+ if (*str == ',')
+ {
+ str++;
+ ans = parse_gen_reg (&str, &r3);
+ if (ans < 0)
+ {
+ as_bad ("count register required");
+ return;
+ }
+
+ /* We insist on three registers but the opcode can only use
+ r1,r2,r3. */
+ if (r1 != 1 || r2 != 2 || r3 != 3)
+ {
+ as_bad ("BMI/BMD can only use format op r1,r2,r3");
+ return;
+ }
+
+ /* Opcode is unmodified by what comes out of the table. */
+ }
+ else
+ {
+ as_bad ("register required");
+ return;
+ }
+ }
+ else
+ {
+ as_bad ("register required");
+ return;
+ }
+
+ this_dest = r1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (relax)
+ output = frag_var (rs_machine_dependent, 8, 4, relax, e1.X_add_symbol,
+ e1.X_add_number, NULL);
+ else
+ output = frag_more (4);
+
+ /* Build the 32-bit instruction in a host-endian-neutral fashion. */
+ output[0] = (opcode >> 24) & 0xff;
+ output[1] = (opcode >> 16) & 0xff;
+ output[2] = (opcode >> 8) & 0xff;
+ output[3] = (opcode >> 0) & 0xff;
+
+ if (relax)
+ /* The size of the instruction is unknown, so tie the debug info to the
+ start of the instruction. */
+ dwarf2_emit_insn (0);
+ else
+ {
+ if (reloc)
+ fix_new_exp (frag_now, output - frag_now->fr_literal, 4, &e1,
+ reloc == BFD_RELOC_VISIUM_REL16, reloc);
+ else
+ visium_update_parity_bit (output);
+
+ dwarf2_emit_insn (4);
+ }
+
+ if (*str != '\0')
+ as_bad ("junk after instruction");
+}
+
+void
+visium_cfi_frame_initial_instructions (void)
+{
+ /* The CFA is in SP on function entry. */
+ cfi_add_CFA_def_cfa (23, 0);
+}
+
+int
+visium_regname_to_dw2regnum (char *regname)
+{
+ if (!regname[0])
+ return -1;
+
+ if (regname[0] == 'f' && regname[1] == 'p' && !regname[2])
+ return 22;
+
+ if (regname[0] == 's' && regname[1] == 'p' && !regname[2])
+ return 23;
+
+ if (regname[0] == 'm' && regname[1] == 'd' && !regname[3])
+ switch (regname[2])
+ {
+ case 'b': return 32;
+ case 'a': return 33;
+ case 'c': return 34;
+ default : return -1;
+ }
+
+ if (regname[0] == 'f' || regname[0] == 'r')
+ {
+ char *p;
+ unsigned int regnum = strtoul (regname + 1, &p, 10);
+ if (*p)
+ return -1;
+ if (regnum >= (regname[0] == 'f' ? 16 : 32))
+ return -1;
+ if (regname[0] == 'f')
+ regnum += 35;
+ return regnum;
+ }
+
+ return -1;
+}
--- /dev/null
+#as: -mtune=gr6
+#objdump: -dzr
+#name: allinsn_gr6
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+0000000 <begin>:
+ 0: 03 e2 00 14 write.l 0\(r2\),r1
+ 4: 03 e2 00 14 write.l 0\(r2\),r1
+ 8: 83 e1 04 22 write.w 1\(r1\),r2
+ c: 03 e3 7c 71 write.b 31\(r3\),r7
+ 10: 03 e4 00 71 write.b 0\(r4\),r7
+ 14: 03 e4 80 54 mults r4,r5
+ 18: 83 e7 fc a4 eamwrite 31,r7,r10
+ 1c: 83 ee 90 f4 writemd r14,r15
+ 20: 83 e9 94 04 writemdc r9
+ 24: 03 e5 88 04 divs r5
+ 28: 83 e6 8c 04 divu r6
+ 2c: 83 ea 98 04 divds r10
+ 30: 83 eb 9c 04 divdu r11
+ 34: 83 ec a4 04 asrd r12
+ 38: 03 ed a8 04 lsrd r13
+ 3c: 83 ee ac 04 asld r14
+ 40: 82 80 00 04 dsi
+ 44: 83 e7 80 84 mults r7,r8
+ 48: 03 e9 84 a4 multu r9,r10
+ 4c: 02 a0 00 04 eni
+ 50: 82 80 00 04 dsi
+ 54: 82 fe 01 d4 rfi
+
+0+0000058 <nsrel>:
+ 58: 00 00 00 00 nop
+ 5c: 07 a0 00 04 rflag r0
+ 60: 08 00 ff fe brr eq,-2
+ 64: 07 a0 00 04 rflag r0
+ 68: 90 00 ff fc brr cs,-4
+ 6c: 07 a0 00 04 rflag r0
+ 70: 18 00 ff fa brr os,-6
+ 74: 07 a0 00 04 rflag r0
+ 78: 20 00 00 1c brr ns,\+28
+ 7c: 07 a0 00 04 rflag r0
+ 80: a8 00 00 1a brr ne,\+26
+ 84: 07 a0 00 04 rflag r0
+ 88: 30 00 00 18 brr cc,\+24
+ 8c: 07 a0 00 04 rflag r0
+ 90: 38 00 00 16 brr oc,\+22
+ 94: 07 a0 00 04 rflag r0
+ 98: c0 00 00 14 brr nc,\+20
+ 9c: 07 a0 00 04 rflag r0
+ a0: 48 00 00 12 brr ge,\+18
+ a4: 07 a0 00 04 rflag r0
+ a8: d0 00 00 10 brr gt,\+16
+ ac: 07 a0 00 04 rflag r0
+ b0: 58 00 00 0e brr hi,\+14
+ b4: 07 a0 00 04 rflag r0
+ b8: 60 00 00 0c brr le,\+12
+ bc: 07 a0 00 04 rflag r0
+ c0: e8 00 00 0a brr ls,\+10
+ c4: 07 a0 00 04 rflag r0
+ c8: 70 00 00 08 brr lt,\+8
+ cc: 07 a0 00 04 rflag r0
+ d0: 78 00 00 06 brr tr,\+6
+ d4: 07 a0 00 04 rflag r0
+ d8: 08 00 ff e0 brr eq,-32
+ dc: 00 00 00 00 nop
+ e0: 00 00 00 00 nop
+ e4: 00 00 00 00 nop
+
+0+00000e8 <sreg>:
+ e8: 86 20 00 14 adc.l r0,r0,r1
+ ec: 86 20 08 32 adc.w r2,r0,r3
+ f0: 86 20 10 51 adc.b r4,r0,r5
+ f4: 86 00 08 14 add.l r2,r0,r1
+ f8: 06 04 14 32 add.w r5,r4,r3
+ fc: 86 07 1c 61 add.b r7,r7,r6
+ 100: 87 40 08 14 and.l r2,r0,r1
+ 104: 07 44 14 32 and.w r5,r4,r3
+ 108: 87 47 1c 61 and.b r7,r7,r6
+ 10c: 06 e3 10 44 asl.l r4,r3,r4
+ 110: 86 e5 1a 02 asl.w r6,r5,0
+ 114: 06 e5 1a 12 asl.w r6,r5,1
+ 118: 06 e7 23 f1 asl.b r8,r7,31
+ 11c: 86 a3 10 44 asr.l r4,r3,r4
+ 120: 06 a5 1a 02 asr.w r6,r5,0
+ 124: 86 a5 1a 12 asr.w r6,r5,1
+ 128: 86 a7 23 f1 asr.b r8,r7,31
+ 12c: 0f 89 28 04 bra eq,r9,r10
+ 130: 07 a0 00 04 rflag r0
+ 134: af 87 04 04 bra ne,r7,r1
+ 138: 07 e0 ae 04 readmda r11
+ 13c: 07 e0 b3 f4 eamread r12,31
+ 140: 87 cd 30 04 extb.l r12,r13
+ 144: 87 cf 38 02 extb.w r14,r15
+ 148: 87 c1 00 01 extb.b r0,r1
+ 14c: 86 83 08 04 extw.l r2,r3
+ 150: 86 85 10 02 extw.w r4,r5
+ 154: 86 c7 18 84 lsr.l r6,r7,r8
+ 158: 06 ca 26 02 lsr.w r9,r10,0
+ 15c: 86 ca 26 12 lsr.w r9,r10,1
+ 160: 86 ca 27 f1 lsr.b r9,r10,31
+ 164: 87 6c 2c 04 not.l r11,r12
+ 168: 07 6e 34 02 not.w r13,r14
+ 16c: 07 6a 3c 01 not.b r15,r10
+ 170: 07 26 14 74 or.l r5,r6,r7
+ 174: 07 29 20 a2 or.w r8,r9,r10
+ 178: 87 22 04 31 or.b r1,r2,r3
+ 17c: 87 e5 12 04 read.l r4,0\(r5\)
+ 180: 87 e5 12 04 read.l r4,0\(r5\)
+ 184: 07 e7 1a 12 read.w r6,1\(r7\)
+ 188: 07 e9 23 f1 read.b r8,31\(r9\)
+ 18c: 87 e9 1a 11 read.b r6,1\(r9\)
+ 190: 87 e0 aa 04 readmda r10
+ 194: 87 e0 ae 14 readmdb r11
+ 198: 07 e0 c6 24 readmdc r17
+ 19c: 87 a0 10 04 rflag r4
+ 1a0: 87 a0 1c 04 rflag r7
+ 1a4: 86 45 10 64 sub.l r4,r5,r6
+ 1a8: 06 48 1c 92 sub.w r7,r8,r9
+ 1ac: 06 41 00 21 cmp.b r1,r2
+ 1b0: 06 65 10 64 subc.l r4,r5,r6
+ 1b4: 86 68 1c 92 subc.w r7,r8,r9
+ 1b8: 86 61 00 21 cmpc.b r1,r2
+ 1bc: 07 03 10 24 xor.l r4,r3,r2
+ 1c0: 87 06 14 72 xor.w r5,r6,r7
+ 1c4: 07 09 04 81 xor.b r1,r9,r8
+ 1c8: 04 07 ff ff addi r7,65535
+ 1cc: 04 87 80 00 movil r7,0x8000
+ 1d0: 84 a7 7f ff moviu r7,0x7FFF
+ 1d4: 04 c6 00 01 moviq r6,1
+ 1d8: 84 47 ff ff subi r7,65535
+ 1dc: ff 86 00 04 bra tr,r6,r0
+ 1e0: 86 00 00 04 add.l r0,r0,r0
+ 1e4: d3 e3 84 5c fpinst 10,f1,f3,f5
+ 1e8: db e4 88 6c fpinst 11,f2,f4,f6
+ 1ec: 7b ed ac fc fpinst 15,f11,f13,f15
+ 1f0: 8f ef e6 ec fpuread 1,r25,f15,f14
+ 1f4: 3b e3 9c 0c fabs f7,f3
+ 1f8: 0b e6 b0 ec fadd f12,f6,f14
+ 1fc: 8b e6 b0 0c fadd f12,f6,f0
+ 200: 63 e6 b0 0c fmove f12,f6
+ 204: b3 e3 9c 0c fneg f7,f3
+ 208: 93 e0 8c 9c fsub f3,f0,f9
+ 20c: 1b e2 84 3c fmult f1,f2,f3
+ 210: 23 eb a8 cc fdiv f10,f11,f12
+ 214: 2b e9 8c 0c fsqrt f3,f9
+ 218: 43 e4 94 0c ftoi f5,f4
+ 21c: 4b e8 9c 0c itof f7,f8
+ 220: 03 ff b4 0c fload f13,r31
+ 224: 07 e7 e6 0c fstore r25,f7
+ 228: 57 ef 82 0c fcmp r0,f15,f0
+ 22c: 5f ef 82 1c fcmpe r0,f15,f1
+ 230: 57 ef 82 0c fcmp r0,f15,f0
+ 234: 5f ef 82 1c fcmpe r0,f15,f1
+ 238: 02 63 00 04 bmd r1,r2,r3
+ 23c: 82 23 00 04 bmi r1,r2,r3
+ 240: 85 00 80 00 wrtl 0x8000
+ 244: 05 20 7f ff wrtu 0x7FFF