BSD 4_3_Net_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 26 Oct 1990 05:14:08 +0000 (21:14 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 26 Oct 1990 05:14:08 +0000 (21:14 -0800)
Work on file usr/src/usr.bin/gas/config/i860.c
Work on file usr/src/usr.bin/gas/config/ns32k.c

Synthesized-from: CSRG/cd2/net.2

usr/src/usr.bin/gas/config/i860.c [new file with mode: 0644]
usr/src/usr.bin/gas/config/ns32k.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/gas/config/i860.c b/usr/src/usr.bin/gas/config/i860.c
new file mode 100644 (file)
index 0000000..9666943
--- /dev/null
@@ -0,0 +1,1142 @@
+/* i860.c -- Assemble for the I860
+   Copyright (C) 1989 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "i860-opcode.h"
+#include "as.h"
+#include "frags.h"
+#include "struc-symbol.h"
+#include "flonum.h"
+#include "expr.h"
+#include "hash.h"
+#include "md.h"
+#include "i860.h"      /* position dependent redefine */
+#include "write.h"
+#include "read.h"
+#include "symbols.h"
+
+void md_begin();
+void md_end();
+void md_number_to_chars();
+void md_assemble();
+char *md_atof();
+void md_convert_frag();
+void md_create_short_jump();
+void md_create_long_jump();
+int  md_estimate_size_before_relax();
+void md_number_to_imm();
+void md_number_to_disp();
+void md_number_to_field();
+void md_ri_to_chars();
+static void i860_ip();
+void emit_relocations();
+
+const relax_typeS md_relax_table[] = { 0 };
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+static void s_dual(), s_enddual();
+static void s_atmp();
+
+const pseudo_typeS
+md_pseudo_table[] = {
+    { "dual",       s_dual,     4 },
+    { "enddual",    s_enddual,  4 },
+    { "atmp",      s_atmp,     4 },
+    { NULL,         0,          0 },
+};
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+int omagic  =  OMAGIC;  /* Magic number for header */
+
+/* This array holds the chars that always start a comment.  If the
+    pre-processor is disabled, these aren't very useful */
+char comment_chars[] = "!/";   /* JF removed '|' from 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 '/*' will always start a comment */
+char line_comment_chars[] = "#/";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or    0d1.2345e12 */
+char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* 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.
+ */
+int size_reloc_info = sizeof(struct relocation_info);
+
+static unsigned char octal[256];
+#define isoctal(c)  octal[c]
+static unsigned char toHex[256];
+
+struct i860_it {
+    char    *error;
+    unsigned long opcode;
+    struct nlist *nlistp;
+    expressionS exp;
+    int pcrel;
+    enum expand_type expand;
+    enum highlow_type highlow;
+    enum reloc_type reloc;
+} the_insn;
+
+#ifdef __STDC__
+static void print_insn(struct i860_it *insn);
+static int getExpression(char *str);
+#else
+static void print_insn();
+static int getExpression();
+#endif
+static char *expr_end;
+static char last_expand;       /* error if expansion after branch */
+
+enum dual
+{
+    DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
+};
+static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */
+
+static void
+s_dual()       /* floating point instructions have dual set */
+{
+    dual_mode = DUAL_ON;
+}
+
+static void
+s_enddual()    /* floating point instructions have dual set */
+{
+    dual_mode = DUAL_OFF;
+}
+
+static int atmp = 31; /* temporary register for pseudo's */
+
+static void
+s_atmp()
+{
+    register int temp;
+    if (strncmp(input_line_pointer, "sp", 2) == 0) {
+      input_line_pointer += 2;
+      atmp = 2;
+    }
+    else if (strncmp(input_line_pointer, "fp", 2) == 0) {
+      input_line_pointer += 2;
+      atmp = 3;
+    }
+    else if (strncmp(input_line_pointer, "r", 1) == 0) {
+      input_line_pointer += 1;
+      temp = get_absolute_expression();
+      if (temp >= 0 && temp <= 31)
+          atmp = temp;
+        else
+            as_warn("Unknown temporary pseudo register");
+    }
+    else {
+        as_warn("Unknown temporary pseudo register");
+    }
+    demand_empty_rest_of_line();
+    return;
+}
+
+/* This function is called once, at assembler startup time.  It should
+   set up all the tables, etc. that the MD part of the assembler will need.  */
+void
+md_begin()
+{
+  register char *retval = NULL;
+  int lose = 0;
+  register unsigned int i = 0;
+
+  op_hash = hash_new();
+  if (op_hash == NULL)
+    as_fatal("Virtual memory exhausted");
+
+  while (i < NUMOPCODES)
+    {
+      const char *name = i860_opcodes[i].name;
+      retval = hash_insert(op_hash, name, &i860_opcodes[i]);
+      if(retval != NULL && *retval != '\0')
+       {
+         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+                  i860_opcodes[i].name, retval);
+         lose = 1;
+       }
+      do
+       {
+         if (i860_opcodes[i].match & i860_opcodes[i].lose)
+           {
+             fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+                      i860_opcodes[i].name, i860_opcodes[i].args);
+             lose = 1;
+           }
+         ++i;
+       } while (i < NUMOPCODES
+                && !strcmp(i860_opcodes[i].name, name));
+    }
+
+  if (lose)
+    as_fatal ("Broken assembler.  No assembly attempted.");
+
+  for (i = '0'; i < '8'; ++i)
+    octal[i] = 1;
+  for (i = '0'; i <= '9'; ++i)
+    toHex[i] = i - '0';
+  for (i = 'a'; i <= 'f'; ++i)
+    toHex[i] = i + 10 - 'a';
+  for (i = 'A'; i <= 'F'; ++i)
+    toHex[i] = i + 10 - 'A';
+}
+
+void
+md_end()
+{
+    return;
+}
+
+void
+md_assemble(str)
+    char *str;
+{
+    char *toP;
+    int rsd;
+    int no_opcodes = 1;
+    int i;
+    struct i860_it pseudo[3];
+
+    assert(str);
+    i860_ip(str);
+
+    /* check for expandable flag to produce pseudo-instructions */
+    if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {
+       for (i = 0; i < 3; i++)
+           pseudo[i] = the_insn;
+
+       switch (the_insn.expand) {
+
+       case E_DELAY:
+               no_opcodes = 1;
+               break;
+
+       case E_MOV:
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 15) &&
+                the_insn.exp.X_add_number >= -(1 << 15)))
+               break;
+           /* or l%const,r0,ireg_dest */
+           pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
+           pseudo[0].highlow = PAIR;
+           /* orh h%const,ireg_dest,ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
+               ((the_insn.opcode & 0x001f0000) << 5);
+           pseudo[1].highlow = HIGH;
+           no_opcodes = 2;
+           break;
+
+       case E_ADDR:
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL)
+               break;
+           /* orh ha%addr_expr,r0,r31 */
+           pseudo[0].opcode = 0xec000000 | (atmp<<16);
+           pseudo[0].highlow = HIGHADJ;
+           pseudo[0].reloc = LOW0;     /* must overwrite */
+           /* l%addr_expr(r31),ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
+           pseudo[1].highlow = PAIR;
+           no_opcodes = 2;
+           break;
+
+       case E_U32:     /* 2nd version emulates Intel as, not doc. */
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 16) &&
+                the_insn.exp.X_add_number >= 0))
+               break;
+           /* $(opcode)h h%const,ireg_src2,ireg_dest
+           pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */
+           /* $(opcode)h h%const,ireg_src2,r31 */
+           pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
+               (atmp << 16);
+           pseudo[0].highlow = HIGH;
+           /* $(opcode) l%const,ireg_dest,ireg_dest
+           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+               ((the_insn.opcode & 0x001f0000) << 5); */
+           /* $(opcode) l%const,r31,ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+               (atmp << 21);
+           pseudo[1].highlow = PAIR;
+           no_opcodes = 2;
+           break;
+
+       case E_AND:     /* 2nd version emulates Intel as, not doc. */
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 16) &&
+                the_insn.exp.X_add_number >= 0))
+               break;
+           /* andnot h%const,ireg_src2,ireg_dest
+           pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */
+           /* andnot h%const,ireg_src2,r31 */
+           pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |
+               (atmp << 16);
+           pseudo[0].highlow = HIGH;
+           pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+           /* andnot l%const,ireg_dest,ireg_dest
+           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+               ((the_insn.opcode & 0x001f0000) << 5); */
+           /* andnot l%const,r31,ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+               (atmp << 21);
+           pseudo[1].highlow = PAIR;
+           pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+           no_opcodes = 2;
+           break;
+
+       case E_S32:
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 15) &&
+                the_insn.exp.X_add_number >= -(1 << 15)))
+               break;
+           /* orh h%const,r0,r31 */
+           pseudo[0].opcode = 0xec000000 | (atmp << 16);
+           pseudo[0].highlow = HIGH;
+           /* or l%const,r31,r31 */
+           pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
+           pseudo[1].highlow = PAIR;
+           /* r31,ireg_src2,ireg_dest */
+           pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
+           pseudo[2].reloc = NO_RELOC;
+           no_opcodes = 3;
+           break;
+
+       default:
+           abort();
+       }
+
+        the_insn = pseudo[0];
+       /* check for expanded opcode after branch or in dual */
+       if (no_opcodes > 1 && last_expand == TRUE)
+           as_warn("Expanded opcode after delayed branch: `%s'", str);
+       if (no_opcodes > 1 && dual_mode != DUAL_OFF)
+           as_warn("Expanded opcode in dual mode: `%s'", str);
+    }
+
+    i = 0;
+    do {       /* always produce at least one opcode */
+        toP = frag_more(4);
+        /* put out the opcode */
+        md_number_to_chars(toP, the_insn.opcode, 4);
+
+       /* check for expanded opcode after branch or in dual */
+       last_expand = the_insn.pcrel;
+
+        /* put out the symbol-dependent stuff */
+        if (the_insn.reloc != NO_RELOC) {
+           fix_new(
+               frag_now,                           /* which frag */
+               (toP - frag_now->fr_literal), /* where */
+               4,                                  /* size */
+               the_insn.exp.X_add_symbol,
+               the_insn.exp.X_subtract_symbol,
+               the_insn.exp.X_add_number,
+               the_insn.pcrel,
+               /* merge bit fields into one argument */
+               (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))
+           );
+        }
+        the_insn = pseudo[++i];
+    } while (--no_opcodes > 0);
+
+}
+
+static void
+i860_ip(str)
+    char *str;
+{
+    char *s;
+    const char *args;
+    char c;
+    unsigned long i;
+    struct i860_opcode *insn;
+    char *argsStart;
+    unsigned long   opcode;
+    unsigned int mask;
+    int match = FALSE;
+    int comma = 0;
+
+
+    for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s)
+       ;
+    switch (*s) {
+
+    case '\0':
+       break;
+
+    case ',':
+       comma = 1;
+
+       /*FALLTHROUGH*/
+
+    case ' ':
+       *s++ = '\0';
+       break;
+
+    default:
+           as_warn("Unknown opcode: `%s'", str);
+           exit(1);
+    }
+
+    if (strncmp(str, "d.", 2) == 0) {  /* check for d. opcode prefix */
+       if (dual_mode == DUAL_ON)
+           dual_mode = DUAL_ONDDOT;
+       else
+           dual_mode = DUAL_DDOT;
+       str += 2;
+    }
+
+    if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) {
+       if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
+           str -= 2;
+       as_warn("Unknown opcode: `%s'", str);
+       return;
+    }
+    if (comma) {
+       *--s = ',';
+    }
+    argsStart = s;
+    for (;;) {
+       opcode = insn->match;
+       bzero(&the_insn, sizeof(the_insn));
+       the_insn.reloc = NO_RELOC;
+
+       /*
+        * Build the opcode, checking as we go to make
+        * sure that the operands match
+        */
+       for (args = insn->args; ; ++args) {
+           switch (*args) {
+
+           case '\0':  /* end of args */
+               if (*s == '\0') {
+                   match = TRUE;
+               }
+               break;
+
+           case '+':
+           case '(':   /* these must match exactly */
+           case ')':
+           case ',':
+           case ' ':
+               if (*s++ == *args)
+                   continue;
+               break;
+
+           case '#':   /* must be at least one digit */
+               if (isdigit(*s++)) {
+                   while (isdigit(*s)) {
+                       ++s;
+                   }
+                   continue;
+               }
+               break;
+
+           case '1':   /* next operand must be a register */
+           case '2':
+           case 'd':
+               switch (*s) {
+
+               case 'f':   /* frame pointer */
+                   s++;
+                   if (*s++ == 'p') {
+                       mask = 0x3;
+                       break;
+                   }
+                   goto error;
+
+               case 's':   /* stack pointer */
+                   s++;
+                   if (*s++ == 'p') {
+                       mask= 0x2;
+                       break;
+                   }
+                   goto error;
+
+               case 'r': /* any register */
+                   s++;
+                   if (!isdigit(c = *s++)) {
+                       goto error;
+                   }
+                   if (isdigit(*s)) {
+                       if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
+                           goto error;
+                       }
+                   } else {
+                       c -= '0';
+                   }
+                   mask= c;
+                   break;
+
+               default:        /* not this opcode */
+                   goto error;
+               }
+               /*
+                * Got the register, now figure out where
+                * it goes in the opcode.
+                */
+               switch (*args) {
+
+               case '1':
+                   opcode |= mask << 11;
+                   continue;
+
+               case '2':
+                   opcode |= mask << 21;
+                   continue;
+
+               case 'd':
+                   opcode |= mask << 16;
+                   continue;
+
+               }
+               break;
+
+           case 'e':    /* next operand is a floating point register */
+           case 'f':
+           case 'g':
+               if (*s++ == 'f' && isdigit(*s)) {
+                   mask = *s++;
+                   if (isdigit(*s)) {
+                       mask = 10 * (mask - '0') + (*s++ - '0');
+                       if (mask >= 32) {
+                           break;
+                       }
+                   } else {
+                       mask -= '0';
+                   }
+                   switch (*args) {
+
+                   case 'e':
+                       opcode |= mask << 11;
+                       continue;
+
+                   case 'f':
+                       opcode |= mask << 21;
+                       continue;
+
+                   case 'g':
+                       opcode |= mask << 16;
+                       if (dual_mode != DUAL_OFF)
+                           opcode |= (1 << 9); /* dual mode instruction */
+                       if (dual_mode == DUAL_DDOT)
+                           dual_mode = DUAL_OFF;
+                       if (dual_mode == DUAL_ONDDOT)
+                           dual_mode = DUAL_ON;
+                       if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))
+                           as_warn("Fsr1 equals fdest with Pipelining");
+                       continue;
+                   }
+               }
+               break;
+
+           case 'c': /* next operand must be a control register */
+               if (strncmp(s, "fir", 3) == 0) {
+                   opcode |= 0x0 << 21;
+                   s += 3;
+                   continue;
+               }
+               if (strncmp(s, "psr", 3) == 0) {
+                   opcode |= 0x1 << 21;
+                   s += 3;
+                   continue;
+               }
+               if (strncmp(s, "dirbase", 7) == 0) {
+                   opcode |= 0x2 << 21;
+                   s += 7;
+                   continue;
+               }
+               if (strncmp(s, "db", 2) == 0) {
+                   opcode |= 0x3 << 21;
+                   s += 2;
+                   continue;
+               }
+               if (strncmp(s, "fsr", 3) == 0) {
+                   opcode |= 0x4 << 21;
+                   s += 3;
+                   continue;
+               }
+               if (strncmp(s, "epsr", 4) == 0) {
+                   opcode |= 0x5 << 21;
+                   s += 4;
+                   continue;
+               }
+               break;
+
+           case '5':   /* 5 bit immediate in src1 */
+               bzero(&the_insn, sizeof(the_insn));
+               if ( !getExpression(s)) {
+                   s = expr_end;
+                   if (the_insn.exp.X_add_number & ~0x1f)
+                       as_warn("5-bit immediate too large");
+                   opcode |= (the_insn.exp.X_add_number & 0x1f) << 11;
+                   bzero(&the_insn, sizeof(the_insn));
+                   the_insn.reloc = NO_RELOC;
+                   continue;
+               }
+               break;
+
+           case 'l':   /* 26 bit immediate, relative branch */
+               the_insn.reloc = BRADDR;
+               the_insn.pcrel = TRUE;
+               goto immediate;
+
+           case 's':   /* 16 bit immediate, split relative branch */
+                       /* upper 5 bits of offset in dest field */
+               the_insn.pcrel = TRUE;
+               the_insn.reloc = SPLIT0;
+               goto immediate;
+
+           case 'S':   /* 16 bit immediate, split (st), aligned */
+               if (opcode & (1 << 28))
+                   if (opcode & 0x1)
+                       the_insn.reloc = SPLIT2;
+                   else
+                       the_insn.reloc = SPLIT1;
+               else
+                   the_insn.reloc = SPLIT0;
+               goto immediate;
+
+           case 'I':   /* 16 bit immediate, aligned */
+               if (opcode & (1 << 28))
+                   if (opcode & 0x1)
+                       the_insn.reloc = LOW2;
+                   else
+                       the_insn.reloc = LOW1;
+               else
+                   the_insn.reloc = LOW0;
+               goto immediate;
+
+           case 'i':   /* 16 bit immediate */
+               the_insn.reloc = LOW0;
+
+               /*FALLTHROUGH*/
+
+           immediate:
+               if(*s==' ')
+                 s++;
+               if (strncmp(s, "ha%", 3) == 0) {
+                   the_insn.highlow = HIGHADJ;
+                   s += 3;
+               } else if (strncmp(s, "h%", 2) == 0) {
+                   the_insn.highlow = HIGH;
+                   s += 2;
+               } else if (strncmp(s, "l%", 2) == 0) {
+                   the_insn.highlow = PAIR;
+                   s += 2;
+               }
+               the_insn.expand = insn->expand; 
+
+               /* Note that if the getExpression() fails, we will still have
+                  created U entries in the symbol table for the 'symbols'
+                  in the input string.  Try not to create U symbols for
+                  registers, etc. */
+
+               if ( !getExpression(s)) {
+                   s = expr_end;
+                   continue;
+               }
+               break;
+
+           default:
+               abort();
+           }
+           break;
+       }
+       error:
+       if (match == FALSE)
+         {
+           /* Args don't match.  */
+           if (&insn[1] - i860_opcodes < NUMOPCODES
+               && !strcmp(insn->name, insn[1].name))
+             {
+               ++insn;
+               s = argsStart;
+               continue;
+             }
+           else
+             {
+               as_warn("Illegal operands");
+               return;
+             }
+         }
+       break;
+    }
+
+    the_insn.opcode = opcode;
+    return;
+}
+
+static int
+getExpression(str)
+    char *str;
+{
+    char *save_in;
+    segT seg;
+
+    save_in = input_line_pointer;
+    input_line_pointer = str;
+    switch (seg = expression(&the_insn.exp)) {
+
+    case SEG_ABSOLUTE:
+    case SEG_TEXT:
+    case SEG_DATA:
+    case SEG_BSS:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_NONE:
+       break;
+
+    default:
+       the_insn.error = "bad segment";
+       expr_end = input_line_pointer;
+       input_line_pointer=save_in;
+       return 1;
+    }
+    expr_end = input_line_pointer;
+    input_line_pointer = save_in;
+    return 0;
+}
+
+
+/*
+    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(type,litP,sizeP)
+    char type;
+    char *litP;
+    int *sizeP;
+{
+    int        prec;
+    LITTLENUM_TYPE words[MAX_LITTLENUMS];
+    LITTLENUM_TYPE *wordP;
+    char       *t;
+    char       *atof_ieee();
+
+    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);
+    for(wordP=words;prec--;) {
+       md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
+       litP+=sizeof(LITTLENUM_TYPE);
+    }
+    return ""; /* Someone should teach Dean about null pointers */
+}
+
+/*
+ * Write out big-endian.
+ */
+void
+md_number_to_chars(buf,val,n)
+    char *buf;
+    long val;
+    int n;
+{
+    switch(n) {
+
+    case 4:
+       *buf++ = val >> 24;
+       *buf++ = val >> 16;
+    case 2:
+       *buf++ = val >> 8;
+    case 1:
+       *buf = val;
+       break;
+
+    default:
+       abort();
+    }
+    return;
+}
+
+void
+md_number_to_imm(buf,val,n, fixP, seg_type)
+    char *buf;
+    long val;
+    int n;
+    fixS *fixP;
+    int seg_type;
+{
+    enum reloc_type reloc = fixP->fx_r_type & 0xf;
+    enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3;
+
+    assert(buf);
+    assert(n == 4);    /* always on i860 */
+
+    switch(highlow)
+    {
+
+    case HIGHADJ:      /* adjusts the high-order 16-bits */
+       if (val & (1 << 15))
+           val += (1 << 16);
+
+           /*FALLTHROUGH*/
+
+    case HIGH: /* selects the high-order 16-bits */
+       val >>= 16;
+       break;
+
+    case PAIR: /* selects the low-order 16-bits */
+       val = val & 0xffff;
+       break;
+
+    default:
+       break;
+    }
+
+    switch(reloc)
+    {
+
+    case BRADDR:       /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */
+       if (fixP->fx_pcrel != TRUE)
+           as_warn("26-bit branch w/o pc relative set: 0x%08x", val);
+       val >>= 2;      /* align pcrel offset, see manual */
+
+       if (val >= (1 << 25) || val < -(1 << 25))       /* check for overflow */
+           as_warn("26-bit branch offset overflow: 0x%08x", val);
+       buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3);
+       buf[1] = val >> 16;
+       buf[2] = val >> 8;
+       buf[3] = val;
+       break;
+
+    case SPLIT2:       /* 16 bit immediate, 4-byte aligned */
+       if (val & 0x3)
+           as_warn("16-bit immediate 4-byte alignment error: 0x%08x", val);
+       val &= ~0x3;    /* 4-byte align value */
+       /*FALLTHROUGH*/
+    case SPLIT1:       /* 16 bit immediate, 2-byte aligned */
+       if (val & 0x1)
+           as_warn("16-bit immediate 2-byte alignment error: 0x%08x", val);
+       val &= ~0x1;    /* 2-byte align value */
+       /*FALLTHROUGH*/
+    case SPLIT0:       /* st,bla,bte,btne w/16-bit immediate */
+       if (fixP->fx_pcrel == TRUE)
+           val >>= 2;  /* align pcrel offset, see manual */
+       /* check for bounds */
+       if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+           as_warn("16-bit branch offset overflow: 0x%08x", val);
+       buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f);
+       buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7);
+       buf[3] |= val;  /* perserve bottom opcode bits */       
+       break;
+
+    case LOW4: /* fld,pfld,pst,flush 16-byte aligned */
+       if (val & 0xf)
+           as_warn("16-bit immediate 16-byte alignment error: 0x%08x", val);
+       val &= ~0xf;    /* 16-byte align value */
+       /*FALLTHROUGH*/
+    case LOW3: /* fld,pfld,pst,flush 8-byte aligned */
+       if (val & 0x7)
+           as_warn("16-bit immediate 8-byte alignment error: 0x%08x", val);
+       val &= ~0x7;    /* 8-byte align value */
+       /*FALLTHROUGH*/
+    case LOW2: /* 16 bit immediate, 4-byte aligned */
+       if (val & 0x3)
+           as_warn("16-bit immediate 4-byte alignment error: 0x%08x", val);
+       val &= ~0x3;    /* 4-byte align value */
+       /*FALLTHROUGH*/
+    case LOW1: /* 16 bit immediate, 2-byte aligned */
+       if (val & 0x1)
+           as_warn("16-bit immediate 2-byte alignment error: 0x%08x", val);
+       val &= ~0x1;    /* 2-byte align value */
+       /*FALLTHROUGH*/
+    case LOW0: /* 16 bit immediate, byte aligned */
+       /* check for bounds */
+       if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+           as_warn("16-bit immediate overflow: 0x%08x", val);
+       buf[2] = val >> 8;
+       buf[3] |= val;  /* perserve bottom opcode bits */       
+       break;
+
+    case NO_RELOC:
+    default:
+       as_warn("bad relocation type: 0x%02x", reloc);
+       break;
+    }
+    return;
+}
+
+/* should never be called for i860 */
+void
+md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+    char *ptr;
+    long from_addr, to_addr;
+{
+    fprintf(stderr, "i860_create_short_jmp\n");
+    abort();
+}
+
+/* should never be called for i860 */
+void
+md_number_to_disp(buf,val,n)
+    char       *buf;
+    long       val;
+{
+    fprintf(stderr, "md_number_to_disp\n");
+    abort();
+}
+
+/* should never be called for i860 */
+void
+md_number_to_field(buf,val,fix)
+    char *buf;
+    long val;
+    void *fix;
+{
+    fprintf(stderr, "i860_number_to_field\n");
+    abort();
+}
+
+/* the bit-field entries in the relocation_info struct plays hell 
+   with the byte-order problems of cross-assembly.  So as a hack,
+   I added this mach. dependent ri twiddler.  Ugly, but it gets
+   you there. -KWK */
+/* on i860: first 4 bytes are normal unsigned long address, next three
+   bytes are index, most sig. byte first.  Byte 7 is broken up with
+   bit 7 as pcrel, bit 6 as extern, and the lower six bits as
+   relocation type (highlow 5-4).  Next 4 bytes are long int addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+void
+md_ri_to_chars(ri_p, ri)
+     struct relocation_info *ri_p, ri;
+{
+#if 0
+  unsigned char the_bytes[sizeof(*ri_p)];
+  
+  /* this is easy */
+  md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address));
+  /* now the fun stuff */
+  the_bytes[4] = (ri.r_index >> 16) & 0x0ff;
+  the_bytes[5] = (ri.r_index >> 8) & 0x0ff;
+  the_bytes[6] = ri.r_index & 0x0ff;
+  the_bytes[7] = ((ri.r_extern << 7)  & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F);
+  /* Also easy */
+  md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend));
+  /* now put it back where you found it, Junior... */
+  bcopy (the_bytes, (char *)ri_p, sizeof(*ri_p));
+#endif
+}
+
+/* should never be called for i860 */
+void
+md_convert_frag(fragP)
+    register fragS *fragP;
+{
+    fprintf(stderr, "i860_convert_frag\n");
+    abort();
+}
+
+/* should never be called for i860 */
+void
+md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+    char       *ptr;
+    long       from_addr,
+               to_addr;
+    fragS      *frag;
+    symbolS    *to_symbol;
+{
+    fprintf(stderr, "i860_create_long_jump\n");
+    abort();
+}
+
+/* should never be called for i860 */
+int
+md_estimate_size_before_relax(fragP, segtype)
+    register fragS *fragP;
+{
+    fprintf(stderr, "i860_estimate_size_before_relax\n");
+    abort();
+    return 0;
+}
+
+/* for debugging only, must match enum reloc_type */
+static char *Reloc[] = {
+    "NO_RELOC",
+    "BRADDR", 
+    "LOW0", 
+    "LOW1", 
+    "LOW2", 
+    "LOW3", 
+    "LOW4", 
+    "SPLIT0", 
+    "SPLIT1", 
+    "SPLIT2", 
+    "RELOC_32", 
+};
+static char *Highlow[] = {
+    "NO_SPEC",
+    "PAIR", 
+    "HIGH", 
+    "HIGHADJ", 
+};
+static void
+print_insn(insn)
+    struct i860_it *insn;
+{
+    if (insn->error) {
+       fprintf(stderr, "ERROR: %s\n");
+    }
+    fprintf(stderr, "opcode=0x%08x\t", insn->opcode);
+    fprintf(stderr, "expand=0x%08x\t", insn->expand);
+    fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]);
+    fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]);
+    fprintf(stderr, "exp =  {\n");
+    fprintf(stderr, "\t\tX_add_symbol = %s\n",
+       insn->exp.X_add_symbol ?
+       (insn->exp.X_add_symbol->sy_name ? 
+       insn->exp.X_add_symbol->sy_name : "???") : "0");
+    fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+       insn->exp.X_subtract_symbol ?
+           (insn->exp.X_subtract_symbol->sy_name ? 
+               insn->exp.X_subtract_symbol->sy_name : "???") : "0");
+    fprintf(stderr, "\t\tX_add_number = %d\n",
+       insn->exp.X_add_number);
+    fprintf(stderr, "}\n");
+    return;
+}
+
+int
+md_parse_option(argP,cntP,vecP)
+    char **argP;
+    int *cntP;
+    char ***vecP;
+{
+    return 1;
+}
+
+/*
+ * I860 relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+void
+emit_relocations(fixP, segment_address_in_file)
+    register fixS *fixP;
+    relax_addressT segment_address_in_file;
+{
+    struct reloc_info_i860 ri;
+    register symbolS *symbolP;
+    extern char *next_object_file_charP;
+    long add_number;
+
+    bzero((char *) &ri, sizeof(ri));
+    for (; fixP; fixP = fixP->fx_next) {
+
+       if (fixP->fx_r_type & ~0x3f) {
+           fprintf(stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
+           abort();
+       }
+       ri.r_pcrel = fixP->fx_pcrel;
+       ri.r_type = fixP->fx_r_type;
+
+       if ((symbolP = fixP->fx_addsy) != NULL) {
+           ri.r_address = fixP->fx_frag->fr_address +
+               fixP->fx_where - segment_address_in_file;
+           if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
+               ri.r_extern = 1;
+               ri.r_symbolnum = symbolP->sy_number;
+           } else {
+               ri.r_extern = 0;
+               ri.r_symbolnum = symbolP->sy_type & N_TYPE;
+           }
+           if (symbolP && symbolP->sy_frag) {
+               ri.r_addend = symbolP->sy_frag->fr_address;
+           }
+           ri.r_type = fixP->fx_r_type;
+           if (fixP->fx_pcrel) {
+               /* preserve actual offset vs. pc + 4 */
+               ri.r_addend -= (ri.r_address + 4);
+           } else {
+               ri.r_addend = fixP->fx_addnumber;
+           }
+
+           md_ri_to_chars((char *) &ri, ri);
+           append(&next_object_file_charP, (char *)& ri, sizeof(ri));
+       }
+    }
+    return;
+}
+
diff --git a/usr/src/usr.bin/gas/config/ns32k.c b/usr/src/usr.bin/gas/config/ns32k.c
new file mode 100644 (file)
index 0000000..8db917b
--- /dev/null
@@ -0,0 +1,1768 @@
+/* ns32k.c  -- Assemble on the National Semiconductor 32k series
+   Copyright (C) 1987 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define NS32K
+/*#define SHOW_NUM 1*/ /* uncomment for debugging */
+
+#include <stdio.h>
+#include <ctype.h>
+#ifdef USG
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "ns32k-opcode.h"
+#include "as.h"
+#include "obstack.h"
+#include "frags.h"
+#include "struc-symbol.h"
+#include "flonum.h"
+#include "expr.h"
+#include "md.h"
+#include "hash.h"
+#include "write.h"
+#include "symbols.h"
+
+/* Macros */
+#define IIF_ENTRIES 13                         /* number of entries in iif */ 
+#define PRIVATE_SIZE 256                       /* size of my garbage memory */
+#define MAX_ARGS 4
+#define DEFAULT        -1              /* addr_mode returns this value when plain constant or label is encountered */
+
+#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1) \
+  iif.iifP[ptr].type= a1; \
+  iif.iifP[ptr].size= c1; \
+  iif.iifP[ptr].object= e1; \
+  iif.iifP[ptr].object_adjust= g1; \
+  iif.iifP[ptr].pcrel= i1; \
+  iif.iifP[ptr].pcrel_adjust= k1; \
+  iif.iifP[ptr].im_disp= m1; \
+  iif.iifP[ptr].relax_substate= o1; \
+  iif.iifP[ptr].bit_fixP= q1; \
+  iif.iifP[ptr].addr_mode= s1; \
+  iif.iifP[ptr].bsr= u1;
+
+#ifdef SEQUENT_COMPATABILITY
+#define LINE_COMMENT_CHARS "|"
+#define ABSOLUTE_PREFIX '@'
+#define IMMEDIATE_PREFIX '#'
+#endif
+
+#ifndef LINE_COMMENT_CHARS
+#define LINE_COMMENT_CHARS "#"
+#endif
+
+char comment_chars[] = "#";
+char line_comment_chars[] = LINE_COMMENT_CHARS;
+#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX)
+#define ABSOLUTE_PREFIX '@'    /* One or the other MUST be defined */
+#endif
+
+struct addr_mode {
+  char mode;                   /* addressing mode of operand (0-31) */
+  char scaled_mode;            /* mode combined with scaled mode */
+  char scaled_reg;             /* register used in scaled+1 (1-8) */
+  char float_flag;             /* set if R0..R7 was F0..F7 ie a floating-point-register */
+  char am_size;                        /* estimated max size of general addr-mode parts*/
+  char im_disp;                        /* if im_disp==1 we have a displacement */
+  char pcrel;                  /* 1 if pcrel, this is really redundant info */
+  char disp_suffix[2];         /* length of displacement(s), 0=undefined */
+  char *disp[2];               /* pointer(s) at displacement(s)
+                                             or immediates(s)     (ascii) */
+  char index_byte;             /* index byte */
+};
+typedef struct addr_mode addr_modeS;
+
+
+char *freeptr,*freeptr_static; /* points at some number of free bytes */
+struct hash_control *inst_hash_handle;
+
+struct ns32k_opcode *desc; /* pointer at description of instruction */
+addr_modeS addr_modeP;
+char EXP_CHARS[] = "eE";
+char FLT_CHARS[] = "fd"; /* we don't want to support lowercase, do we */
+long omagic = OMAGIC;
+void md_number_to_disp();
+void md_number_to_imm();
+segT evaluate_expr();
+void fix_new_ns32k();
+
+/* UPPERCASE denotes live names 
+ * when an instruction is built, IIF is used as an intermidiate form to store
+ * the actual parts of the instruction. A ns32k machine instruction can
+ * be divided into a couple of sub PARTs. When an instruction is assembled
+ * the appropriate PART get an assignment. When an IIF has been completed it's
+ * converted to a FRAGment as specified in AS.H */
+
+/* internal structs */
+struct option {
+  char *pattern;
+  unsigned long or;
+  unsigned long and;
+};
+
+typedef struct {
+  int                  type;           /* how to interpret object */
+  int                  size;           /* Estimated max size of object */
+  unsigned long                object;         /* binary data */
+  int                  object_adjust;  /* number added to object */
+  int                  pcrel;          /* True if object is pcrel */
+  int                  pcrel_adjust;   /* It's value reflects the length in bytes from the instruction start to the displacement */
+  int                  im_disp;        /* True if the object is a displacement */
+  relax_substateT      relax_substate; /* Initial relaxsubstate */
+  bit_fixS             *bit_fixP;      /* Pointer at bit_fix struct */ 
+  int                  addr_mode;      /* What addrmode do we associate with this iif-entry */
+  char                 bsr;            /* Sequent hack */
+}iif_entryT;                           /* Internal Instruction Format */
+struct int_ins_form {
+  int          instr_size;             /* Max size of instruction in bytes. */
+  iif_entryT    iifP[IIF_ENTRIES+1];
+};
+struct int_ins_form iif;
+expressionS exprP;
+char *input_line_pointer;
+/* description of the PARTs in IIF 
+ *object[n]:
+ * 0   total length in bytes of entries in iif
+ * 1   opcode
+ * 2   index_byte_a
+ * 3   index_byte_b
+ * 4   disp_a_1
+ * 5   disp_a_2
+ * 6   disp_b_1
+ * 7   disp_b_2
+ * 8   imm_a
+ * 9   imm_b
+ * 10  implied1
+ * 11  implied2
+ * 
+ * For every entry there is a datalength in bytes. This is stored in size[n].
+ *      0,     the objectlength is not explicitly given by the instruction
+ *             and the operand is undefined. This is a case for relaxation.
+ *             Reserve 4 bytes for the final object.
+ *
+ *      1,     the entry contains one byte
+ *      2,     the entry contains two bytes
+ *      3,     the entry contains three bytes
+ *      4,     the entry contains four bytes
+ *     etc
+ *
+ * Furthermore, every entry has a data type identifier in type[n].
+ *
+ *      0,     the entry is void, ignore it.
+ *      1,     the entry is a binary number.
+ *      2,     the entry is a pointer at an expression.
+ *             Where expression may be as simple as a single '1',
+ *             and as complicated as  foo-bar+12,
+ *             foo and bar may be undefined but suffixed by :{b|w|d} to
+ *             control the length of the object.
+ *
+ *      3,     the entry is a pointer at a bignum struct
+ *
+ *
+ * The low-order-byte coresponds to low physical memory.
+ * Obviously a FRAGment must be created for each valid disp in PART whose
+ * datalength is undefined (to bad) .
+ * The case where just the expression is undefined is less severe and is
+ * handled by fix. Here the number of bytes in the objectfile is known.
+ * With this representation we simplify the assembly and separates the
+ * machine dependent/independent parts in a more clean way (said OE)
+ */
+\f
+struct option opt1[]= /* restore, exit */
+{
+  { "r0",      0x80,   0xff    },
+  { "r1",      0x40,   0xff    },
+  { "r2",      0x20,   0xff    },
+  { "r3",      0x10,   0xff    },
+  { "r4",      0x08,   0xff    },
+  { "r5",      0x04,   0xff    },
+  { "r6",      0x02,   0xff    },
+  { "r7",      0x01,   0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+struct option opt2[]= /* save, enter */
+{
+  { "r0",      0x01,   0xff    },
+  { "r1",      0x02,   0xff    },
+  { "r2",      0x04,   0xff    },
+  { "r3",      0x08,   0xff    },
+  { "r4",      0x10,   0xff    },
+  { "r5",      0x20,   0xff    },
+  { "r6",      0x40,   0xff    },
+  { "r7",      0x80,   0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+struct option opt3[]= /* setcfg */
+{
+  { "c",       0x8,    0xff    },
+  { "m",       0x4,    0xff    },
+  { "f",       0x2,    0xff    },
+  { "i",       0x1,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option opt4[]= /* cinv */
+{
+  { "a",       0x4,    0xff    },
+  { "i",       0x2,    0xff    },
+  { "d",       0x1,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option opt5[]= /* string inst */
+{
+  { "b",       0x2,    0xff    },
+  { "u",       0xc,    0xff    },
+  { "w",       0x4,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option opt6[]= /* plain reg ext,cvtp etc */
+{
+  { "r0",      0x00,   0xff    },
+  { "r1",      0x01,   0xff    },
+  { "r2",      0x02,   0xff    },
+  { "r3",      0x03,   0xff    },
+  { "r4",      0x04,   0xff    },
+  { "r5",      0x05,   0xff    },
+  { "r6",      0x06,   0xff    },
+  { "r7",      0x07,   0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+
+#if !defined(NS32032) && !defined(NS32532)
+#define NS32032
+#endif
+
+struct option cpureg_532[]= /* lpr spr */
+{
+  { "us",      0x0,    0xff    },
+  { "dcr",     0x1,    0xff    },
+  { "bpc",     0x2,    0xff    },
+  { "dsr",     0x3,    0xff    },
+  { "car",     0x4,    0xff    },
+  { "fp",      0x8,    0xff    },
+  { "sp",      0x9,    0xff    },
+  { "sb",      0xa,    0xff    },
+  { "usp",     0xb,    0xff    },
+  { "cfg",     0xc,    0xff    },
+  { "psr",     0xd,    0xff    },
+  { "intbase", 0xe,    0xff    },
+  { "mod",     0xf,    0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+struct option mmureg_532[]= /* lmr smr */
+{
+  { "mcr",     0x9,    0xff    },
+  { "msr",     0xa,    0xff    },
+  { "tear",    0xb,    0xff    },
+  { "ptb0",    0xc,    0xff    },
+  { "ptb1",    0xd,    0xff    },
+  { "ivar0",   0xe,    0xff    },
+  { "ivar1",   0xf,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+
+struct option cpureg_032[]= /* lpr spr */
+{
+  { "upsr",    0x0,    0xff    },
+  { "fp",      0x8,    0xff    },
+  { "sp",      0x9,    0xff    },
+  { "sb",      0xa,    0xff    },
+  { "psr",     0xd,    0xff    },
+  { "intbase", 0xe,    0xff    },
+  { "mod",     0xf,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option mmureg_032[]= /* lmr smr */
+{
+  { "bpr0",    0x0,    0xff    },
+  { "bpr1",    0x1,    0xff    },
+  { "pf0",     0x4,    0xff    },
+  { "pf1",     0x5,    0xff    },
+  { "sc",      0x8,    0xff    },
+  { "msr",     0xa,    0xff    },
+  { "bcnt",    0xb,    0xff    },
+  { "ptb0",    0xc,    0xff    },
+  { "ptb1",    0xd,    0xff    },
+  { "eia",     0xf,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+
+#if defined(NS32532)
+struct option *cpureg = cpureg_532;
+struct option *mmureg = mmureg_532;
+#else
+struct option *cpureg = cpureg_032;
+struct option *mmureg = mmureg_032;
+#endif
+\f
+
+const pseudo_typeS md_pseudo_table[]={ /* so far empty */
+  { 0, 0,      0       }
+};
+
+#define IND(x,y)       (((x)<<2)+(y))
+
+/* those are index's to relax groups in md_relax_table 
+   ie it must be multiplied by 4 to point at a group start. Viz IND(x,y)
+   Se function relax_segment in write.c for more info */
+
+#define BRANCH         1
+#define PCREL          2 
+
+/* those are index's to entries in a relax group */
+
+#define BYTE           0
+#define WORD           1
+#define DOUBLE         2
+#define UNDEF           3
+/* Those limits are calculated from the displacement start in memory.
+   The ns32k uses the begining of the instruction as displacement base.
+   This type of displacements could be handled here by moving the limit window
+   up or down. I choose to use an internal displacement base-adjust as there
+   are other routines that must consider this. Also, as we have two various
+   offset-adjusts in the ns32k (acb versus br/brs/jsr/bcond), two set of limits
+   would have had to be used.
+   Now we dont have to think about that. */
+
+
+const relax_typeS md_relax_table[]={
+  { 1,         1,              0,      0                       },
+  { 1,         1,              0,      0                       },
+  { 1,         1,              0,      0                       },
+  { 1,         1,              0,      0                       },
+
+  { (63),      (-64),          1,      IND(BRANCH,WORD)        },
+  { (8192),    (-8192),        2,      IND(BRANCH,DOUBLE)      },
+  { 0,         0,              4,      0                       },
+  { 1,         1,              0,      0                       }
+};
+
+/* Array used to test if mode contains displacements.
+   Value is true if mode contains displacement. */
+
+char disp_test[]={ 0,0,0,0,0,0,0,0,
+                  1,1,1,1,1,1,1,1,
+                  1,1,1,0,0,1,1,0,
+                  1,1,1,1,1,1,1,1 };
+
+/* Array used to calculate max size of displacements */
+
+char disp_size[]={ 4,1,2,0,4 };
+\f
+/* Parses a general operand into an addressingmode struct 
+
+   in:  pointer at operand in ascii form
+        pointer at addr_mode struct for result
+       the level of recursion. (always 0 or 1)
+
+   out: data in addr_mode struct
+ */
+int addr_mode(operand,addr_modeP,recursive_level)
+     char *operand;
+     register addr_modeS *addr_modeP;
+int recursive_level;
+{
+  register char *str;
+  register int i;
+  register int strl;
+  register int mode;
+  int j;
+  mode = DEFAULT;                              /* default */
+  addr_modeP->scaled_mode=0;           /* why not */
+  addr_modeP->scaled_reg=0;            /* if 0, not scaled index */
+  addr_modeP->float_flag=0;
+  addr_modeP->am_size=0;
+  addr_modeP->im_disp=0;
+  addr_modeP->pcrel=0;                 /* not set in this function */
+  addr_modeP->disp_suffix[0]=0;
+  addr_modeP->disp_suffix[1]=0;
+  addr_modeP->disp[0]=NULL;
+  addr_modeP->disp[1]=NULL;
+  str=operand;
+  if (str[0]==0) {return (0);}         /* we don't want this */
+  strl=strlen(str);               
+  switch (str[0]) {
+    /* the following three case statements controls the mode-chars
+       this is the place to ed if you want to change them */
+#ifdef ABSOLUTE_PREFIX
+  case ABSOLUTE_PREFIX:
+    if (str[strl-1]==']') break;
+    addr_modeP->mode=21;               /* absolute */
+    addr_modeP->disp[0]=str+1;
+    return (-1);
+#endif
+#ifdef IMMEDIATE_PREFIX
+  case IMMEDIATE_PREFIX:
+    if (str[strl-1]==']') break;
+    addr_modeP->mode=20;               /* immediate */
+    addr_modeP->disp[0]=str+1;
+    return (-1);
+#endif
+  case '.':
+    if (str[strl-1]!=']') {
+      switch (str[1]) {
+      case'-':case'+':
+        if (str[2]!='\000') {
+         addr_modeP->mode=27;          /* pc-relativ */
+         addr_modeP->disp[0]=str+2;
+         return (-1);
+       }
+      default:
+        as_warn("Invalid syntax in PC-relative addressing mode");
+        return(0);
+      }
+    }
+    break;
+  case'e':
+    if (str[strl-1]!=']') {
+      if((!strncmp(str,"ext(",4)) && strl>7) { /* external */
+       addr_modeP->disp[0]=str+4;
+       i=0;
+       j=2;
+       do {                             /* disp[0]'s termination point */
+         j+=1;
+         if (str[j]=='(') i++;
+         if (str[j]==')') i--;
+       } while (j<strl && i!=0);
+       if (i!=0 || !(str[j+1]=='-' || str[j+1]=='+') ) {
+         as_warn("Invalid syntax in External addressing mode");
+         return(0);
+       }
+       str[j]='\000';                  /* null terminate disp[0] */
+       addr_modeP->disp[1]=str+j+2;
+       addr_modeP->mode=22;
+       return (-1);
+      }
+    }
+  break;
+  default:;
+  }
+  strl=strlen(str);               
+  switch(strl) {
+  case 2:
+    switch (str[0]) {
+    case'f':addr_modeP->float_flag=1;
+    case'r':
+      if (str[1]>='0' && str[1]<'8') {
+       addr_modeP->mode=str[1]-'0';
+       return (-1);
+      }
+    }
+  case 3:
+    if (!strncmp(str,"tos",3)) {
+      addr_modeP->mode=23; /* TopOfStack */
+      return (-1);
+    }
+  default:;
+  }
+  if (strl>4) {
+    if (str[strl-1]==')') {
+      if (str[strl-2]==')') {
+       if (!strncmp(&str[strl-5],"(fp",3)) {
+         mode=16; /* Memory Relative */
+       }
+       if (!strncmp(&str[strl-5],"(sp",3)) {
+         mode=17;
+       }
+       if (!strncmp(&str[strl-5],"(sb",3)) {
+         mode=18;
+       }
+       if (mode!=DEFAULT) {          /* memory relative */
+         addr_modeP->mode=mode;
+         j=strl-5; /* temp for end of disp[0] */
+         i=0;
+         do {
+           strl-=1;
+           if (str[strl]==')') i++;
+           if (str[strl]=='(') i--;
+         } while (strl>-1 && i!=0);
+         if (i!=0) {
+           as_warn("Invalid syntax in Memory Relative addressing mode");
+           return(0);
+         }
+         addr_modeP->disp[1]=str;
+         addr_modeP->disp[0]=str+strl+1;
+         str[j]='\000'; /* null terminate disp[0] */
+         str[strl]='\000'; /* null terminate disp[1] */
+         return (-1);
+       }
+      }
+      switch (str[strl-3]) {
+      case'r':case'R':
+        if (str[strl-2]>='0' && str[strl-2]<'8' && str[strl-4]=='(') {
+         addr_modeP->mode=str[strl-2]-'0'+8;
+         addr_modeP->disp[0]=str;
+         str[strl-4]=0;
+         return (-1); /* reg rel */
+       }
+      default:
+        if (!strncmp(&str[strl-4],"(fp",3)) {
+         mode=24;
+       }
+        if (!strncmp(&str[strl-4],"(sp",3)) {
+         mode=25;
+       }
+        if (!strncmp(&str[strl-4],"(sb",3)) {
+         mode=26;
+       }
+       if (!strncmp(&str[strl-4],"(pc",3)) {
+         mode=27;
+       }
+        if (mode!=DEFAULT) {
+         addr_modeP->mode=mode;
+         addr_modeP->disp[0]=str;
+         str[strl-4]='\0';
+         return (-1); /* memory space */
+       }
+      }
+    }
+     /* no trailing ')' do we have a ']' ? */
+    if (str[strl-1]==']') {
+      switch (str[strl-2]) {
+      case'b':mode=28;break;
+      case'w':mode=29;break;
+      case'd':mode=30;break;
+      case'q':mode=31;break;
+      default:;
+        as_warn("Invalid scaled-indexed mode, use (b,w,d,q)");
+        if (str[strl-3]!=':' || str[strl-6]!='[' ||
+           str[strl-5]=='r' || str[strl-4]<'0' || str[strl-4]>'7') {
+         as_warn("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}");
+       }
+      }  /* scaled index */
+      {
+       if (recursive_level>0) {
+         as_warn("Scaled-indexed addressing mode combined with scaled-index");
+         return(0);
+       }
+       addr_modeP->am_size+=1;         /* scaled index byte */
+       j=str[strl-4]-'0';              /* store temporary */
+       str[strl-6]='\000';             /* nullterminate for recursive call */
+       i=addr_mode(str,addr_modeP,1);
+       if (!i || addr_modeP->mode==20) {
+         as_warn("Invalid or illegal addressing mode combined with scaled-index");
+         return(0);
+       }
+       addr_modeP->scaled_mode=addr_modeP->mode; /* store the inferior mode */
+       addr_modeP->mode=mode;
+       addr_modeP->scaled_reg=j+1;
+       return (-1);
+      }
+    }
+  }
+  addr_modeP->mode = DEFAULT;  /* default to whatever */
+  addr_modeP->disp[0]=str;
+  return (-1);
+}
+\f
+/* ptr points at string
+   addr_modeP points at struct with result
+   This routine calls addr_mode to determine the general addr.mode of
+   the operand. When this is ready it parses the displacements for size
+   specifying suffixes and determines size of immediate mode via ns32k-opcode.
+   Also builds index bytes if needed.
+ */
+int get_addr_mode(ptr,addr_modeP)
+     char *ptr;
+     addr_modeS *addr_modeP;
+{
+  int tmp;
+  addr_mode(ptr,addr_modeP,0);
+  if (addr_modeP->mode == DEFAULT || addr_modeP->scaled_mode == -1) {
+                              /* resolve ambigious operands, this shouldn't
+                                 be necessary if one uses standard NSC operand
+                                 syntax. But the sequent compiler doesn't!!!
+                                 This finds a proper addressinging mode if it
+                                 is implicitly stated. See ns32k-opcode.h */
+    (void)evaluate_expr(&exprP,ptr); /* this call takes time Sigh! */
+    if (addr_modeP->mode == DEFAULT) {
+      if (exprP.X_add_symbol || exprP.X_subtract_symbol) {
+       addr_modeP->mode=desc->default_model; /* we have a label */
+      } else {
+       addr_modeP->mode=desc->default_modec; /* we have a constant */
+      }
+    } else {
+      if (exprP.X_add_symbol || exprP.X_subtract_symbol) {
+       addr_modeP->scaled_mode=desc->default_model;
+      } else {
+       addr_modeP->scaled_mode=desc->default_modec;
+      }
+    }
+    /* must put this mess down in addr_mode to handle the scaled case better */
+  }
+  /* It appears as the sequent compiler wants an absolute when we have a
+     label without @. Constants becomes immediates besides the addr case.
+     Think it does so with local labels too, not optimum, pcrel is better.
+     When I have time I will make gas check this and select pcrel when possible
+     Actually that is trivial.
+     */
+  if (tmp=addr_modeP->scaled_reg) { /* build indexbyte */
+    tmp--; /* remember regnumber comes incremented for flagpurpose */
+    tmp|=addr_modeP->scaled_mode<<3;
+    addr_modeP->index_byte=(char)tmp;
+    addr_modeP->am_size+=1;
+  }
+  if (disp_test[addr_modeP->mode]) { /* there was a displacement, probe for length specifying suffix*/
+    {
+      register char c;
+      register char suffix;
+      register char suffix_sub;
+      register int i;
+      register char *toP;
+      register char *fromP;
+
+      addr_modeP->pcrel=0;
+      if (disp_test[addr_modeP->mode]) { /* there is a displacement */
+       if (addr_modeP->mode==27 || addr_modeP->scaled_mode==27) { /* do we have pcrel. mode */
+         addr_modeP->pcrel=1;
+       }
+       addr_modeP->im_disp=1;
+       for(i=0;i<2;i++) {
+         suffix_sub=suffix=0;
+         if (toP=addr_modeP->disp[i]) { /* suffix of expression, the largest size rules */
+           fromP=toP;
+           while (c = *fromP++) {
+             *toP++=c;
+             if (c==':') {
+               switch (*fromP) {
+               case '\0':
+                 as_warn("Premature end of suffix--Defaulting to d");
+                 suffix=4;
+                 continue;
+               case 'b':suffix_sub=1;break;
+               case 'w':suffix_sub=2;break;
+               case 'd':suffix_sub=4;break;
+               default:
+                 as_warn("Bad suffix after ':' use {b|w|d} Defaulting to d");
+                 suffix=4;
+               }
+               fromP++;
+               toP--; /* So we write over the ':' */
+               if (suffix<suffix_sub) suffix=suffix_sub;
+             }
+           }
+           *toP='\0'; /* terminate properly */
+           addr_modeP->disp_suffix[i]=suffix;
+           addr_modeP->am_size+=suffix ? suffix : 4;
+         }
+       }
+      }
+    }
+  } else {
+    if (addr_modeP->mode==20) { /* look in ns32k_opcode for size */
+      addr_modeP->disp_suffix[0]=addr_modeP->am_size=desc->im_size;
+      addr_modeP->im_disp=0;
+    }
+  }
+  return addr_modeP->mode;
+}
+
+
+/* read an optionlist */
+void optlist(str,optionP,default_map)
+     char *str;                         /* the string to extract options from */
+     struct option *optionP;    /* how to search the string */
+     unsigned long *default_map; /* default pattern and output */
+{
+  register int i,j,k,strlen1,strlen2;
+  register char *patternP,*strP;
+  strlen1=strlen(str);
+  if (strlen1<1) { 
+    as_fatal("Very short instr to option, ie you can't do it on a NULLstr");
+  }
+  for (i=0;optionP[i].pattern!=0;i++) {
+    strlen2=strlen(optionP[i].pattern);
+    for (j=0;j<strlen1;j++) {
+      patternP=optionP[i].pattern;
+      strP = &str[j];
+      for (k=0;k<strlen2;k++) {
+       if (*(strP++)!=*(patternP++)) break;
+      }
+      if (k==strlen2) { /* match */
+       *default_map|=optionP[i].or;
+       *default_map&=optionP[i].and;
+      }
+    }
+  }
+}
+/* search struct for symbols 
+   This function is used to get the short integer form of reg names
+   in the instructions lmr, smr, lpr, spr
+   return true if str is found in list */
+
+int list_search(str,optionP,default_map)
+     char *str;                         /* the string to match */
+     struct option *optionP;    /* list to search */
+     unsigned long *default_map; /* default pattern and output */
+{
+  register int i;
+  for (i=0;optionP[i].pattern!=0;i++) {
+    if (!strncmp(optionP[i].pattern,str,20)) { /* use strncmp to be safe */
+      *default_map|=optionP[i].or;
+      *default_map&=optionP[i].and;
+      return -1;
+    }
+  }
+  as_warn("No such entry in list. (cpu/mmu register)");
+  return 0;
+}
+segT evaluate_expr(resultP,ptr)
+expressionS *resultP;
+char *ptr;
+{
+  register char *tmp_line;
+  register segT segment;
+  tmp_line=input_line_pointer;
+  input_line_pointer=ptr;
+  segment=expression(&exprP);
+  input_line_pointer=tmp_line;
+  return (segment);
+}
+\f
+/* Convert operands to iif-format and adds bitfields to the opcode.
+   Operands are parsed in such an order that the opcode is updated from
+   its most significant bit, that is when the operand need to alter the
+   opcode.
+   Be carefull not to put to objects in the same iif-slot.
+   */
+
+encode_operand(argc,argv,operandsP,suffixP,im_size,opcode_bit_ptr)
+     int argc;
+     char **argv;
+     char *operandsP;
+     char *suffixP;
+     char im_size;
+     char opcode_bit_ptr;
+{
+  register int i,j;
+  int pcrel,tmp,b,loop,pcrel_adjust;
+  for(loop=0;loop<argc;loop++) {
+    i=operandsP[loop<<1]-'1'; /* what operand are we supposed to work on */
+    if (i>3) as_fatal("Internal error check ns32k-opcode.h");
+    pcrel=0;
+    pcrel_adjust=0;
+    tmp=0;
+    switch (operandsP[(loop<<1)+1]) {
+    case 'f':  /* operand of sfsr turns out to be a nasty specialcase */
+      opcode_bit_ptr-=5;
+    case 'F':          /* 32 bit float general form */
+    case 'L':          /* 64 bit float */
+    case 'Q':          /* quad-word    */
+    case 'B':          /* byte  */
+    case 'W':          /* word  */
+    case 'D':          /* double-word  */
+    case 'A':          /* double-word  gen-address-form ie no regs allowed */
+      get_addr_mode(argv[i],&addr_modeP);
+      iif.instr_size+=addr_modeP.am_size;
+      if (opcode_bit_ptr==desc->opcode_size) b=4; else b=6;
+      for (j=b;j<(b+2);j++) { 
+       if (addr_modeP.disp[j-b]) { 
+         IIF(j,
+             2,
+             addr_modeP.disp_suffix[j-b],
+             (unsigned long)addr_modeP.disp[j-b],
+             0,
+             addr_modeP.pcrel,
+             iif.instr_size-addr_modeP.am_size, /* this aint used (now) */
+             addr_modeP.im_disp,
+             IND(BRANCH,BYTE),
+             NULL,
+             addr_modeP.scaled_reg ? addr_modeP.scaled_mode:addr_modeP.mode,
+             0);
+       }
+      }
+      opcode_bit_ptr-=5;
+      iif.iifP[1].object|=((long)addr_modeP.mode)<<opcode_bit_ptr;
+      if (addr_modeP.scaled_reg) { 
+       j=b/2;
+       IIF(j,1,1, (unsigned long)addr_modeP.index_byte,0,0,0,0,0, NULL,-1,0);
+      }
+      break;
+    case 'b':          /* multiple instruction disp */
+      freeptr++;       /* OVE:this is an useful hack */
+      tmp=(int)sprintf(freeptr,"((%s-1)*%d)\000",argv[i],desc->im_size);
+      argv[i]=freeptr;
+      freeptr=(char*)tmp;
+      pcrel-=1; /* make pcrel 0 inspite of what case 'p': wants */
+      /* fall thru */
+    case 'p':          /* displacement - pc relative addressing */
+      pcrel+=1;
+      /* fall thru */
+    case 'd':                                  /* displacement */
+      iif.instr_size+=suffixP[i] ? suffixP[i] : 4;
+      IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0,
+         pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,0);
+      break;
+    case 'H': /* sequent-hack: the linker wants a bit set when bsr */
+      pcrel=1;
+      iif.instr_size+=suffixP[i] ? suffixP[i] : 4;
+      IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0,
+         pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,1);break;
+    case 'q':                                  /* quick */
+      opcode_bit_ptr-=4;
+      IIF(11,2,42,(unsigned long)argv[i],0,0,0,0,0,
+         bit_fix_new(4,opcode_bit_ptr,-8,7,0,1,0),-1,0);
+      break;
+    case 'r':                          /* register number (3 bits) */
+      list_search(argv[i],opt6,&tmp);
+      opcode_bit_ptr-=3;
+      iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+      break;
+    case 'O':                          /* setcfg instruction optionslist */
+      optlist(argv[i],opt3,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<15;
+      break;
+    case 'C':                          /* cinv instruction optionslist */
+      optlist(argv[i],opt4,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<15;/*insert the regtype in opcode */
+      break;
+    case 'S':                          /* stringinstruction optionslist */
+      optlist(argv[i],opt5,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<15;
+      break;
+    case 'u':case 'U':                         /* registerlist */
+      IIF(10,1,1,0,0,0,0,0,0,NULL,-1,0);
+      switch (operandsP[(i<<1)+1]) {
+      case 'u':                                /* restore, exit */
+       optlist(argv[i],opt1,&iif.iifP[10].object);
+       break;
+      case 'U':                                        /* save,enter */
+       optlist(argv[i],opt2,&iif.iifP[10].object);
+       break;
+      }
+      iif.instr_size+=1;
+      break;
+    case 'M':                                  /* mmu register */
+      list_search(argv[i],mmureg,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+      break;
+    case 'P':                                  /* cpu register  */
+      list_search(argv[i],cpureg,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+      break;
+    case 'g': /* inss exts */
+      iif.instr_size+=1; /* 1 byte is allocated after the opcode */
+      IIF(10,2,1,
+         (unsigned long)argv[i], /* i always 2 here */
+         0,0,0,0,0,
+         bit_fix_new(3,5,0,7,0,0,0), /* a bit_fix is targeted to the byte */
+         -1,0);
+    case 'G':
+      IIF(11,2,42,
+         (unsigned long)argv[i], /* i always 3 here */
+         0,0,0,0,0,
+         bit_fix_new(5,0,1,32,-1,0,-1),-1,0);
+      break;
+    case 'i':
+      iif.instr_size+=1;
+      b=2+i;  /* put the extension byte after opcode */
+      IIF(b,2,1,0,0,0,0,0,0,0,-1,0);
+    default:
+      as_fatal("Bad opcode-table-option, check in file ns32k-opcode.h");
+    }
+  }
+}
+\f
+/* in:  instruction line
+   out: internal structure of instruction
+        that has been prepared for direct conversion to fragment(s) and
+       fixes in a systematical fashion
+       Return-value = recursive_level
+*/
+/* build iif of one assembly text line */
+int parse(line,recursive_level)
+     char *line;
+     int recursive_level;
+{
+  register char                        *lineptr,c,suffix_separator;
+  register int                 i;
+  int                          argc,arg_type;
+  char                         sqr,sep;
+  char suffix[MAX_ARGS],*argv[MAX_ARGS];/* no more than 4 operands */
+  if (recursive_level<=0) { /* called from md_assemble */
+    for (lineptr=line;(*lineptr)!='\0' && (*lineptr)!=' ';lineptr++); 
+    c = *lineptr;
+    *lineptr='\0';
+    if (!(desc=(struct ns32k_opcode*)hash_find(inst_hash_handle,line))) {
+      as_fatal("No such opcode");
+    }
+    *lineptr=c;
+  } else {
+    lineptr=line;
+  }
+  argc=0;
+  if (*desc->operands) {
+    if (*lineptr++!='\0') {
+      sqr='[';
+      sep=',';
+      while (*lineptr!='\0') {
+       if (desc->operands[argc<<1]) {
+         suffix[argc]=0;
+         arg_type=desc->operands[(argc<<1)+1];
+         switch (arg_type) {
+         case 'd': case 'b': case 'p': case 'H':  /* the operand is supposed to be a displacement */
+           /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h */
+           suffix_separator=':';
+           break;
+         default:
+           suffix_separator='\255'; /* if this char occurs we loose */
+         }
+         suffix[argc]=0; /* 0 when no ':' is encountered */
+         argv[argc]=freeptr;
+         *freeptr='\0';
+         while ((c = *lineptr)!='\0' && c!=sep) {
+           if (c==sqr) {
+             if (sqr=='[') {
+               sqr=']';sep='\0';
+             } else {
+               sqr='[';sep=',';
+             }
+           }
+           if (c==suffix_separator) { /* ':' - label/suffix separator */
+             switch (lineptr[1]) {
+             case 'b':suffix[argc]=1;break;
+             case 'w':suffix[argc]=2;break;
+             case 'd':suffix[argc]=4;break;
+             default: as_warn("Bad suffix, defaulting to d");
+               suffix[argc]=4;
+               if (lineptr[1]=='\0' || lineptr[1]==sep) {
+                 lineptr+=1;
+                 continue;
+               }
+             }
+             lineptr+=2;
+             continue;
+           }
+           *freeptr++=c;
+           lineptr++;
+         }
+         *freeptr++='\0';
+         argc+=1;
+         if (*lineptr=='\0') continue;
+         lineptr+=1;
+       } else {
+         as_fatal("Too many operands passed to instruction");
+       }
+      }
+    }
+  }
+  if (argc!=strlen(desc->operands)/2) {
+    if (strlen(desc->default_args)) { /* we can apply default, dont goof */
+      if (parse(desc->default_args,1)!=1) { /* check error in default */
+       as_fatal("Wrong numbers of operands in default, check ns32k-opcodes.h");
+      }
+    } else {
+      as_fatal("Wrong number of operands");
+    }
+
+  }
+  for (i=0;i<IIF_ENTRIES;i++) {
+    iif.iifP[i].type=0; /* mark all entries as void*/
+  }
+
+    /* build opcode iif-entry */
+  iif.instr_size=desc->opcode_size/8;
+  IIF(1,1,iif.instr_size,desc->opcode_seed,0,0,0,0,0,0,-1,0);
+
+    /* this call encodes operands to iif format */
+  if (argc) {
+    encode_operand(argc,
+                  argv,
+                  &desc->operands[0],
+                  &suffix[0],
+                  desc->im_size,
+                  desc->opcode_size);
+  }
+  return recursive_level;
+}
+
+\f
+  /* Convert iif to fragments.
+     From this point we start to dribble with functions in other files than
+     this one.(Except hash.c) So, if it's possible to make an iif for an other
+     CPU, you don't need to know what frags, relax, obstacks, etc is in order
+     to port this assembler. You only need to know if it's possible to reduce
+     your cpu-instruction to iif-format (takes some work) and adopt the other
+     md_? parts according to given instructions
+     Note that iif was invented for the clean ns32k`s architecure.
+     */
+convert_iif()
+{
+  register int                 i,j;
+  fragS                        *inst_frag;
+  char                         *inst_offset,*inst_opcode;
+  char                         *memP;
+  segT                         segment;
+  int                          l,k;
+  register int rem_size; /* count the remaining bytes of instruction */
+  register char type;
+  register char size = 0;
+  int  size_so_far=0; /* used to calculate pcrel_adjust */
+
+    rem_size=iif.instr_size;
+    memP=frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */
+    inst_opcode=memP;
+    inst_offset=(char*)(memP-frag_now->fr_literal);
+    inst_frag=frag_now;
+    for (i=0;i<IIF_ENTRIES;i++) {
+      if (type=iif.iifP[i].type) {                     /* the object exist, so handle it */
+       switch (size=iif.iifP[i].size) {
+       case 42: size=0; /* it's a bitfix that operates on an existing object*/
+         if (iif.iifP[i].bit_fixP->fx_bit_base) { /* expand fx_bit_base to point at opcode */
+           iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode;
+         }
+       case 8: /* bignum or doublefloat */
+         bzero (memP,8);
+       case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */
+         j=(unsigned long)iif.iifP[i].bit_fixP;
+         switch (type) {
+         case 1:                               /* the object is pure binary */
+           if (j || iif.iifP[i].pcrel) {
+             fix_new_ns32k(frag_now,
+                           (long)(memP-frag_now->fr_literal),
+                           size,
+                           0,
+                           0,
+                           iif.iifP[i].object,
+                           iif.iifP[i].pcrel,
+                           (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+                           iif.iifP[i].im_disp,
+                           j,
+                           iif.iifP[i].bsr); /* sequent hack */
+           } else {                    /* good, just put them bytes out */
+             switch (iif.iifP[i].im_disp) {
+             case 0:
+               md_number_to_chars(memP,iif.iifP[i].object,size);break;
+             case 1:
+               md_number_to_disp(memP,iif.iifP[i].object,size);break;
+             default: as_fatal("iif convert internal pcrel/binary");
+             }
+           }
+           memP+=size;
+           rem_size-=size;
+           break;
+         case 2:       /* the object is a pointer at an expression, so unpack
+                          it, note that bignums may result from the expression
+                        */
+           if ((segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object))==SEG_BIG || size==8) {
+             if ((k=exprP.X_add_number)>0) { /* we have a bignum ie a quad */
+               /* this can only happens in a long suffixed instruction */
+               bzero(memP,size); /* size normally is 8 */
+               if (k*2>size) as_warn("Bignum too big for long");
+               if (k==3) memP+=2;
+               for (l=0;k>0;k--,l+=2) {
+                 md_number_to_chars(memP+l,generic_bignum[l>>1],sizeof(LITTLENUM_TYPE));
+               }
+             } else { /* flonum */
+               LITTLENUM_TYPE words[4];
+
+               switch(size) {
+               case 4:
+                 gen_to_words(words,2,8);
+                 md_number_to_imm(memP                       ,(long)words[0],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+sizeof(LITTLENUM_TYPE),(long)words[1],sizeof(LITTLENUM_TYPE));
+                 break;
+               case 8:
+                 gen_to_words(words,4,11);
+                 md_number_to_imm(memP                         ,(long)words[0],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+sizeof(LITTLENUM_TYPE)  ,(long)words[1],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+2*sizeof(LITTLENUM_TYPE),(long)words[2],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+3*sizeof(LITTLENUM_TYPE),(long)words[3],sizeof(LITTLENUM_TYPE));
+                 break;
+               }
+             }
+           memP+=size;
+           rem_size-=size;
+           break;
+           }
+           if (j ||
+               exprP.X_add_symbol ||
+               exprP.X_subtract_symbol ||
+               iif.iifP[i].pcrel) {            /* fixit */
+             /* the expression was undefined due to an undefined label */
+             /* create a fix so we can fix the object later */
+             exprP.X_add_number+=iif.iifP[i].object_adjust;
+             fix_new_ns32k(frag_now,
+                           (long)(memP-frag_now->fr_literal),
+                           size,
+                           exprP.X_add_symbol,
+                           exprP.X_subtract_symbol,
+                           exprP.X_add_number,
+                           iif.iifP[i].pcrel,
+                           (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+                           iif.iifP[i].im_disp,
+                           j,
+                           iif.iifP[i].bsr); /* sequent hack */
+             
+           } else {                    /* good, just put them bytes out */
+             switch (iif.iifP[i].im_disp) {
+             case 0:
+               md_number_to_imm(memP,exprP.X_add_number,size);break;
+             case 1:
+               md_number_to_disp(memP,exprP.X_add_number,size);break;
+             default: as_fatal("iif convert internal pcrel/pointer");
+             }
+           }
+           memP+=size;
+           rem_size-=size;
+           break;
+         default: as_fatal("Internal logic error in iif.iifP[n].type");
+         }
+         break;
+       case 0:          /* To bad, the object may be undefined as far as its final
+                           nsize in object memory is concerned. The size of the object
+                           in objectmemory is not explicitly given.
+                           If the object is defined its length can be determined and
+                           a fix can replace the frag.
+                           */
+         {
+           int temp;
+           segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object);
+           if ((exprP.X_add_symbol || exprP.X_subtract_symbol) &&
+               !iif.iifP[i].pcrel) { /* OVE: hack, clamp to 4 bytes */
+             size=4; /* we dont wan't to frag this, use 4 so it reaches */
+             fix_new_ns32k(frag_now,
+                           (long)(memP-frag_now->fr_literal),
+                           size,
+                           exprP.X_add_symbol,
+                           exprP.X_subtract_symbol,
+                           exprP.X_add_number,
+                           0, /* never iif.iifP[i].pcrel, */
+                           (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+                           1, /* always iif.iifP[i].im_disp, */
+                           0,0);
+             memP+=size;
+             rem_size-=4;
+             break; /* exit this absolute hack */
+           }
+
+           if (exprP.X_add_symbol || exprP.X_subtract_symbol) { /* frag it */
+             if (exprP.X_subtract_symbol) { /* We cant relax this case */
+               as_fatal("Can't relax difference");
+             }
+             else {
+               /* at this stage we must undo some of the effect caused
+                  by frag_more, ie we must make sure that frag_var causes
+                  frag_new to creat a valid fix-size in the frag it`s closing
+                  */
+               temp = -(rem_size-4);
+               obstack_blank_fast(&frags,temp);
+                 /* we rewind none, some or all of the requested size we
+                    requested by the first frag_more for this iif chunk.
+                    Note: that we allocate 4 bytes to an object we NOT YET 
+                    know the size of, thus rem_size-4.
+                    */
+               (void)frag_variant(rs_machine_dependent,
+                                  4,
+                                  0,
+                                  IND(BRANCH,UNDEF), /* expecting the worst */
+                                  exprP.X_add_symbol,
+                                  exprP.X_add_number,
+                                  (char*)inst_opcode,
+                                  (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/
+                                  iif.iifP[i].bsr); /* sequent linker hack */
+               rem_size-=4;
+               if (rem_size>0) {
+                 memP=frag_more(rem_size);
+               }
+             }
+           }
+           else {/* Double work, this is done in md_number_to_disp */
+             exprP.X_add_number;
+             if (-64<=exprP.X_add_number && exprP.X_add_number<=63) {
+               size=1;
+             } else {
+               if (-8192<=exprP.X_add_number && exprP.X_add_number<=8191) {
+                 size=2;
+               } else {
+                 if (-0x1f000000<=exprP.X_add_number &&
+                     exprP.X_add_number<=0x1fffffff)
+                 /* if (-0x40000000<=exprP.X_add_number &&
+                     exprP.X_add_number<=0x3fffffff) */
+                 {
+                   size=4;
+                 } else {
+                   as_warn("Displacement to large for :d");
+                   size=4;
+                 }
+               }
+             }
+             /* rewind the bytes not used */
+             temp = -(4-size);
+             md_number_to_disp(memP,exprP.X_add_number,size);
+             obstack_blank_fast(&frags,temp);
+             memP+=size;
+             rem_size-=4; /* we allocated this amount */
+           }
+         }
+         break;
+       default:
+         as_fatal("Internal logic error in iif.iifP[].type");
+       }
+       size_so_far+=size;
+       size=0;
+      }
+    }
+}
+\f
+void md_assemble(line)
+char *line;
+{
+  freeptr=freeptr_static;
+  parse(line,0); /* explode line to more fix form in iif */
+  convert_iif(); /* convert iif to frags, fix's etc */
+#ifdef SHOW_NUM
+  printf(" \t\t\t%s\n",line);
+#endif
+}
+
+
+void md_begin()
+{
+  /* build a hashtable of the instructions */
+  register struct ns32k_opcode *ptr;
+  register char *stat;
+  inst_hash_handle=hash_new();
+  for (ptr=ns32k_opcodes;ptr<endop;ptr++) {
+    if (*(stat=hash_insert(inst_hash_handle,ptr->name,(char*)ptr))) {
+       as_fatal("Can't hash %s: %s",ptr->name,stat); /*fatal*/
+      exit(0);
+    }
+  }
+  freeptr_static=(char*)malloc(PRIVATE_SIZE); /* some private space please! */
+}
+
+
+void
+md_end()
+{
+  free(freeptr_static);
+}
+
+/* Must be equal to MAX_PRECISON in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+/* Turn the string pointed to by litP into a floating point constant of type
+   type, and emit the appropriate bytes.  The number of LITTLENUMS emitted
+   is stored in *sizeP .  An error message is returned, or NULL on OK.
+ */
+char *
+md_atof(type,litP,sizeP)
+char type;
+char *litP;
+int *sizeP;
+{
+       int     prec;
+       LITTLENUM_TYPE words[MAX_LITTLENUMS];
+       LITTLENUM_TYPE *wordP;
+       char    *t;
+       char    *atof_ieee();
+
+       switch(type) {
+       case 'f':
+               prec = 2;
+               break;
+
+       case 'd':
+               prec = 4;
+               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);
+       for(wordP=words+prec;prec--;) {
+               md_number_to_chars(litP,(long)(*--wordP),sizeof(LITTLENUM_TYPE));
+               litP+=sizeof(LITTLENUM_TYPE);
+       }
+       return "";      /* Someone should teach Dean about null pointers */
+}
+\f
+/* Convert number to chars in correct order */
+
+void
+md_number_to_chars (buf, value, nbytes)
+     char      *buf;
+     long int  value;
+     int       nbytes;
+{
+  while (nbytes--)
+    {
+#ifdef SHOW_NUM
+      printf("%x ",value & 0xff);
+#endif
+      *buf++ = value;          /* Lint wants & MASK_CHAR. */
+      value >>= BITS_PER_CHAR;
+    }
+}
+/* Convert number to chars in correct order */
+
+
+
+/* This is a variant of md_numbers_to_chars. The reason for its' existence
+   is the fact that ns32k uses Huffman coded displacements. This implies
+   that the bit order is reversed in displacements and that they are prefixed
+   with a size-tag.
+
+   binary: msb -> lsb  0xxxxxxx                                byte
+                       10xxxxxx xxxxxxxx                       word
+                       11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx     double word
+          
+   This must be taken care of and we do it here!                 
+ */
+void md_number_to_disp(buf,val,n)
+     char      *buf;
+     long      val;
+     char       n;
+{ 
+  switch(n) {
+  case 1:
+    if (val < -64 || val > 63)
+      as_warn("Byte displacement out of range.  line number not valid");
+    val&=0x7f;
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 2:
+    if (val < -8192 || val > 8191)
+      as_warn("Word displacement out of range.  line number not valid");
+    val&=0x3fff;
+    val|=0x8000;
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 4:
+    if (val < -0x1f000000 || val >= 0x20000000)
+    /* if (val < -0x20000000 || val >= 0x20000000) */
+      as_warn("Double word displacement out of range");
+    val|=0xc0000000;
+#ifdef SHOW_NUM
+               printf("%x ",val>>24 & 0xff);
+#endif
+    *buf++=(val>>24);
+#ifdef SHOW_NUM
+               printf("%x ",val>>16 & 0xff);
+#endif
+    *buf++=(val>>16);
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  default:
+    as_fatal("Internal logic error");
+  }
+}
+void md_number_to_imm(buf,val,n)
+     char      *buf;
+     long      val;
+     char       n;
+{ 
+  switch(n) {
+  case 1:
+#ifdef SHOW_NUM
+    printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 2:
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 4:
+#ifdef SHOW_NUM
+               printf("%x ",val>>24 & 0xff);
+#endif
+    *buf++=(val>>24);
+#ifdef SHOW_NUM
+               printf("%x ",val>>16 & 0xff);
+#endif
+    *buf++=(val>>16);
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  default:
+    as_fatal("Internal logic error");
+  }
+}
+/* the bit-field entries in the relocation_info struct plays hell 
+   with the byte-order problems of cross-assembly.  So as a hack,
+   I added this mach. dependent ri twiddler.  Ugly, but it gets
+   you there. -KWK */
+/* OVE: on a ns32k the twiddling continues at an even deeper level
+   here we have to distinguish between displacements and immediates.
+
+   The sequent has a bit for this. It also has a bit for relocobjects that
+   points at the target for a bsr (BranchSubRoutine) !?!?!?!
+
+   Using [] is importable but fast!! still, its rather funny :-)
+   This md_ri.... is tailored for sequent.
+   */
+
+void md_ri_to_chars(ri_p, ri)
+     struct relocation_info *ri_p, ri;
+{      
+  if (ri.r_bsr) {ri.r_pcrel=0;} /* sequent seems to want this */
+  md_number_to_chars((char*)ri_p, ri.r_address, sizeof(ri.r_address));
+  md_number_to_chars((char*)ri_p+4,
+                    (long)(ri.r_symbolnum       ) |
+                    (long)(ri.r_pcrel     << 24 ) |
+                    (long)(ri.r_length    << 25 ) |
+                    (long)(ri.r_extern    << 27 ) |
+                    (long)(ri.r_bsr       << 28 ) |
+                    (long)(ri.r_disp      << 29 ),
+                    4);
+  /* the first and second md_number_to_chars never overlaps (32bit cpu case) */
+}
+\f
+/* fast bitfiddling support */
+/* mask used to zero bitfield before oring in the true field */
+
+static unsigned long l_mask[]={        0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
+                               0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
+                               0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
+                               0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
+                               0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
+                               0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
+                               0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
+                               0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
+                               };
+static unsigned long r_mask[]={        0x00000000, 0x00000001, 0x00000003, 0x00000007,
+                               0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+                               0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+                               0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+                               0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+                               0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+                               0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+                               0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+                               };
+#define MASK_BITS 31
+/* Insert bitfield described by field_ptr and val at buf
+   This routine is written for modification of the first 4 bytes pointed
+   to by buf, to yield speed.
+   The ifdef stuff is for selection between a ns32k-dependent routine
+   and a general version. (My advice: use the general version!)
+ */
+
+void md_number_to_field(buf,val,field_ptr)
+     register char     *buf;
+     register long     val;
+     register bit_fixS  *field_ptr;
+{ 
+  register unsigned long object;
+  register unsigned long mask;
+/* define ENDIAN on a ns32k machine */
+#ifdef ENDIAN
+  register unsigned long *mem_ptr;
+#else
+  register char *mem_ptr;
+#endif
+  if (field_ptr->fx_bit_min<=val && val<=field_ptr->fx_bit_max) {
+#ifdef ENDIAN
+    if (field_ptr->fx_bit_base) { /* override buf */
+      mem_ptr=(unsigned long*)field_ptr->fx_bit_base;
+    } else {
+      mem_ptr=(unsigned long*)buf;
+    }
+#else
+    if (field_ptr->fx_bit_base) { /* override buf */
+      mem_ptr=(char*)field_ptr->fx_bit_base;
+    } else {
+      mem_ptr=buf;
+    }
+#endif
+    mem_ptr+=field_ptr->fx_bit_base_adj;
+#ifdef ENDIAN  /* we have a nice ns32k machine with lowbyte at low-physical mem */
+    object = *mem_ptr; /* get some bytes */
+#else /* OVE Goof! the machine is a m68k or dito */
+      /* That takes more byte fiddling */
+    object=0;
+    object|=mem_ptr[3] & 0xff;
+    object<<=8;
+    object|=mem_ptr[2] & 0xff;
+    object<<=8;
+    object|=mem_ptr[1] & 0xff;
+    object<<=8;
+    object|=mem_ptr[0] & 0xff;
+#endif
+    mask=0;
+    mask|=(r_mask[field_ptr->fx_bit_offset]);
+    mask|=(l_mask[field_ptr->fx_bit_offset+field_ptr->fx_bit_size]);
+    object&=mask;
+    val+=field_ptr->fx_bit_add;
+    object|=((val<<field_ptr->fx_bit_offset) & (mask ^ 0xffffffff));
+#ifdef ENDIAN
+    *mem_ptr=object;
+#else
+    mem_ptr[0]=(char)object;
+    object>>=8;
+    mem_ptr[1]=(char)object;
+    object>>=8;
+    mem_ptr[2]=(char)object;
+    object>>=8;
+    mem_ptr[3]=(char)object;
+#endif
+  } else {
+    as_warn("Bit field out of range");
+  }
+}
+\f
+/* Convert a relaxed displacement to dito in final output */
+
+void
+  md_convert_frag(fragP)
+register fragS *fragP;
+{
+  long disp;
+  long ext;
+
+  /* Address in gas core of the place to store the displacement.  */
+  register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
+  /* Address in object code of the displacement.  */
+  register int object_address = fragP -> fr_fix + fragP -> fr_address;
+
+  know(fragP->fr_symbol);
+
+  /* The displacement of the address, from current location.  */
+  disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address;
+  disp+= fragP->fr_pcrel_adjust;
+
+  switch(fragP->fr_subtype) {
+  case IND(BRANCH,BYTE):
+    ext=1;
+    break;
+  case IND(BRANCH,WORD):
+    ext=2;
+    break;
+  case IND(BRANCH,DOUBLE):
+    ext=4;
+    break;
+  }
+  if(ext) {
+    md_number_to_disp(buffer_address,(long)disp,(int)ext);
+    fragP->fr_fix+=ext;
+  }
+}
+
+
+
+/* This function returns the estimated size a variable object will occupy,
+   one can say that we tries to guess the size of the objects before we
+   actually know it */
+   
+md_estimate_size_before_relax(fragP,segtype)
+     register fragS *fragP;
+{
+  int  old_fix;
+  old_fix=fragP->fr_fix;
+  switch(fragP->fr_subtype) {
+  case IND(BRANCH,UNDEF):
+    if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
+      /* the symbol has been assigned a value */
+      fragP->fr_subtype=IND(BRANCH,BYTE);
+    } else {
+      /* we don't relax symbols defined in an other segment
+         the thing to do is to assume the object will occupy 4 bytes */
+      fix_new_ns32k(fragP,
+                   (int)(fragP->fr_fix),
+                   4,
+                   fragP->fr_symbol,
+                   (symbolS *)0,
+                   fragP->fr_offset,
+                   1,
+                   fragP->fr_pcrel_adjust,
+                   1,
+                   0,
+                   fragP->fr_bsr); /*sequent hack */
+      fragP->fr_fix+=4;
+      /* fragP->fr_opcode[1]=0xff; */
+      frag_wane(fragP);
+      break;
+    }
+  case IND(BRANCH,BYTE):
+    fragP->fr_var+=1;
+    break;
+  default:
+    break;
+  }
+  return fragP->fr_var + fragP->fr_fix - old_fix;
+}
+
+int md_short_jump_size = 3;
+int md_long_jump_size  = 5;
+
+void
+md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char   *ptr;
+long   from_addr,
+       to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       long offset;
+
+       offset = to_addr - from_addr;
+       md_number_to_chars(ptr, (long)0xEA  ,1);
+       md_number_to_disp(ptr+1,(long)offset,2);
+}
+
+void
+md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char   *ptr;
+long   from_addr,
+       to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       long offset;
+
+       offset= to_addr - from_addr;
+       md_number_to_chars(ptr, (long)0xEA,  2);
+       md_number_to_disp(ptr+2,(long)offset,4);
+}
+\f
+/* JF this is a new function to parse machine-dep options */
+int
+md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+       switch(**argP) {
+       case 'm':
+         (*argP)++;
+
+         if(!strcmp(*argP,"32032")) {
+           cpureg = cpureg_032;
+           mmureg = mmureg_032;
+         } else if(!strcmp(*argP, "32532")) {
+           cpureg = cpureg_532;
+           mmureg = mmureg_532;
+         } else
+           as_warn("Unknown -m option ignored");
+
+         while(**argP)
+           (*argP)++;
+         break;
+
+       default:
+         return 0;
+       }
+       return 1;
+}
+\f
+/*
+ *                     bit_fix_new()
+ *
+ * Create a bit_fixS in obstack 'notes'.
+ * This struct is used to profile the normal fix. If the bit_fixP is a
+ * valid pointer (not NULL) the bit_fix data will be used to format the fix.
+ */
+bit_fixS *
+bit_fix_new (size,offset,min,max,add,base_type,base_adj)
+     char      size;           /* Length of bitfield           */
+     char      offset;         /* Bit offset to bitfield       */
+     long      base_type;      /* 0 or 1, if 1 it's exploded to opcode ptr */
+     long      base_adj;
+     long      min;            /* Signextended min for bitfield */
+     long      max;            /* Signextended max for bitfield */
+     long      add;            /* Add mask, used for huffman prefix */
+{
+  register bit_fixS *  bit_fixP;
+
+  bit_fixP = (bit_fixS *)obstack_alloc(&notes,sizeof(bit_fixS));
+
+  bit_fixP -> fx_bit_size      = size;
+  bit_fixP -> fx_bit_offset    = offset;
+  bit_fixP -> fx_bit_base      = base_type;
+  bit_fixP -> fx_bit_base_adj  = base_adj;
+  bit_fixP -> fx_bit_max       = max;
+  bit_fixP -> fx_bit_min       = min;
+  bit_fixP -> fx_bit_add       = add;
+
+  return bit_fixP;
+}
+
+void
+fix_new_ns32k (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+        pcrel_adjust, im_disp, bit_fixP, bsr)
+     fragS *   frag;           /* Which frag? */
+     int       where;          /* Where in that frag? */
+     short int size;           /* 1, 2  or 4 usually. */
+     symbolS * add_symbol;     /* X_add_symbol. */
+     symbolS * sub_symbol;     /* X_subtract_symbol. */
+     long int  offset;         /* X_add_number. */
+     int       pcrel;          /* TRUE if PC-relative relocation. */
+     char      pcrel_adjust;   /* not zero if adjustment of pcrel offset is needed */
+     char      im_disp;        /* true if the value to write is a displacement */
+     bit_fixS *bit_fixP;       /* pointer at struct of bit_fix's, ignored if NULL */
+     char      bsr;            /* sequent-linker-hack: 1 when relocobject is a bsr */
+     
+{
+  register fixS *      fixP;
+
+  fixP = (fixS *)obstack_alloc(&notes,sizeof(fixS));
+  fixP -> fx_frag              = frag;
+  fixP -> fx_where             = where;
+  fixP -> fx_size              = size;
+  fixP -> fx_addsy             = add_symbol;
+  fixP -> fx_subsy             = sub_symbol;
+  fixP -> fx_offset            = offset;
+  fixP -> fx_pcrel             = pcrel;
+  fixP -> fx_pcrel_adjust      = pcrel_adjust;
+  fixP -> fx_im_disp           = im_disp;
+  fixP -> fx_bit_fixP          = bit_fixP;
+  fixP -> fx_bsr               = bsr;
+  fixP -> fx_next              = * seg_fix_rootP;
+
+  * seg_fix_rootP = fixP;
+}