aboutsummaryrefslogtreecommitdiffstats
path: root/as1750.c
diff options
context:
space:
mode:
Diffstat (limited to 'as1750.c')
-rw-r--r--as1750.c1295
1 files changed, 1295 insertions, 0 deletions
diff --git a/as1750.c b/as1750.c
new file mode 100644
index 0000000..13301b4
--- /dev/null
+++ b/as1750.c
@@ -0,0 +1,1295 @@
+/***************************************************************************/
+/* */
+/* Project : as1750 -- Mil-Std-1750 Assembler and Linker */
+/* */
+/* Component : as1750.c -- 1750 instruction assembly */
+/* */
+/* Copyright : (C) Daimler-Benz Aerospace AG, 1994-1997 */
+/* */
+/* Author : Oliver M. Kellogg, Dornier Satellite Systems, */
+/* Dept. RST13, D-81663 Munich, Germany. */
+/* Contact : oliver.kellogg@space.otn.dasa.de */
+/* */
+/* Disclaimer: */
+/* */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program 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 this program; if not, write to the Free Software */
+/* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/***************************************************************************/
+
+#ifdef AS1750
+#include "common.h"
+#include "utils.h"
+#else /* ASL */
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include "datatypes.h"
+#include "strutil.h"
+#include "asmdef.h"
+#include "asmsub.h"
+#include "asmpars.h"
+#include "as1750.h"
+#define bool char
+#define ushort unsigned short
+#define ulong unsigned long
+#define status unsigned
+#define dtoi(ascii_char) (ascii_char - '0')
+#endif
+
+
+#ifndef AS1750
+static
+#endif
+ status /* Output an error text (printf style). */
+error (char *layout,...) /* Return the ERROR status code. */
+{
+ va_list vargu;
+ char output_line[132];
+
+ va_start (vargu, layout);
+ vsprintf (output_line, layout, vargu);
+#ifdef AS1750
+ fprintf (stderr, "%s line%5d: %s\n", nopath (file[curr_file].name),
+ file[curr_file].line_number, output_line);
+#else /* ASL */
+ WrErrorString (output_line, "\0", 0, 0);
+#endif
+ va_end (vargu);
+ return ERROR;
+}
+
+
+/* Get a number. Return pointer to first position in s after the end of
+ * the number, or NULL for error.
+ * Will also read character constants of the form: 'x', and two-character
+ * packed strings of the form "xy" (where x=>highbyte,y=>lowbyte.)
+ */
+
+#ifdef AS1750
+
+char *
+get_num (char *s, int *outnum)
+{
+ bool is_neg = FALSE, intel = FALSE, c_lang = FALSE, tld = FALSE;
+ char *start;
+
+ *outnum = 0;
+ if (*s == '-')
+ {
+ is_neg = TRUE;
+ ++s;
+ }
+ else if (*s == '+')
+ ++s;
+ /* determine if Intel format */
+ if (isdigit (*s))
+ {
+ char *p = s;
+ while (isxdigit (*++p))
+ ;
+ if (upcase (*p) == 'H')
+ intel = TRUE;
+ }
+ if (intel
+ || (c_lang = (*s == '0' && upcase (*(s + 1)) == 'X'))
+ || (tld = strncmp (s, "16#", 3) == 0))
+ {
+ s += c_lang ? 2 : tld ? 3 : 0;
+ start = s;
+ while (isxdigit (*s))
+ {
+ *outnum = (*outnum << 4) | xtoi (*s);
+ ++s;
+ }
+ if (s - start > 4)
+ {
+ error ("get_num -- number at '%s' too large", start);
+ return NULL;
+ }
+ if (intel)
+ s++;
+ else if (tld)
+ {
+ if (*s != '#')
+ {
+ error ("get_num -- expecting '#' at end of number");
+ return NULL;
+ }
+ s++;
+ }
+ }
+ else if (*s == '0' || (tld = (*s == '8' && *(s + 1) == '#')))
+ {
+ s += tld ? 2 : 1;
+ start = s;
+ while (*s >= '0' && *s <= '7')
+ {
+ *outnum = (*outnum << 3) | (*s - '0');
+ ++s;
+ }
+ if (s - start > 6)
+ {
+ error ("get_num -- number at '%s' too large", start);
+ return NULL;
+ }
+ if (tld)
+ {
+ if (*s != '#')
+ {
+ error ("get_num -- expecting '#' at end of number");
+ return NULL;
+ }
+ ++s;
+ }
+ }
+ else if (*s == '@' || (tld = (*s == '2' && *(s + 1) == '#')))
+ {
+ s += (tld ? 2 : 1);
+ start = s;
+ while (*s == '0' || *s == '1')
+ {
+ *outnum = (*outnum << 1) | (*s - '0');
+ ++s;
+ }
+ if (s - start > 16)
+ {
+ error ("get_num -- number at '%s' too large", start);
+ return NULL;
+ }
+ if (tld)
+ {
+ if (*s != '#')
+ {
+ error ("get_num -- expecting '#' at end of number");
+ return NULL;
+ }
+ ++s;
+ }
+ }
+ else if (isdigit (*s))
+ {
+ start = s;
+ while (isdigit (*s))
+ {
+ *outnum = (*outnum * 10) + dtoi (*s);
+ ++s;
+ }
+ if (s - start > 5)
+ {
+ error ("get_num -- number at '%s' too large", start);
+ return NULL;
+ }
+ }
+ else if (*s == '\'')
+ {
+ start = s;
+ if (*++s == '\\')
+ {
+ switch (*++s)
+ {
+ case 't':
+ *outnum = 9;
+ break;
+ case 'n':
+ *outnum = 10;
+ break;
+ case 'r':
+ *outnum = 13;
+ break;
+ default:
+ error ("get_num -- unknown escape '\\%c'", *s);
+ return NULL;
+ }
+ }
+ else
+ *outnum = (int) *s & 0xFF;
+ if (*++s != '\'')
+ {
+ error ("get_num -- character constant incorrectly terminated", start);
+ return NULL;
+ }
+ ++s;
+ }
+ else if (*s == '"')
+ {
+ start = s;
+ *outnum = ((int) *++s & 0xFF) << 8;
+ *outnum |= (int) *++s & 0xFF;
+ if (*++s != '"')
+ {
+ error ("get_num -- character tuple incorrectly terminated", start);
+ return NULL;
+ }
+ ++s;
+ }
+ else
+ return NULL;
+ if (is_neg)
+ *outnum = -*outnum;
+ return s;
+}
+
+/* Get a constant symbol (previously defined by EQU) or a number.
+ * Return pointer to first character after the symbol or number consumed,
+ * or NULL if reading the symbol or number was unsuccessful.
+ */
+char *
+get_sym_num (char *s, int *outnum)
+{
+ char *p, c;
+ symbol_t sym;
+
+ if ((p = get_num (s, outnum)) != NULL)
+ return p;
+
+ /* Didn't find a raw number; try symbol. */
+ if (!issymstart (*s))
+ {
+ error ("expecting symbol at '%s'", s);
+ return NULL;
+ }
+ p = s;
+ while (issymchar (*p))
+ p++;
+ c = *p;
+ *p = '\0';
+ if ((sym = find_symbol (s)) == SNULL)
+ {
+ error ("unidentified symbol at '%s'", s);
+ return NULL;
+ }
+ *p = c;
+ if (!sym->is_constant)
+ {
+ error ("symbol must be constant in this context");
+ return NULL;
+ }
+ *outnum = (int) sym->value;
+ return p;
+}
+
+
+extern int curr_frag; /* imported from main.c */
+
+/* Enter a 16-bit word into the object space */
+void
+add_word (ushort word)
+{
+ struct objblock *obj = &objblk[curr_frag];
+
+ if (obj->data == (ushort *) 0)
+ {
+ obj->n_allocated = 256;
+ obj->data = (ushort *) malloc (obj->n_allocated * sizeof (ushort));
+ obj->line = (struct linelist **) malloc
+ (obj->n_allocated * sizeof (struct linelist *));
+ }
+ else if (obj->n_used == obj->n_allocated)
+ {
+ obj->n_allocated *= 2;
+ obj->data = (ushort *) realloc (obj->data,
+ obj->n_allocated * sizeof (ushort));
+ obj->line = (struct linelist **) realloc (obj->line,
+ obj->n_allocated * sizeof (struct linelist *));
+ }
+ if (obj->data == (ushort *) 0 || obj->line == (struct linelist **) 0)
+ problem ("request for object space refused by OS");
+ obj->data[obj->n_used] = word;
+ obj->line[obj->n_used] = line;
+ obj->n_used++;
+}
+
+void
+add_reloc (symbol_t sym) /* auxiliary to parse_addr() */
+{
+ struct reloc *rel;
+
+ if (relblk.data == (struct reloc *) 0)
+ {
+ relblk.n_allocated = 256;
+ relblk.data = (struct reloc *) malloc
+ (relblk.n_allocated * sizeof (struct reloc));
+ }
+ else if (relblk.n_used == relblk.n_allocated)
+ {
+ relblk.n_allocated *= 2;
+ relblk.data = (struct reloc *) realloc (relblk.data,
+ relblk.n_allocated * sizeof (struct reloc));
+ }
+ if (relblk.data == (struct reloc *) 0)
+ problem ("request for relocation space refused by OS");
+ rel = &relblk.data[relblk.n_used];
+ rel->done = FALSE; /* default initializations */
+ rel->reltype = Word_Reloc;
+ rel->frag_index = curr_frag;
+ rel->obj_index = objblk[curr_frag].n_used;
+ rel->sym = sym;
+ relblk.n_used++;
+}
+
+
+/* Parse the address expression at s into object space.
+ Returns OKAY or ERROR. */
+status
+parse_addr (char *s)
+{
+ int num;
+ char *p, c, c1;
+ symbol_t sym, sym1;
+
+ if (issymstart (*s))
+ {
+ p = skip_symbol (s);
+ c = *p; /* prepare for symbol lookup */
+ *p = '\0';
+ if ((sym = find_or_enter (s)) == SNULL)
+ return ERROR;
+ sym->is_referenced = TRUE;
+ *p = c;
+ s = p++;
+ if (c == '\0')
+ {
+ if (sym->is_constant)
+ add_word ((ushort) sym->value);
+ else
+ {
+ add_reloc (sym);
+ add_word (0);
+ }
+ }
+ else if (c != '+' && c != '-')
+ return error ("error after symbolname at: %s", s);
+ else if (issymstart (*p))
+ {
+ s = skip_symbol (p);
+ if (*s != '\0' && *s != ',')
+ return error ("address expression too complex");
+ c1 = *s; /* prepare for symbol lookup */
+ *s = '\0';
+ if ((sym1 = find_or_enter (p)) == SNULL)
+ return ERROR;
+ sym1->is_referenced = TRUE;
+ *s = c1;
+ if (c == '+')
+ {
+ if (sym->is_constant)
+ {
+ if (sym1->is_constant)
+ {
+ long sum = sym->value + sym1->value;
+ if (sum < -0x8000L)
+ return error ("negative overflow in symbol addition");
+ else if (sum > 0xFFFFL)
+ return error ("positive overflow in symbol addition");
+ add_word ((ushort) sum);
+ }
+ else
+ {
+ add_reloc (sym1);
+ add_word ((ushort) sym->value);
+ }
+ }
+ else
+ {
+ if (sym1->is_constant)
+ {
+ add_reloc (sym);
+ add_word ((ushort) sym1->value);
+ }
+ else
+ return error ("cannot add relocatable symbols");
+ }
+ }
+ else
+ /* subtraction */
+ {
+ if (sym->is_constant)
+ {
+ if (sym1->is_constant)
+ {
+ long dif = sym->value - sym1->value;
+ if (dif < -0x8000L)
+ return error ("negative overflow in symbol subtraction");
+ else if (dif > 0xFFFFL)
+ return error ("positive overflow symbol subtraction");
+ add_word ((ushort) dif);
+ }
+ else
+ error ("cannot subtract relocatable symbol from constant symbol");
+ }
+ else
+ {
+ if (sym1->is_constant)
+ {
+ add_reloc (sym);
+ add_word ((ushort) - sym1->value);
+ }
+ else
+ {
+ if (objblk[sym->frag_index].section !=
+ objblk[sym1->frag_index].section)
+ return error
+ ("cannot subtract relocatable symbols from different fragments");
+ if (sym->value < sym1->value)
+ error ("warning: strange subtraction of relocatable symbols");
+ add_word ((ushort) (sym->value - sym1->value));
+ }
+ }
+ }
+ }
+ else
+ {
+ if (get_num (s, &num) == NULL)
+ return ERROR;
+ if (sym->is_constant)
+ {
+ long sum = sym->value + (long) num;
+ if (sum < -32768L)
+ return error ("neg. overflow in symbolic expression");
+ else if (sum > 65535L)
+ return error ("overflow in symbolic expression");
+ add_word ((ushort) sum);
+ }
+ else
+ {
+ add_reloc (sym);
+ add_word ((ushort) num);
+ }
+ }
+ }
+ else if ((s = get_num (s, &num)) == NULL)
+ return ERROR;
+ else
+ {
+ if (*s == '\0')
+ add_word ((ushort) num);
+ else if (*s != '+')
+ return error ("expected '+' in address expression at: %s", s);
+ else
+ {
+ ++s;
+ if (!issymstart (*s))
+ return error ("expected symbolname in address expression at: %s", s);
+ p = skip_symbol (s);
+ if (*p != '\0' && *p != ',')
+ return error ("illegal characters after symbolname at: %s", s);
+ c = *p; /* prepare for symbol lookup */
+ *p = '\0';
+ if ((sym = find_or_enter (s)) == SNULL)
+ return ERROR;
+ sym->is_referenced = TRUE;
+ *p = c;
+ s = p;
+ if (sym->is_constant)
+ add_word ((ushort) (sym->value + (long) num));
+ else
+ {
+ add_reloc (sym);
+ add_word ((ushort) num);
+ }
+ }
+ }
+ return OKAY;
+}
+
+#else /* ASL */
+
+static char *
+get_sym_num (char *s, int *outnum)
+{
+ Boolean okay;
+ *outnum = (int) EvalIntExpression (s, Int16, &okay);
+ if (!okay)
+ return NULL;
+ return (s + strlen (s)); /* Any non-NULL value will do here. */
+}
+
+
+#define add_word(word) WAsmCode[CodeLen++]=word
+
+static status
+parse_addr (char *s)
+{
+ int value;
+ Boolean okay;
+ value = (int) EvalIntExpression (s, Int16, &okay);
+ if (!okay)
+ return ERROR;
+ add_word ((ushort) value);
+ return OKAY;
+}
+
+#endif /* from #else of #ifdef AS1750 */
+
+/* From here on, everything is identical between as1750 and ASL. */
+
+static ushort
+get_num_bounded (char *s, int lowlim, int highlim)
+{
+ int num;
+ if (get_sym_num (s, &num) == NULL)
+ return ERROR;
+ if (num < lowlim || num > highlim)
+ return error ("number not in range %d..%d", lowlim, highlim);
+ return (ushort) num;
+}
+
+static ushort
+get_regnum (char *s)
+{
+ ushort regnum;
+ *s = toupper (*s);
+ if (*s != 'R')
+ return error ("expecting register at '%s'", s);
+ ++s;
+ if (!isdigit (*s))
+ return error ("expecting register at '%s'", s);
+ regnum = dtoi (*s);
+ ++s;
+ if (isdigit (*s))
+ {
+ regnum = regnum * 10 + dtoi (*s);
+ if (regnum > 15)
+ return error ("register number out of range");
+ ++s;
+ }
+ return regnum;
+}
+
+
+/**********************************************************************/
+/* Functions to process opcode arguments according to addressing mode */
+
+static int n_args;
+static char *arg[4];
+
+static status
+check_indexreg (void)
+{
+ if (n_args > 2)
+ {
+ ushort rx;
+
+ if ((rx = get_regnum (arg[2])) == ERROR)
+ return ERROR;
+ if (rx == 0)
+ return error ("R0 not an index register");
+#ifdef AS1750
+ objblk[curr_frag].data[objblk[curr_frag].n_used - 2] |= rx;
+#else /* ASL */
+ WAsmCode[0] |= rx;
+#endif
+ }
+ return OKAY;
+}
+
+
+static ushort
+as_r (ushort oc)
+{
+ ushort ra, rb;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ if ((ra = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ if ((rb = get_regnum (arg[1])) == ERROR)
+ return ERROR;
+
+ add_word (oc | (ra << 4) | rb);
+ return 1;
+}
+
+static ushort
+as_mem (ushort oc)
+{
+ ushort ra;
+ if (n_args < 2)
+ return error ("insufficient number of operands");
+ if ((ra = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ add_word (oc | (ra << 4));
+ if (parse_addr (arg[1]))
+ return ERROR;
+ if (check_indexreg ())
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_addr (ushort oc) /* LST and LSTI */
+{
+ if (n_args < 1)
+ return error ("insufficient number of operands");
+ add_word (oc);
+ if (parse_addr (arg[0]))
+ return ERROR;
+ n_args++; /* cheat check_indexreg() */
+ arg[2] = arg[1];
+ if (check_indexreg ())
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_xmem (ushort oc) /* MIL-STD-1750B extended mem. addr. */
+{
+ ushort ra;
+
+ if (n_args < 2)
+ return error ("insufficient number of operands");
+ if ((ra = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ add_word (oc | (ra << 4));
+ if (parse_addr (arg[1]))
+ return ERROR;
+ if (n_args > 2)
+ {
+ ushort rx;
+ if ((rx = get_regnum (arg[2])) == ERROR)
+ return ERROR;
+#ifdef AS1750
+ objblk[curr_frag].data[objblk[curr_frag].n_used - 2] |= rx;
+#else /* ASL */
+ WAsmCode[0] |= rx;
+#endif
+ }
+ return 2;
+}
+
+static ushort
+as_im_0_15 (ushort oc) /* for STC, LM, TB,SB,RB,TSB */
+{
+ ushort ra;
+ if (n_args < 2)
+ return error ("insufficient number of operands");
+ if ((ra = get_num_bounded (arg[0], 0, 15)) == ERROR)
+ return ERROR;
+ add_word (oc | (ra << 4));
+ if (parse_addr (arg[1]))
+ return ERROR;
+ if (check_indexreg ())
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_im_1_16 (ushort oc)
+{
+ ushort ra;
+ if (n_args < 2)
+ return error ("insufficient number of operands");
+ if ((ra = get_num_bounded (arg[0], 1, 16)) == ERROR)
+ return ERROR;
+ add_word (oc | ((ra - 1) << 4));
+ if (parse_addr (arg[1]))
+ return ERROR;
+ if (check_indexreg ())
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_im_ocx (ushort oc)
+{
+ ushort ra;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ if ((ra = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ add_word (oc | (ra << 4)); /* oc has OCX in LSnibble */
+ if (parse_addr (arg[1]))
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_is (ushort oc)
+{
+ ushort ra, i;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ if ((ra = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ if ((i = get_num_bounded (arg[1], 1, 16)) == ERROR)
+ return ERROR;
+ add_word (oc | (ra << 4) | (i - 1));
+ return 1;
+}
+
+static ushort
+as_icr (ushort oc)
+{
+#ifdef AS1750
+ struct objblock *obj = &objblk[curr_frag];
+ int last = obj->n_used;
+#endif
+ if (n_args != 1)
+ return error ("incorrect number of operands");
+ if (parse_addr (arg[0]))
+ return ERROR;
+#ifdef AS1750
+ /* If symbol relocation, then set the relocation type to Byte_Reloc */
+ if (relblk.n_used > 0)
+ {
+ struct reloc *rel = &relblk.data[relblk.n_used - 1];
+ if (rel->frag_index == curr_frag && rel->obj_index == last)
+ rel->reltype = Byte_Reloc;
+ }
+ obj->data[last] &= 0x00FF;
+ obj->data[last] |= oc;
+#else /* ASL */
+ {
+ const short target = (short) WAsmCode[0];
+ const long curr_pc = (long) EProgCounter () & 0xFFFFL;
+ const long diff = (long) target - curr_pc;
+ if (diff < -128L || diff > 127L)
+ return error
+ ("address distance too large in Instruction Counter Relative operation");
+ WAsmCode[0] = oc | (ushort) (diff & 0xFFL);
+ }
+#endif
+ return 1;
+}
+
+static ushort
+as_b (ushort oc)
+{
+ char r;
+ ushort br, lobyte;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ r = toupper (*arg[0]);
+ if (r != 'B' && r != 'R')
+ return error ("expecting base register");
+ if ((br = get_num_bounded (arg[0] + 1, 12, 15)) == ERROR)
+ return ERROR;
+ if ((lobyte = get_num_bounded (arg[1], 0, 255)) == ERROR)
+ return ERROR;
+ add_word (oc | ((br - 12) << 8) | lobyte);
+ return 1;
+}
+
+static ushort
+as_bx (ushort oc)
+{
+ char r;
+ ushort br, rx = 0;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ r = toupper (*arg[0]);
+ if ((r != 'B' && r != 'R')
+ || (br = get_num_bounded (arg[0] + 1, 12, 15)) == ERROR)
+ return error ("expecting base register");
+ if ((rx = get_regnum (arg[1])) == ERROR)
+ return ERROR;
+ if (rx == 0)
+ return error ("R0 not an index register");
+ add_word (oc | ((br - 12) << 8) | rx);
+ return 1;
+}
+
+static ushort
+as_r_imm (ushort oc) /* for shifts with immediate shiftcount */
+{
+ ushort rb, n;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ if ((rb = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ if ((n = get_num_bounded (arg[1], 1, 16)) == ERROR)
+ return ERROR;
+ add_word (oc | ((n - 1) << 4) | rb);
+ return 1;
+}
+
+static ushort
+as_imm_r (ushort oc) /* for test/set/reset-bit in reg. */
+{
+ ushort n, rb;
+ if (n_args != 2)
+ return error ("incorrect number of operands");
+ if ((n = get_num_bounded (arg[0], 0, 15)) == ERROR)
+ return ERROR;
+ if ((rb = get_regnum (arg[1])) == ERROR)
+ return ERROR;
+ add_word (oc | (n << 4) | rb);
+ return 1;
+}
+
+static ushort
+as_jump (ushort oc)
+{
+ ushort condcode = 0xFFFF;
+ static const struct
+ {
+ char *name;
+ ushort value;
+ }
+ cond[] =
+ { /* CPZN */
+ { "LT", 0x1 }, /* 0001 */
+ { "LZ", 0x1 }, /* 0001 */
+ { "EQ", 0x2 }, /* 0010 */
+ { "EZ", 0x2 }, /* 0010 */
+ { "LE", 0x3 }, /* 0011 */
+ { "LEZ", 0x3 }, /* 0011 */
+ { "GT", 0x4 }, /* 0100 */
+ { "GTZ", 0x4 }, /* 0100 */
+ { "NE", 0x5 }, /* 0101 */
+ { "NZ", 0x5 }, /* 0101 */
+ { "GE", 0x6 }, /* 0110 */
+ { "GEZ", 0x6 }, /* 0110 */
+ { "ALL", 0x7 }, /* 0111 */
+ { "CY", 0x8 }, /* 1000 */
+ { "CLT", 0x9 }, /* 1001 */
+ { "CEQ", 0xA }, /* 1010 */
+ { "CEZ", 0xA }, /* 1010 */
+ { "CLE", 0xB }, /* 1011 */
+ { "CGT", 0xC }, /* 1100 */
+ { "CNZ", 0xD }, /* 1101 */
+ { "CGE", 0xE }, /* 1110 */
+ { "UC", 0xF } /* 1111 */
+ };
+ if (n_args < 2)
+ return error ("insufficient number of operands");
+ if (isalpha (*arg[0]))
+ {
+ int i;
+ for (i = 0; i < 22; i++)
+ if (!strcasecmp (arg[0], cond[i].name))
+ {
+ condcode = cond[i].value;
+ break;
+ }
+ }
+ if (condcode == 0xFFFF)
+ if ((condcode = get_num_bounded (arg[0], 0, 15)) == ERROR)
+ return ERROR;
+ add_word (oc | (condcode << 4));
+ if (parse_addr (arg[1]))
+ return ERROR;
+ if (check_indexreg ())
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_s (ushort oc) /* For the moment, BEX only. */
+{
+ ushort lsnibble;
+ if (n_args != 1)
+ return error ("incorrect number of operands");
+ if ((lsnibble = get_num_bounded (arg[0], 0, 15)) == ERROR)
+ return ERROR;
+ add_word (oc | lsnibble);
+ return 1;
+}
+
+static ushort
+as_sr (ushort oc) /* XBR and URS. */
+{
+ ushort hlp;
+ if (n_args != 1)
+ return error ("incorrect number of operands");
+ if ((hlp = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ add_word (oc | (hlp << 4));
+ return 1;
+}
+
+static ushort
+as_xio (ushort oc)
+{
+ ushort ra;
+ int cmdfld = -1;
+ static const struct
+ {
+ char *mnem;
+ ushort cmd;
+ }
+ xio[] =
+ {
+ { "SMK", 0x2000 },
+ { "CLIR", 0x2001 },
+ { "ENBL", 0x2002 },
+ { "DSBL", 0x2003 },
+ { "RPI", 0x2004 },
+ { "SPI", 0x2005 },
+ { "OD", 0x2008 },
+ { "RNS", 0x200A },
+ { "WSW", 0x200E },
+ { "CO", 0x4000 },
+ { "CLC", 0x4001 },
+ { "MPEN", 0x4003 },
+ { "ESUR", 0x4004 },
+ { "DSUR", 0x4005 },
+ { "DMAE", 0x4006 },
+ { "DMAD", 0x4007 },
+ { "TAS", 0x4008 },
+ { "TAH", 0x4009 },
+ { "OTA", 0x400A },
+ { "GO", 0x400B },
+ { "TBS", 0x400C },
+ { "TBH", 0x400D },
+ { "OTB", 0x400E },
+ { "LMP", 0x5000 },
+ { "WIPR", 0x5100 },
+ { "WOPR", 0x5200 },
+ { "RMP", 0xD000 },
+ { "RIPR", 0xD100 },
+ { "ROPR", 0xD200 },
+ { "RMK", 0xA000 },
+ { "RIC1", 0xA001 },
+ { "RIC2", 0xA002 },
+ { "RPIR", 0xA004 },
+ { "RDOR", 0xA008 },
+ { "RDI", 0xA009 },
+ { "TPIO", 0xA00B },
+ { "RMFS", 0xA00D },
+ { "RSW", 0xA00E },
+ { "RCFR", 0xA00F },
+ { "CI", 0xC000 },
+ { "RCS", 0xC001 },
+ { "ITA", 0xC00A },
+ { "ITB", 0xC00E },
+ { "", 0xFFFF }
+ };
+
+ if (n_args < 2)
+ return error ("incorrect number of operands");
+ if ((ra = get_regnum (arg[0])) == ERROR)
+ return ERROR;
+ add_word (oc | (ra << 4));
+ /* Get the XIO command field. */
+ if (isalpha (*arg[1]))
+ {
+ int i;
+ for (i = 0; xio[i].cmd != 0xFFFF; i++)
+ if (!strcasecmp (arg[1], xio[i].mnem))
+ break;
+ if (xio[i].cmd != 0xFFFF)
+ cmdfld = xio[i].cmd;
+ }
+ if (cmdfld == -1)
+ if (get_sym_num (arg[1], &cmdfld) == NULL)
+ return ERROR;
+ add_word ((ushort) cmdfld);
+ if (check_indexreg ())
+ return ERROR;
+ return 2;
+}
+
+static ushort
+as_none (ushort oc)
+{
+ add_word (oc);
+ return 1;
+}
+
+/* end of argument assembly functions */
+
+/***********************************************************************/
+
+static struct
+ {
+ char *mnemon;
+ ushort opcode;
+ ushort (*as_args) (ushort);
+ } optab[] =
+ {
+ { "AISP", 0xA200, as_is }, /* Sorted by beginning letter. */
+ { "AIM", 0x4A01, as_im_ocx }, /* Within each beginning letter, */
+ { "AR", 0xA100, as_r }, /* sorted by approximate */
+ { "A", 0xA000, as_mem }, /* instruction frequency. */
+ { "ANDM", 0x4A07, as_im_ocx },
+ { "ANDR", 0xE300, as_r },
+ { "AND", 0xE200, as_mem },
+ { "ABS", 0xA400, as_r },
+ { "AB", 0x1000, as_b },
+ { "ANDB", 0x3400, as_b },
+ { "ABX", 0x4040, as_bx },
+ { "ANDX", 0x40E0, as_bx },
+ { "BEZ", 0x7500, as_icr },
+ { "BNZ", 0x7A00, as_icr },
+ { "BGT", 0x7900, as_icr },
+ { "BLE", 0x7800, as_icr },
+ { "BGE", 0x7B00, as_icr },
+ { "BLT", 0x7600, as_icr },
+ { "BR", 0x7400, as_icr },
+ { "BEX", 0x7700, as_s },
+ { "BPT", 0xFFFF, as_none },
+ { "BIF", 0x4F00, as_s },
+ { "CISP", 0xF200, as_is },
+ { "CIM", 0x4A0A, as_im_ocx },
+ { "CR", 0xF100, as_r },
+ { "C", 0xF000, as_mem },
+ { "CISN", 0xF300, as_is },
+ { "CB", 0x3800, as_b },
+ { "CBL", 0xF400, as_mem },
+ { "CBX", 0x40C0, as_bx },
+ { "DLR", 0x8700, as_r },
+ { "DL", 0x8600, as_mem },
+ { "DST", 0x9600, as_mem },
+ { "DSLL", 0x6500, as_r_imm },
+ { "DSRL", 0x6600, as_r_imm },
+ { "DSRA", 0x6700, as_r_imm },
+ { "DSLC", 0x6800, as_r_imm },
+ { "DSLR", 0x6D00, as_r },
+ { "DSAR", 0x6E00, as_r },
+ { "DSCR", 0x6F00, as_r },
+ { "DECM", 0xB300, as_im_1_16 },
+ { "DAR", 0xA700, as_r },
+ { "DA", 0xA600, as_mem },
+ { "DSR", 0xB700, as_r },
+ { "DS", 0xB600, as_mem },
+ { "DMR", 0xC700, as_r },
+ { "DM", 0xC600, as_mem },
+ { "DDR", 0xD700, as_r },
+ { "DD", 0xD600, as_mem },
+ { "DCR", 0xF700, as_r },
+ { "DC", 0xF600, as_mem },
+ { "DLB", 0x0400, as_b },
+ { "DSTB", 0x0C00, as_b },
+ { "DNEG", 0xB500, as_r },
+ { "DABS", 0xA500, as_r },
+ { "DR", 0xD500, as_r },
+ { "D", 0xD400, as_mem },
+ { "DISP", 0xD200, as_is },
+ { "DIM", 0x4A05, as_im_ocx },
+ { "DISN", 0xD300, as_is },
+ { "DVIM", 0x4A06, as_im_ocx },
+ { "DVR", 0xD100, as_r },
+ { "DV", 0xD000, as_mem },
+ { "DLI", 0x8800, as_mem },
+ { "DSTI", 0x9800, as_mem },
+ { "DB", 0x1C00, as_b },
+ { "DBX", 0x4070, as_bx },
+ { "DLBX", 0x4010, as_bx },
+ { "DSTX", 0x4030, as_bx },
+ { "DLE", 0xDF00, as_xmem },
+ { "DSTE", 0xDD00, as_xmem },
+ { "EFL", 0x8A00, as_mem },
+ { "EFST", 0x9A00, as_mem },
+ { "EFCR", 0xFB00, as_r },
+ { "EFC", 0xFA00, as_mem },
+ { "EFAR", 0xAB00, as_r },
+ { "EFA", 0xAA00, as_mem },
+ { "EFSR", 0xBB00, as_r },
+ { "EFS", 0xBA00, as_mem },
+ { "EFMR", 0xCB00, as_r },
+ { "EFM", 0xCA00, as_mem },
+ { "EFDR", 0xDB00, as_r },
+ { "EFD", 0xDA00, as_mem },
+ { "EFLT", 0xEB00, as_r },
+ { "EFIX", 0xEA00, as_r },
+ { "FAR", 0xA900, as_r },
+ { "FA", 0xA800, as_mem },
+ { "FSR", 0xB900, as_r },
+ { "FS", 0xB800, as_mem },
+ { "FMR", 0xC900, as_r },
+ { "FM", 0xC800, as_mem },
+ { "FDR", 0xD900, as_r },
+ { "FD", 0xD800, as_mem },
+ { "FCR", 0xF900, as_r },
+ { "FC", 0xF800, as_mem },
+ { "FABS", 0xAC00, as_r },
+ { "FIX", 0xE800, as_r },
+ { "FLT", 0xE900, as_r },
+ { "FNEG", 0xBC00, as_r },
+ { "FAB", 0x2000, as_b },
+ { "FABX", 0x4080, as_bx },
+ { "FSB", 0x2400, as_b },
+ { "FSBX", 0x4090, as_bx },
+ { "FMB", 0x2800, as_b },
+ { "FMBX", 0x40A0, as_bx },
+ { "FDB", 0x2C00, as_b },
+ { "FDBX", 0x40B0, as_bx },
+ { "FCB", 0x3C00, as_b },
+ { "FCBX", 0x40D0, as_bx },
+ { "INCM", 0xA300, as_im_1_16 },
+ { "JC", 0x7000, as_jump },
+ { "J", 0x7400, as_icr }, /* TBD (GAS) */
+ { "JEZ", 0x7500, as_icr }, /* TBD (GAS) */
+ { "JLE", 0x7800, as_icr }, /* TBD (GAS) */
+ { "JGT", 0x7900, as_icr }, /* TBD (GAS) */
+ { "JNZ", 0x7A00, as_icr }, /* TBD (GAS) */
+ { "JGE", 0x7B00, as_icr }, /* TBD (GAS) */
+ { "JLT", 0x7600, as_icr }, /* TBD (GAS) */
+ { "JCI", 0x7100, as_jump },
+ { "JS", 0x7200, as_mem },
+ { "LISP", 0x8200, as_is },
+ { "LIM", 0x8500, as_mem },
+ { "LR", 0x8100, as_r },
+ { "L", 0x8000, as_mem },
+ { "LISN", 0x8300, as_is },
+ { "LB", 0x0000, as_b },
+ { "LBX", 0x4000, as_bx },
+ { "LSTI", 0x7C00, as_addr },
+ { "LST", 0x7D00, as_addr },
+ { "LI", 0x8400, as_mem },
+ { "LM", 0x8900, as_im_0_15 },
+ { "LUB", 0x8B00, as_mem },
+ { "LLB", 0x8C00, as_mem },
+ { "LUBI", 0x8D00, as_mem },
+ { "LLBI", 0x8E00, as_mem },
+ { "LE", 0xDE00, as_xmem },
+ { "MISP", 0xC200, as_is },
+ { "MSIM", 0x4A04, as_im_ocx },
+ { "MSR", 0xC100, as_r },
+ { "MS", 0xC000, as_mem },
+ { "MISN", 0xC300, as_is },
+ { "MIM", 0x4A03, as_im_ocx },
+ { "MR", 0xC500, as_r },
+ { "M", 0xC400, as_mem },
+ { "MOV", 0x9300, as_r },
+ { "MB", 0x1800, as_b },
+ { "MBX", 0x4060, as_bx },
+ { "NEG", 0xB400, as_r },
+ { "NOP", 0xFF00, as_none },
+ { "NIM", 0x4A0B, as_im_ocx },
+ { "NR", 0xE700, as_r },
+ { "N", 0xE600, as_mem },
+ { "ORIM", 0x4A08, as_im_ocx },
+ { "ORR", 0xE100, as_r },
+ { "OR", 0xE000, as_mem },
+ { "ORB", 0x3000, as_b },
+ { "ORBX", 0x40F0, as_bx },
+ { "PSHM", 0x9F00, as_r },
+ { "POPM", 0x8F00, as_r },
+ { "RBR", 0x5400, as_imm_r },
+ { "RVBR", 0x5C00, as_r },
+ { "RB", 0x5300, as_im_0_15 },
+ { "RBI", 0x5500, as_im_0_15 },
+ { "ST", 0x9000, as_mem },
+ { "STC", 0x9100, as_im_0_15 },
+ { "SISP", 0xB200, as_is },
+ { "SIM", 0x4A02, as_im_ocx },
+ { "SR", 0xB100, as_r },
+ { "S", 0xB000, as_mem },
+ { "SLL", 0x6000, as_r_imm },
+ { "SRL", 0x6100, as_r_imm },
+ { "SRA", 0x6200, as_r_imm },
+ { "SLC", 0x6300, as_r_imm },
+ { "SLR", 0x6A00, as_r },
+ { "SAR", 0x6B00, as_r },
+ { "SCR", 0x6C00, as_r },
+ { "SJS", 0x7E00, as_mem },
+ { "STB", 0x0800, as_b },
+ { "SBR", 0x5100, as_imm_r },
+ { "SB", 0x5000, as_im_0_15 },
+ { "SVBR", 0x5A00, as_r },
+ { "SOJ", 0x7300, as_mem },
+ { "SBB", 0x1400, as_b },
+ { "STBX", 0x4020, as_bx },
+ { "SBBX", 0x4050, as_bx },
+ { "SBI", 0x5200, as_im_0_15 },
+ { "STZ", 0x9100, as_addr },
+ { "STCI", 0x9200, as_im_0_15 },
+ { "STI", 0x9400, as_mem },
+ { "SFBS", 0x9500, as_r },
+ { "SRM", 0x9700, as_mem },
+ { "STM", 0x9900, as_im_0_15 },
+ { "STUB", 0x9B00, as_mem },
+ { "STLB", 0x9C00, as_mem },
+ { "SUBI", 0x9D00, as_mem },
+ { "SLBI", 0x9E00, as_mem },
+ { "STE", 0xDC00, as_xmem },
+ { "TBR", 0x5700, as_imm_r },
+ { "TB", 0x5600, as_im_0_15 },
+ { "TBI", 0x5800, as_im_0_15 },
+ { "TSB", 0x5900, as_im_0_15 },
+ { "TVBR", 0x5E00, as_r },
+ { "URS", 0x7F00, as_sr },
+ { "UAR", 0xAD00, as_r },
+ { "UA", 0xAE00, as_mem },
+ { "USR", 0xBD00, as_r },
+ { "US", 0xBE00, as_mem },
+ { "UCIM", 0xF500, as_im_ocx },
+ { "UCR", 0xFC00, as_r },
+ { "UC", 0xFD00, as_mem },
+ { "VIO", 0x4900, as_mem },
+ { "XORR", 0xE500, as_r },
+ { "XORM", 0x4A09, as_im_ocx },
+ { "XOR", 0xE400, as_mem },
+ { "XWR", 0xED00, as_r },
+ { "XBR", 0xEC00, as_sr },
+ { "XIO", 0x4800, as_xio },
+ { "", 0, as_none } /* end-of-array marker */
+};
+
+/* Offset table with indexes into optab: indexed by starting letter
+ (A => 0, B => 1, ..., Z => 25), returns the starting index
+ and number of entries for that letter in optab[].
+ start_index is -1 if no entries for that starting letter in optab[]. */
+
+static struct
+ {
+ int start_index;
+ int n_entries;
+ }
+ofstab[26];
+
+/* Initialize ofstab[]. This must be called before as1750() can be used. */
+void
+init_as1750 ()
+{
+ int optab_ndx, ofstab_ndx = 1;
+ char c;
+
+ ofstab[0].start_index = 0;
+ ofstab[0].n_entries = 1;
+ for (optab_ndx = 1; (c = *optab[optab_ndx].mnemon) != '\0'; optab_ndx++)
+ {
+ if (c != *optab[optab_ndx - 1].mnemon)
+ {
+ while (ofstab_ndx != c - 'A')
+ ofstab[ofstab_ndx++].start_index = -1;
+ ofstab[ofstab_ndx].start_index = optab_ndx;
+ ofstab[ofstab_ndx++].n_entries = 1;
+ }
+ else
+ ofstab[ofstab_ndx - 1].n_entries++;
+ }
+}
+
+
+/************************** HERE'S THE BEEF: ****************************/
+
+ushort
+as1750 (char *operation, int n_operands, char *operand[])
+{
+ int i, optab_ndx, firstletter;
+ bool found = FALSE;
+
+ if (n_operands < 0 || n_operands > 3 || *operation < 'A' || *operation > 'X')
+ return NO_OPCODE;
+ n_args = n_operands;
+ for (i = 0; i < n_args; i++)
+ arg[i] = operand[i];
+ firstletter = (int) (*operation - 'A');
+ if ((optab_ndx = ofstab[firstletter].start_index) < 0)
+ return NO_OPCODE;
+ for (i = 0; i < ofstab[firstletter].n_entries; i++, optab_ndx++)
+ if (!strcmp (operation + 1, optab[optab_ndx].mnemon + 1))
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ return NO_OPCODE;
+ return (*optab[optab_ndx].as_args) (optab[optab_ndx].opcode);
+}
+