1296 lines
32 KiB
C
1296 lines
32 KiB
C
/***************************************************************************/
|
|
/* */
|
|
/* 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);
|
|
}
|
|
|