v07i097: Generic assembler for micros, Part01/02

sources-request at mirror.TMC.COM sources-request at mirror.TMC.COM
Wed Jan 21 02:08:45 AEST 1987


Submitted by: seismo!cisden!lmc
Mod.sources: Volume 7, Issue 97
Archive-name: micro.asm/Part01

Yet another assembler.......

This one is for assembling absolute code (for prom loading, fer instance)
for 8 and 16 bit microprocessors. I've used it successfully as a back-end
for the small c compiler posted previously, and it works just fine, as
long as you don't need any external subroutines loaded later on. Lints
out as much as possible, but there are probably still some few errors
within, particularly for 16 bit uPs. Feedback welcome. Also any newly
generated machine tables.

Shouldn't be too hard to add relocation stuff - I just didn't have that
need.

: This is a shar archieve.  Extract with sh, not csh.
: The rest of this file will extract:
: 6803reg.h Makefile README asm.1 asm.c asm.h asm.o asm_ops.5
echo extracting - 6803reg.h
sed 's/^X//' > 6803reg.h << '~FUNKY STUFF~'
X
X; control register & bit definition
X;       assumes operating mode 2 or 3
X
Xp1ddr   equ     0       ; port 1 data direction
Xp2ddr   equ     01      ; port 2 data direction
Xp1dr    equ     02      ; port 1 data
Xp2dr    equ     03      ; port 2 data
X
Xp2d_pc2     equ     080
Xp2d_pc1     equ     040
Xp2d_pc0     equ     020
Xp2d_p24     equ     010
Xscixmt      equ     p2d_p24
Xp2d_p23     equ     08
Xscircv      equ     p2d_p23
Xp2d_p22     equ     04
Xsciclock    equ     p2d_p22
Xp2d_p21     equ     02
Xtimerout    equ     p2d_p21
Xp2d_p20     equ     01
Xtimerin     equ     p2d_p20
X
Xtcsr    equ     08      ; timer control & status
X
Xtcs_icf     equ     080     ; input capture flag
Xtcs_ocf     equ     040     ; output capture flag
Xtcs_tof     equ     020     ; timer overflow flag
Xtcs_eici    equ     010     ; enable input capture interrupt
Xtcs_eoci    equ     08      ; enable output capture flag
Xtcs_etoi    equ     04      ; enable timer overflow interrupt
Xtcs_iedg    equ     02      ; input edge
Xtcs_olvl    equ     01      ; output level
X
Xcounth  equ     09      ; timer counter msb
Xcountl  equ     0a      ; timer counter lsb
Xoutcmh  equ     0b      ; timer output compare msb
Xoutcml  equ     0c      ; timer output compare lsb
Xincaph  equ     0d      ; input capture msb
Xincapl  equ     0e      ; input capture lsb
Xrmcr    equ     010     ; SCI rate & mode control
X
Xrmc_cc1     equ     08
Xrmc_cc0     equ     04
Xrmc_cc      equ     0c      ; clock source and format
Xrmc_ss1     equ     02
Xrmc_ss0     equ     01
Xrmc_ss      equ     03      ; clock speed select 0-3, hi-lo
X
Xtrcsr   equ     011     ; xmit/rcv control & status
X
Xtrc_rdf     equ     080     ; rcv data reg full
Xtrc_ofe     equ     040     ; overrun or framing error
Xtrc_tre     equ     020     ; xmit data reg empty
Xtrc_rie     equ     010     ; rcv interrupt enable
Xtrc_re      equ     08      ; receiver enable
Xtrc_tie     equ     04      ; xmit interrupt enable
Xtrc_te      equ     02      ; transmitter enable
Xtrc_wu      equ     01      ; wakeup
X
Xscirdr  equ     012     ; SCI rcv data
Xscitdr  equ     013     ; SCI xmit data
Xramcr   equ     014     ; RAM control
X
Xram_sb      equ     080     ; stand-by power
Xram_e       equ     040     ; internal RAM enabled
X
Xstintram equ    080
Xenintram equ    0ff
X
X; interrupt vectors
X
Xvectors equ     0ff0
Xscivec  equ     vectors+0
Xtofvec  equ     vectors+02
Xtocvec  equ     vectors+04
Xticvec  equ     vectors+06
Xrq1vec  equ     vectors+08
Xswivec  equ     vectors+0a
Xnmivec  equ     vectors+0c
Xstartvec equ    vectors+0e
~FUNKY STUFF~
echo extracting - Makefile
sed 's/^X//' > Makefile << '~FUNKY STUFF~'
XCFLAGS=-O
X
Xasm:    asm.o
X	cc asm.o -o asm
X
Xasm.o:  asm.h ops.h
X
Xclean:
X	rm -f asm *.o
~FUNKY STUFF~
echo extracting - README
sed 's/^X//' > README << '~FUNKY STUFF~'
XSimplicity itself: just link one of the XXXX_ops.h files to ops.h,
Xand say make. You've got an assembler.
X
X6803reg.h has some specific register names for special hardware registers
Xon the 6803.
X
XI would appreciate getting back any new ops.h files anyone cares to
Xgenerate (or maybe regenerate). Send them to hao!cisden!lmc, or to
X
X	Lyle McElhaney
X	Contel, Inc.
X	1101 W. Mineral Ave.
X	Littleton, CO 80120
~FUNKY STUFF~
echo extracting - asm.1
sed 's/^X//' > asm.1 << '~FUNKY STUFF~'
X.so /usr/lib/tmac/tmac.e
X.TH ASM 1 "1 May 1986"
X.SH NAME
Xasm \- generic assembler
X.SH SYNOPSIS
X.B asm
X[
X.B \-o
Xbinname] [
X.B \-l
Xlistname] [
X.B \-x
Xxrefname] inputfile
X.br
X.SH DESCRIPTION
XThe generic assembler is an attempt to build a quick-and-dirty meta-
Xassembler, with which code for several types of microcomputers can be
Xgenerated. It outputs absolute code in two passes, contains a minimum of
Xpseudo-ops, and is quasi-portable between micro types. The opcodes and
Xinstruction layout information is contained within tables, leaving the
Xcode unchanged from micro to micro. There has been no effort expended to
Xmake the assembler match any particular assembly format on the market, so
Xdon't expect any miracles there.
X
XThe statup options specify various files for input and output. The basic
Xoption is the name of the input file; normally it is suffixed by ".a",
Xalthough this is not necessary. If no file is given, then input is taken
Xfrom standard input. The
X.B \-o
Xoption introduces the name of the file to receive the binary
Xoutput. If the option does not exist, the binary goes to standard output
X(since the output is actually in ASCII format, it won't bolix your screen
Xif you forget).  If the option is not followed immediately by a filename,
Xthen the binary will be output to the input file name suffixed by ".o".
XThe format of the binary output is "Intel Standard Hexadecimal Format" and
Xis documented in the source code.
XThe
X.B \-l
Xoption similarly specifies the file for the assembly listing; if the
Xoption is not given, no listing is produced. If the option is alone, then
Xthe listing will go into the input file name suffixed with ".l". The
X.B \-x
Xoption specifies the file to receive the cross-reference; it defaults to
Xthe same filename as the listing, and is deleted if the option is not
Xgiven.
X.pp
XThe assembler boasts (or at least admits) the following features:
X.in +.5i
X.ip \(bu
XTwo pass, all labels are defined both forward and backward.
X.ip \(bu
XAbsolute format code only, no relocation information available.
X.ip \(bu
XTable driven instruction formats, including single opcodes and fixed
Xnumbers of operands.
X.ip \(bu
XExpression evaluation in operands is left-to-right, no precedence or
Xparentheses.
X.ip \(bu
XPredefined symbols accomodated.
X.ip \(bu
XPseudo-ops include org, equ, set (for changing manifest variables), bss,
Xdata, data2 (two bytes!!), string, seg (for setting up data segments that
Xare made contiguous right after pass 1)
Xand end.
X.ip \(bu
XAtoms in operands include labels, ops add (+), subtract (-), multiply (*),
Xinteger divide (/), mod (%), and (&), or (|), and exclusive or (^),
Xdecimal constants, hexadecimal constants (with a leading zero), right
Xjustified zero-filled single characters ('x) and double characters ("xx).
XThe string pseudo-op supports strings surrounded by any unused delimiter.
X.in -.5i
X.pp
XThe pseudo op syntax is as follows:
X.in +.5i
X.ip "[label] org     expr
XSet the value of the symbol in label to the current location counter; set
Xthe location counter to the value of the expression.
X.ip "label   equ     expr
XSet the value of the symbol in label to the value of the expression. Any
Xsuch value may only be changed by a "set" pseudo.
X.ip "label   set     expr
XReset the value of a symbol to the value of the expression.
X.ip "[label] bss     expr
XSet the value of the symbol in the label to the current location counter,
Xthen set the location counter to its current value plus the value of the
Xexpression.
X.ip "[label] data    [:count:]expr
XSet the value of the label to the current location counter, and then
Xgenerate count (default 1) bytes of data, each containing the value of the
Xexpression. Count must contain no forward referenced symbols.
X.ip "[label] data2   [:count:]expr
XSet the value of the label to the current location counter, and then
Xgenerate count (default 1) double-bytes of data, each double-byte
Xcontaining the value of the expression.
XCount must contain no forward referenced symbols.
X.ip "[label] string  $string$
XSet the value of the label to the current location counter, and then
Xgenerate the string as bytes from left to right, appending a single nul
Xbyte. The string delimiter shown above ($) may be any character that
Xdoesn't appear in the string itself, except blank or tab. The special
Xescapes \\t (tab), \\r (carriage return), \\n (newline), \\b (backspace),
X\\? (del), \\^ (escape), \\nn (nn is any hex pair) and \\\\ (\\ itself)
Xare allowed.
X.ip "    seg   [name]
XDeclare a new or reuse an older data segment, which defines it's own
Xlocation counter. The segment that is predefined at the beginning of the
Xassembler may be returned to by a
X.b seg
Xwith no argument.  Any number of segments may be invoked.  Each segment's
Xlocation counter starts at zero during pass 1. When pass 1 is complete,
Xthe segments are "stacked" in the order that they were created, so that
Xthe second segment's lc starts at the first location following the end of
Xthe first segment's highest lc.  These computed lc's are displayed in the
Xpass 2 listing output.  The name used may be any non-blank-containing
Xstring; it is also independent of the symbol name space. At this time,
Xthere are no other definable characteristics of segments.
X.in -.5i
X.SH "OTHER FILES
X/tmp/asm* - intermediate files.
X.SH AUTHOR
XLyle McElhaney
~FUNKY STUFF~
echo extracting - asm.c
sed 's/^X//' > asm.c << '~FUNKY STUFF~'
X#include <stdio.h>
X
X#include "asm.h"
X
Xopdclass o_none  = {0, 0, 0, 0};
Xinsclass i_noopd = {1, 0, &o_none, &o_none, 0, 0};
Xopdef pseudotab[] = {
X	"bss"    , &i_noopd, 0x00, do_bss   ,
X	"data"   , &i_noopd, 0x00, do_data  ,
X	"data2"  , &i_noopd, 0x00, do_data2 ,
X	"end"    , &i_noopd, 0x00, do_end   ,
X	"equ"    , &i_noopd, 0x00, do_equ   ,
X	"include", &i_noopd, 0x00, do_incl  ,
X	"listoff", &i_noopd, 0x00, do_loff  ,
X	"liston" , &i_noopd, 0x00, do_lon   ,
X	"org"    , &i_noopd, 0x00, do_org   ,
X	"seg"    , &i_noopd, 0x00, do_seg   ,
X	"set"    , &i_noopd, 0x00, do_set   ,
X	"string" , &i_noopd, 0x00, do_string,
X};
X#include "ops.h"
X
X#define pseudolen sizeof(pseudotab)/sizeof(opdef)
X
XFILE *input[INCLSTACK], *output, *list;
XFILE *srcin, *binout;
X
Xint errorstat = 0;
Xchar *name;
Xchar *label, *op, *opd;
Xchar buf[100], linecopy[100];
Xchar *filename[INCLSTACK];
Xint lineno[INCLSTACK];
Xint currinput = 0;
Xint pass = 0;
Xint liston = YES;
Xint listing = 0;
Xint binary = 0;
Xint xref = 0;
Xint ignerr;
Xsymbol *symtab;
XMemad lc;
XWord *dummy;
Xsegmnt segmain = {0, 0, "", 0};
Xsegmnt *seghd = &segmain;
Xsegmnt *curseg = &segmain;
Xsegmnt *exprseg;
X
Xmain (argc, argv)
X	int argc;
X	char **argv;
X{
X	char *t1, *t2;
X
X	srcin = stdin;
X	filename[0] = "stdin";
X	binout = stdout;
X	getargs (argc, argv);
X	init ();
X	output = fopen ((t1 = mktemp ("/tmp/asm185XXXXXX")), "w+");
X	input[0] = srcin;
X	if (process ()) reporterr (E_PASS1);
X	(void) fclose (input[0]);
X	init2 ();
X	rewind (output);
X	input[0] = output;
X	output = fopen ((t2 = mktemp ("/tmp/asm285XXXXXX")), "w+");
X	if (process ()) reporterr (E_PASS2);
X	(void) fclose (input[0]);
X	(void) unlink (t1);
X	input[0] = output;
X	output = binout;
X	rewind (input[0]);
X	sort ();
X	(void) fclose (input[0]);
X	(void) unlink (t2);
X	(void) fclose (output);
X	if (xref) crossref ();
X	exit (errorstat);
X}
X
X
X/*      Current arguments:
X		infile  input file name (default stdin)
X		-lfile  listing output to file (default no listing),
X			(default file is infile.l);
X		-ofile  binary output to file (default binary to stdout),
X			(default file is infile.o);
X		-xfile  cross reference output to listing file (default no xref);
X*/
Xvoid getargs (argc, argv)
X	int argc;
X	char **argv;
X{
X	char *cp, *arg, *lname, *oname;
X
X	while (--argc) {
X		arg = *(++argv);
X		if (*arg == '-') {
X			switch (*(++arg)) {
X			case 'l':
X				listing ++;
X				lname = ++arg;
X				break;
X			case 'o':
X				binary ++;
X				oname = ++arg;
X				break;
X			case 'x':
X				xref ++;
X				break;
X			}
X		} else {
X			name = arg;
X			if ((srcin = fopen (name, "r")) == NULL)
X				reporterr (E_INPUT);
X			filename[0] = strcpy (malloc ((unsigned) strlen (name) + 1), name);
X			if (cp = index (name, '.'))
X				*cp = '\0';
X		}
X	}
X	if (binary) {
X		if (!*oname) {
X			(void) strcat (strcpy (buf, name), ".o");
X			oname = buf;
X		}
X		binout = fopen (oname, "w");
X	}
X	if (listing || xref) {
X		if (!*lname) {
X			(void) strcat (strcpy (buf, name), ".l");
X			lname = buf;
X		}
X		list = fopen (lname, "w");
X	}
X	return;
X}
X
X
Xvoid init ()
X{
X	symbol *spt;
X	int i;
X
X	lc = seghd->lc = 0;
X	symtab = (symbol *) malloc ((unsigned) sizeof (symbol) * NSYMS);
X	for (i = 0; i < NSYMS; i++)
X		symtab->name = (char *) 0;
X	for (spt = predef; *(spt->name); spt++)
X		insert (spt->name, spt->value, spt->type, spt->segp, NO);
X	return;
X}
X
X
Xvoid init2 ()
X{
X	segmnt *sp;
X	Memad acc;
X
X	acc = seghd->lc;
X	seghd->lc = 0;
X	for (sp = seghd->next; sp; sp = sp->next) {
X		acc += sp->lc;
X		sp->lc = sp->start = acc - sp->lc;
X	}
X	curseg = seghd;
X	lc = curseg->lc;
X	errorstat = 0;
X	return;
X}
X
X
X
X/*      Gross syntax rules:      <and the rest of us simply obey>
X	Input line:     [label] op [operands]
X	Comments: Blank lines and anything following ';'
X	White space is any combination of blank and/or tab chars.
X	Operands cannot contain white space (except within strings)
X	    and are separated by commas.
X	Label must start in col 1 if it exists.
X*/
Xint process ()
X{
X	char *ipt;
X	int i, done;
X	static char *zit = "";
X
X	pass ++;
X	lineno[0] = 0;
Xcontproc:
X	while (fgets (buf, sizeof buf, input[currinput]) != NULL) {
X		(void) strcpy (linecopy, buf);
X		linecopy[strlen(linecopy)-1] = 0;
X		if (pass == 1) fputs (buf, output);
X		lineno[currinput]++;
X		ipt = buf;
X		label = ipt;
X		op = opd = zit;
X		while (islabel (*ipt)) ipt++;
X		if (iseol (*ipt)) {
X			if (pass == 2)
X				listit (linecopy, lc, dummy, 0);
X			continue;
X		}
X		*ipt++ = 0;
X		while (iswhite (*ipt)) ipt++;
X		if (iseol (*ipt)) {
X			if (pass == 2)
X				listit (linecopy, lc, dummy, 0);
X			continue;
X		}
X		op = ipt;
X		while (isalnum (*ipt)) ipt++;
X		if (iseol (*ipt)) {
X			*ipt = 0;
X			goto parsed;
X		}
X		*ipt++ = 0;
X		while (iswhite (*ipt)) ipt++;
X		opd = ipt;
X		while (*ipt != '\n') ipt++;
X		*ipt = 0;
Xparsed:
X		if ((i = opsrch (op, pseudotab, pseudolen)) >= 0) {
X			done = (pseudotab[i].action) ();
X		} else if ((i = opsrch (op, optab, oplen)) >= 0) {
X			(void) (optab[i].action) (i);
X		} else {
X			reporterr (E_ILLOP);
X			listit (linecopy, lc, dummy, 0);
X		}
X		if (done) break;
X	}
X	if (currinput > 0) {
X		free (filename[currinput]);
X		filename[currinput] = NULL;
X		(void) fclose (input[currinput--]);
X		goto contproc;
X	}
X	return (errorstat);
X}
X
Xint opsrch (op, table, tablen)
X	char *op;
X	int tablen;
X	opdef table[];
X{
X	int i;
X
X	for (i = 0; i < tablen; i++)
X		if (strcmp (table[i].name, op) == 0)
X			return (i);
X	return (-1);
X}
X
X
Xint do_incl ()
X{
X	if (pass == 1) {
X		char *ip;
X
X		if (++currinput > INCLSTACK)
X			reporterr (E_INCL);
X		opd++;
X		if ((ip = index (opd, '"')) == 0)
X			reporterr (E_INCLSYN);
X		*ip = 0;
X		if ((input[currinput] = fopen (opd, "r")) == NULL)
X			reporterr (E_INPUT);
X		filename[currinput] = strcpy (malloc ((unsigned) strlen (opd) + 1), opd);
X		lineno[currinput] = 0;
X	}
X	return (0);
X}
X
X
Xint do_org ()
X{
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	if (pass == 2)
X		listit (linecopy, lc, dummy, 0);
X	lc = (Memad) expr (&opd, &ignerr, NO);
X	return (0);
X}
X
X
Xint do_loff ()
X{
X	liston = NO;
X	return (0);
X}
X
X
Xint do_lon ()
X{
X	liston = YES;
X	return (0);
X}
X
X
Xint do_equ ()
X{
X	long eqtemp;
X
X	eqtemp = expr (&opd, &ignerr, NO);
X	if (label && *label)
X		insert (label, eqtemp, &o_mem, exprseg, NO);
X	if (pass == 2)
X		listit (linecopy, eqtemp, dummy, 0);
X	return (0);
X}
X
X
Xint do_seg ()
X{
X	segmnt *sp, *osp;
X
X	curseg->lc = lc;
X	if (opd && *opd) {
X		for (sp = seghd; sp; osp = sp, sp = sp->next) {
X			if (strcmp (sp->name, opd) == 0) {
X				lc = sp->lc;
X				curseg = sp;
X				goto fin_seg;
X			}
X		}
X	} else {
X		lc = seghd->lc;
X		curseg = seghd;
X	}
X	curseg = osp->next = (segmnt *) malloc ((unsigned) sizeof (segmnt));
X	curseg->name = strcpy (malloc ((unsigned) strlen (opd) + 1), opd);
X	curseg->lc = lc = 0;
X	curseg->next = (segmnt *) 0;
Xfin_seg:
X	if (pass == 2)
X		listit (linecopy, lc, dummy, 0);
X	return (0);
X}
X
X
Xint do_set ()
X{
X	long eqtemp;
X
X	eqtemp = expr (&opd, &ignerr, NO);
X	if (label && *label)
X		insert (label, eqtemp, &o_mem, exprseg, YES);
X	if (pass == 2)
X		listit (linecopy, eqtemp, dummy, 0);
X	return (0);
X}
X
X
Xint do_bss ()
X{
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	if (pass == 2)
X		listit (linecopy, lc, dummy, 0);
X	lc += (Memad) expr (&opd, &ignerr, NO);
X	return (0);
X}
X
X
Xint do_end ()
X{
X	curseg->lc = lc;
X	if (pass == 2) {
X		listit (linecopy, lc, dummy, 0);
X		lc = 0xffff;
X		putoutbin (dummy, 0);
X	}
X	curseg = seghd;
X	return (1);
X}
X
X
Xint do_data ()
X{
X	Word temp, templist[MAXBYTPERINS];
X	char *tp;
X	int count;
X
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	tp = opd;
X	count = 1;
X	if (*opd == ':') {
X		++opd;
X		count = expr (&opd, &ignerr, NO);
X		if (*opd == ':') {
X			opd ++;
X		} else {
X			reporterr (E_EXPR);
X			count = 1;
X			opd = tp;
X		}
X	}
X	if (pass == 2) {
X		int i, j;
X
X		temp = (Word) expr (&opd, &ignerr, NO);
X		for (i = 0; i < MAXBYTPERINS; i++)
X		       templist[i] = temp;
X		for (i = count; i > 0; i -= 3) {
X			j = i > MAXBYTPERINS ? MAXBYTPERINS : i;
X			listit (linecopy, lc, templist, j);
X			lc += j;
X			*linecopy = 0;
X		}
X		for (i = 0; i < count; i++)
X			putoutbin (&temp, 1);
X	} else
X		lc += count;
X	return (0);
X}
X
X
Xint do_data2 ()
X{
X	long temp;
X	char *tp;
X	int count;
X
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	tp = opd;
X	count = 1;
X	if (*opd == ':') {
X		++opd;
X		count = expr (&opd, &ignerr, NO);
X		if (*opd == ':') {
X			opd ++;
X		} else {
X			reporterr (E_EXPR);
X			count = 1;
X			opd = tp;
X		}
X	}
X	if (pass == 2) {
X		int i;
X
X		temp = expr (&opd, &ignerr, NO);
X		for (i = 0; i < count; i++) {
X			listit (linecopy, lc, (Word *)&temp, 2);
X			lc += 2;
X			*linecopy = 0;
X			putoutbin ((Word *)&temp, 1);
X		}
X	} else
X		lc += (count * 2);
X	return (0);
X}
X
X
Xint do_string ()
X{
X	Word buf[120], *bp;
X	Word delim;
X	int len, i;
X
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	delim = *opd++;
X	bp = buf;
X	while (*opd != delim) {
X		if (*opd != '\\')
X			*bp++ = *opd;
X		else {
X			++opd;
X			*bp++ = escape (&opd);
X		}
X		opd++;
X	}
X	*bp++ = '\0';
X	len = bp - buf;
X	if (pass == 2) {
X		for (bp = buf, i = 0; i < len; i += 3, bp += 3) {
X			listit (linecopy, lc + i, bp, len + buf - bp);
X			*linecopy = 0;
X		}
X		putoutbin (buf, len);
X	}
X	lc += len;
X	return (0);
X}
X
X
Xint choiceinstr (ins)
X	int ins;
X{
X	choicedef *chpt;
X	int num, i, fits;
X	Long value;
X	static char *opdpt;
X
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	chpt = (choicedef *)optab[ins].class;
X	num = chpt->field;
X	for (opdpt = opd; num > 1; num --) {
X		opdpt = index (opdpt, ',');
X		if (opdpt == NULL) {
X			reporterr (E_NOPS);
X			return (0);
X		}
X		opdpt++;
X	}
X	value = expr (&opdpt, &i, YES);
X	fits = i ? NO :
X		(value >= chpt->lorange &&
X		 value <= chpt->hirange &&
X		 curseg == exprseg);
X	if ((i = opsrch ((fits ? chpt->rname : chpt->nname), optab, oplen)) >= 0) {
X		(optab[i].action) (i);
X	} else {
X		reporterr (E_ILLOP);
X	}
X	return (0);
X}
X
X
Xint geninstr (ins)
X	int ins;
X{
X	int nargs, length, i, j, k;
X	opdclass *oclass;
X	insclass *iclass;
X	Word itemtemp, obuf[MAXBYTPERINS];
X	unsigned long mask;
X	static unsigned long cons = ~0L;
X	union itemitem {
X		Word s[BYTPERLONG];
X		unsigned long l;
X		long ls;
X	} item;
X	char *nextopd;
X
X	if (label && *label)
X		insert (label, (long) lc, &o_mem, curseg, NO);
X	iclass = optab[ins].class;
X	length = iclass->length;
X	if (pass == 2) {
X		nargs = iclass->mopds;
X		item.l = 0L;
X		for (i = 0; i < MAXBYTPERINS; i++)
X			obuf[i] = 0;
X		*obuf = optab[ins].mask;
X		nextopd = opd;
X		for (j = 0; j < nargs; j++) {
X			if (j != 0) {
X				if (*nextopd != ',') {
X					reporterr (E_NOPS);
X				} else {
X					nextopd++;
X				}
X			}
X			oclass = iclass->type[j];
X			item.l = expr (&nextopd, &ignerr, NO) + oclass->offset -
X				(oclass->relative ? lc : 0);
X			mask = cons >> (LONGLEN - oclass->length);
X			if (item.l < 0L && !oclass->signed)
X				reporterr (E_NEG);
X			if (((item.ls < 0L && oclass->signed) ? -item.ls : item.ls) & ~mask)
X				reporterr (E_TOOBIG);
X			item.l &= mask;
X			if (oclass->byteswapped) {
X				itemtemp = item.s[BYTPERLONG - 2];
X				item.s[BYTPERLONG - 2] = item.s[BYTPERLONG - 1];
X				item.s[BYTPERLONG - 1] = itemtemp;
X			}
X			item.l <<= (LONGLEN - 8 - iclass->offset[j]);
X			for (k = 0; k < MAXBYTPERINS; k++)
X				obuf[k] |= item.s[k];
X		}
X		putoutbin (obuf, length);
X		listit (linecopy, lc, obuf, length);
X	}
X	lc += length;
X	return (0);
X}
X
Xlong expr (string, errind, test)
X	char **string;
X	int *errind;
X	int test;
X{
X	long exp, val;
X	int op, err;
X	int uniop = 0;
X	segmnt *seg1, *seg2;
X
X	*errind = NO;
X	if (**string == '-')
X		uniop = 1;
X	else if (**string == '~')
X		uniop = 2;
X	if (uniop)
X		(*string)++;
X	exp = getval(string, &err, test, &seg1);
X	if (err) goto errorexit;
X	if (uniop == 2)
X		exp = ~exp;
X	else if (uniop == 1)
X		exp = -exp;
X	while (!isdelim(**string)) {
X		if ((op = getop (string)) == NOOP) {
X			if (!test) reporterr (E_EXPR);
Xerrorexit:              for (; !isdelim (**string); *string++)  ;
X			*errind = YES;
X			return (0);
X		}
X		val = getval (string, &err, test, &seg2);
X		if (err) goto errorexit;
X		if (seg1 && seg2 && seg1 != seg2 && pass == 1)
X			reporterr (E_SEG);
X		switch (op) {
X		case PLUS:
X			exp += val;
X			break;
X		case MINUS:
X			exp -= val;
X			break;
X		case MULT:
X			exp *= val;
X			break;
X		case DIV:
X			exp /= val;
X			break;
X		case MOD:
X			exp %= val;
X			break;
X		case OR:
X			exp |= val;
X			break;
X		case AND:
X			exp &= val;
X			break;
X		case EXOR:
X			exp ^= val;
X			break;
X		case SHLF:
X			exp <<= val;
X			break;
X		case SHRT:
X			exp >>= val;
X			break;
X		default:
X			if (!test) reporterr (E_EXPR);
X		}
X		seg1 = seg2;
X	}
X	exprseg = seg1;
X	return (exp);
X}
X
X
X/*      Snag literals and variable names. The literal classes are:
X
X	[digit]....[digit]      unsigned decimal number
X	0[hexdigit]...[hexdigit]unsigned hexadecimal number
X	$                       current location counter
X	'[char]                 single character, right just, zero fill
X	"[char][char]           character pair
X
X	Returns a 16 bit value. Unary operations taken care of in expr;
X	byte swapping done if required by geninstr.
X*/
Xlong getval (strpt, errorret, test, segment)
X	segmnt **segment;
X	char **strpt;
X	int *errorret;
X	int test;
X{
X	long total;
X	char name[33], *npt;
X	int i;
X
X	*segment = (segmnt *) 0;
X	*errorret = 0;
X	total = 0L;
X	if (isdigit (**strpt)) {
X		if (**strpt == '0') {
X			while (isxdigit (**strpt)) {
X				total *= 16;
X				total += xtod (**strpt);
X				(*strpt)++;
X			}
X		} else {
X			while (isdigit (**strpt)) {
X				total *= 10;
X				total += (Long)(**strpt - '0');
X				(*strpt)++;
X			}
X		}
X	} else if (islabel (**strpt)) {
X		npt = name;
X		while (islabel (**strpt)) {
X			*npt++ = **strpt;
X			(*strpt)++;
X		}
X		*npt = '\0';
X		if ((i = lookup (name)) == -1) {
X			if (pass == 2)
X				if (!test) reporterr (E_UNDEF);
X			*errorret = 1;
X			total = 0L;
X		} else {
X			total = symtab[i].value;
X			if (pass == 2 && symtab[i].segp)
X				total += (symtab[i].segp)->start;
X			*segment = symtab[i].segp;
X		}
X	} else if (**strpt == '\'') {
X		(*strpt)++;
X		if (**strpt == '\\') {
X			(*strpt)++;
X			total = escape (strpt);
X		} else {
X			total = **strpt;
X			(*strpt)++;
X		}
X	} else if (**strpt == '"') {
X		(*strpt)++;
X		if (**strpt == '\\') {
X			(*strpt)++;
X			total = escape (strpt);
X		} else {
X			total = **strpt;
X			(*strpt)++;
X		}
X		total <<= 8;
X		if (**strpt == '\\') {
X			(*strpt)++;
X			total |= escape (strpt);
X		} else {
X			total |= **strpt;
X			(*strpt)++;
X		}
X	} else if (**strpt == '$') {
X		total = lc;
X		*segment = curseg;
X		(*strpt)++;
X	} else {
X		if (!test) reporterr (E_EXPR);
X		*errorret = 1;
X	}
X	return (total);
X}
X
X
Xchar escape (st)
X	char **st;
X{
X	switch (*((*st)++)) {
X	case 'b':
X		return ('\b');
X	case 'n':
X		return ('\n');
X	case 'r':
X		return ('\r');
X	case '^':
X		return ('\033');
X	case 'f':
X		return ('\f');
X	case 't':
X		return ('\t');
X	case '?':
X		return ('\177');
X	case '\\':
X		return ('\\');
X	default:
X		(*st)--;
X		if (isxdigit (**st) && isxdigit (*(*st + 1))) {
X			*st += 2;
X			return (xtod (*(*st - 2)) << 4 | xtod (*(*st - 1)));
X		} else {
X			return (*(*st++));
X		}
X	}
X}
X
X
Xint xtod (c)
X	char c;
X{
X	return ((int) c - (c > '9' ? (c > 'F' ? 'W' : '7') : '0'));
X}
X
X
Xint getop (string)
X	char **string;
X{
X	static char ops[] = OPSTRING;
X	char *k;
X
X	for (k = ops; *k; k++)
X		if (*k == **string) {
X			(*string)++;
X			return ((int) (k - ops));
X		}
X	(*string)++;
X	return (NOOP);
X}
X
X
Xvoid listit (line, xlc, binbuf, length)
X	char *line;
X	Memad xlc;
X	Word *binbuf;
X	int length;
X{
X	int i;
X
X	if (listing && liston) {
X		(void) fprintf (list, "%4ld %04x: ", lineno[currinput], xlc);
X		if (length > 3) length = 3;
X		for (i = 0; i < length; i++)
X			(void) fprintf (list, "%02x ", binbuf[i]);
X		for (i = length; i < MAXBYTPERINS; i++)
X			(void) fprintf (list, "   ");
X		(void) fprintf (list, "    %s\n", line);
X	}
X	return;
X}
X
X
X/*      Binary output format:
X
X	Intel standard hexadecimal format!!!!
X
X        Output is a series of variable length records consisting of ascii
X        characters 0-9, A-F (0x30-0x39, 0x41-0x6). Each character contains
X        four bits of significant data; two such characters form a binary
X	byte of data, the binary equivalent to the hexadecimal ascii
X	characters.
X
X	The data records have the format:
X
X					    /  len covers this \
X	+---+---+---+---+---+---+---+---+---+--------//--------+---+---+
X	| : |  len  |    address    | 0 | 0 |    data bytes    | cksum |
X	+---+---+---+---+---+---+---+---+---+--------//--------+---+---+
X	    \             checksum covers this                 /
X
X	Checksum computed such that sum of all bytes except ':' modulo
X	the bytelength is 0.
X
X	End Record:
X
X	+---+---+---+---+---+---+---+---+---+---+---+
X	| : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | f | f |
X	+---+---+---+---+---+---+---+---+---+---+---+
X
X
X*/
Xvoid putoutbin (binbuf, length)
X	Word binbuf[];
X	int length;
X{
X	static Memad address;
X	static int count;
X	static Word checksum;
X	static Word array[BINBUFLEN];
X	static Word *curpt = 0;
X	static Memad binlc = ~0;
X	int i;
X
X	if (binlc != lc) {
X		if (curpt != 0) {
X			(void) fwrite (":", 1, 1, output);
X			putout ((Word) count);
X			putout ((Word) address >> 8);
X			putout ((Word) address & 0xff);
X			(void) fwrite ("00", 2, 1, output);
X			for (i = 0; i < count; i++)
X				putout (array[i]);
X			putout (checksum);
X			if (length == 0) {
X				(void) fwrite (":00000001ff", 11, 1, output);
X			}
X		}
X		curpt = array;
X		count = 0;
X		address = binlc = lc;
X		checksum = 0;
X	}
X	for (i = 0; i < length; i++) {
X		*curpt++ = binbuf[i];
X		checksum += binbuf[i];
X		count++;
X		binlc ++;
X	}
X	if (count > BINBUFLEN - MAXBYTPERINS)
X		binlc = 0;
X	return;
X}
X
X#define hex(x) x+(x<10?'0':'7')
X
Xvoid putout (c)
X	Word c;
X{
X	Word outc[2], t;
X
X	t = c>>4;
X	c &= 0xf;
X	outc[0] = hex(t);
X	outc[1] = hex(c);
X	(void) fwrite ((char *)outc, 2, 1, output);
X	return;
X}
X
X
Xvoid insert (name, value, type, segment, mult)
X	char *name;
X	long value;
X	opdclass *type;
X	segmnt *segment;
X	int mult;
X{
X	int x, y;
X	symbol *sp;
X
X	x = y = hash (name);
X	while ((sp = &symtab[x])->name != (char *) 0) {
X		if (strcmp (sp->name, name) == 0) {
X			if (!mult && value != sp->value && pass == 1) {
X				reporterr (E_MULT);
X				return;
X			}
X			break;
X		}
X		if (++x == y) reporterr (E_STOFLO);
X		if (x == NSYMS) x = 0;
X	}
X	sp->name = malloc ((unsigned) strlen (name) + 1);
X	(void) strcpy (sp->name, name);
X	sp->value = value;
X	sp->type = type;
X	sp->segp = segment;
X	return;
X}
X
X
Xint lookup (name)
X	char *name;
X{
X	int x, y;
X
X	x = y = hash (name);
X	while (symtab[x].name != (char *) 0) {
X		if (strcmp (name, symtab[x].name) == 0)
X			return (x);
X		x++;
X		if (x == y) return (-1);
X		if (x == NSYMS) x = 0;
X	}
X	return (-1);
X}
X
X
Xint hash (string)
X	char *string;
X{
X	char *pt;
X	int tot;
X
X	tot = 0;
X	for (pt = string; *pt; pt++)
X		tot += *pt;
X	if (NSYMS >= 256)
X		tot += (tot << 8);
X	return (tot % NSYMS);
X}
X
X
Xvoid reporterr (errcode)
X	int errcode;
X{
X	static char *elist[] = {
X		"",
X		"aborting at end of pass1",
X		"aborting at end of pass2",
X		"symbol table overflow",
X		"input file error",
X		"too many nested includes",
X		"include syntax error",
X		"illegal expression",
X		"undefined symbol",
X		"unknown op code",
X		"multiply defined symbol",
X		"insufficient operands",
X		"value too large for field",
X		"unsigned value negative",
X		"segment violation",
X	};
X
X	if (pass == 1) {
X		(void) fprintf (list, "----> Error in file %s, line %d: %s\n", filename[currinput], lineno[currinput], elist[errcode]);
X		(void) fprintf (stderr, "----> Error in file %s, line %d: %s\n", filename[currinput], lineno[currinput], elist[errcode]);
X	} else {
X		(void) fprintf (list, "----> %s: %s\n", filename[currinput], elist[errcode]);
X		(void) fprintf (stderr, "----> %s: %s\n", filename[currinput], elist[errcode]);
X	}
X	(void) fflush (list);
X	if (errcode <= A_MAX) {
X		(void) fprintf (stderr, "asm: Abort error: %s\n", elist[errcode]);
X		exit (1);
X	}
X	errorstat++;
X	return;
X}
X
X
Xvoid sort ()
X{
X	char c;
X
X	while ((c = getc (input[0])) > 0)
X		putc (c, output);
X	return;
X}
X
X
Xvoid crossref ()
X{
X	int i, j, k, gap;
X	symbol symtemp;
X
X	(void) fprintf (list, "\n\n\n                     Cross Reference\n\n");
X	k = 0;
X	for (i = 0; i < NSYMS; i++)
X		if (symtab[i].name && *symtab[i].name)
X			symtab[k++] = symtab[i];
X	for (gap = k / 2; gap > 0; gap /= 2)
X		for (i = gap; i < k; i++)
X			for (j = i - gap; j >= 0; j -= gap) {
X				if (strcmp (symtab[j].name,
X						  symtab[j+gap].name) <= 0)
X					break;
X				symtemp = symtab[j];
X				symtab[j] = symtab[j+gap];
X				symtab[j+gap] = symtemp;
X			}
X	for (i = 0; i < k; i++)
X		(void) fprintf (list, "    %s: 0x%x\n", symtab[i].name,
X							symtab[i].value);
X	return;
X}
~FUNKY STUFF~
echo extracting - asm.h
sed 's/^X//' > asm.h << '~FUNKY STUFF~'
X#include <ctype.h>
X#define YES 1
X#define NO 0
X
X#define NSYMS 253
X#define INCLSTACK 10
X#define MAXBYTPERINS 3
X#define BYTPERLONG 4
X#define LONGLEN 32
X#define MAXOPDS 2
X#define NHEAD 5                 /* words of overhead in binary header */
X#define BINBUFLEN 250
X
X#define iswhite(c) (c==' '||c=='\t')
X#define iseol(c) (c=='\0'||c==';'||c=='\n')
X#define isdelim(c) (c==','||c==':'||iseol(c)||iswhite(c))
X#define islabel(c) (isalnum(c)||c=='_')
X
X#define A_MAX 6         /* highest error code causing immediate abort */
X#define E_PASS1 1
X#define E_PASS2 2
X#define E_STOFLO 3
X#define E_INPUT 4
X#define E_INCL 5
X#define E_INCLSYN 6
X#define E_EXPR 7
X#define E_UNDEF 8
X#define E_ILLOP 9
X#define E_MULT 10
X#define E_NOPS 11
X#define E_TOOBIG 12
X#define E_NEG 13
X#define E_SEG 14
X
X#define NOOP -1
X#define PLUS 0
X#define MINUS 1
X#define MULT 2
X#define DIV 3
X#define MOD 4
X#define OR 5
X#define AND 6
X#define EXOR 7
X#define SHLF 8
X#define SHRT 9
X#define OPSTRING "+-*/%|&^<>"   /* same order as definitions above */
X
Xtypedef unsigned char Word;     /* instruction word */
Xtypedef short Long;             /* Long, that is, on an 8085: 16 bit data */
Xtypedef char  Short;            /* 8 bit data */
Xtypedef unsigned Long Memad;
Xtypedef char Flag;
X
Xtypedef struct opdclassitem {   /* This defines an instruction field */
X	int length;                     /* length in bits of field */
X	Flag signed;                    /* else unsigned */
X	Flag byteswapped;               /* data has bytes backwards */
X	Flag relative;                  /* field is relative to $ */
X	int offset;                     /* fixed value added to field */
X} opdclass;
X
Xtypedef struct insclassitem {   /* This defines an instruction type */
X	int length;                     /* instruction length in bytes */
X	int mopds;                      /* number of operands expected */
X	opdclass *type[MAXOPDS];        /* each operand's field type */
X	int offset[MAXOPDS];            /* each operand's bit offset,
X					   from right end of first byte */
X} insclass;
X
Xtypedef struct chcitem {        /* Defines the alternatives for instr choices */
X	char *rname;                    /* restrictive mnemonic */
X	char *nname;                    /* non-restrictive mnemonic */
X	int field;                      /* operand that is restricted */
X	int lorange, hirange;           /* range of restriction inclusive */
X	Flag relative;                  /* to current lc, else absolute value */
X} choicedef;
X
Xtypedef struct opdefitem {      /* Defines an instruction */
X	char *name;                     /* instruction mnemonic */
X	insclass *class;                /* instruction type */
X	Word mask;                      /* mask for first byte of instruction */
X	int (*action) ();               /* action routine for assembly */
X} opdef;
X
Xtypedef struct seg {            /* Defines a location counter segment */
X	Memad lc, start;                /* segment's lc and starting loc */
X	char *name;                     /* segment name */
X	struct seg *next;               /* pointer to next segment */
X} segmnt;
X
Xtypedef struct ltitem {         /* Defines a label table entry */
X	char *name;                     /* symbol name */
X	long value;                     /* symbol's current value */
X	opdclass *type;                 /* symbol type (defines fields it can fill) */
X	segmnt *segp;                   /* pointer to segment value's defined in */
X} symbol;
X
Xextern char *malloc();
Xextern char *strcpy();
Xextern char *strcat();
Xextern char *mktemp();
Xextern char *index();
Xextern int geninstr();
Xextern int choiceinstr();
Xextern int do_bss();
Xextern int do_data();
Xextern int do_data2();
Xextern int do_end();
Xextern int do_equ();
Xextern int do_seg();
Xextern int do_set();
Xextern int do_org();
Xextern int do_string();
Xextern int do_incl();
Xextern int do_loff();
Xextern int do_lon();
Xextern void getargs ();
Xextern void init ();
Xextern void init2 ();
Xextern int process ();
Xextern void listit ();
Xextern void insert ();
Xextern void reporterr ();
Xextern int hash ();
Xextern long expr ();
Xextern int getop ();
Xextern long getval ();
Xextern int lookup ();
Xextern void putoutbin ();
Xextern void crossref ();
Xextern void sort ();
Xextern void putout ();
Xextern int xtod ();
Xextern char escape ();
~FUNKY STUFF~
echo extracting - asm.o
sed 's/^X//' > asm.o << '~FUNKY STUFF~'
X"@00 HNVx#|#|1P#|/./.a6POaTHy1hHy1VN9XO-@|/N9PO#@#yazJ
XHxaXO/9N9XOav/9N9XO#yHy1}Hy1kN9XO- at x/N9PO#@aJ
XHxaXO/9N9XO/.|N9XO#y#y/9N9XOaH/9N9XO/.xN9XO/9N9XOJ90bga/90JN9XON^NuNVpS.gfX. n-Px nx-fNR.x nxH
XHxazXO/9/9N9XOR

Vx y0r=Pz y0rBP y0r-h|g  n|0Qnz0.zP1@ n|0
X n|_fR.|`X n|Jg;g
Xf290Rf
XB'/9p09/Hya*Oo`~f n|BR.| n| gr	glJg;g
Xf290Rf~.B'/9p09/HyaNOo`~
Xg,BR.| n| gr	gl#H n|
XgR.|`p n|BHxHy"d/9avOo- at xmP

HpN^NuNV|90RfLR90N9
X0No
XHxa(XOR9Hx"/9N9PO-@|f
XHxaXO n|BHy1
XHxaHXO/9/9N9XOR
XvOo3 at pN^NuNVB90VpN^NuNVr#A0VpN^NuNV|B'HyHya
X.Oo-@|J9g( yJgB'/9Hy#0//9alOo90RfB'/9/.|HyaOopN^NuNVx y0v09J9gX yJgN-y0r|J.|gV/9 n|/(N9POJ

Oo-@|J9g* yJg Hx/9Hy#0//9aROo90RfB'/9/.|HyatOopN^NuNVJ9g0 yJg&B'/90vHy#0p09//9ajOo90Rf B'/9p09/HyaOoB'HyHya6OoQypN^NuNV y0v0990Rf6B'/9p09/Hya(Oo3|B'/9ajPO#y0r0vpN^NuNVlJ9g0 yJg&B'/90vHy#0p09//9a~Oo-yxr-At y:fLR9B'HyH


yaVOo- at t y:fR9`Hxa4XOr-At#nx90Rf0B'HyHyaOo@B.p .p.|R.p.pmh-ntpJ.poJ.pop` .p- at l/Hn|p09/Hya


hOo- at t y:fR9`HxaFXOr-At#nx90RfhB'HyHyaOo-@|B.p .p0.tlLHxHn|p09/HyaOoTyB9HxHn|a\POR.p`6 .tc

90RfbAn-HB.z .z0.~l>AnQn~nHP/.p09P.z/Hya
XdOoB9V.zV.`8/.~HnaPO0.

/av>Oo- at tm/P

- at P nh (P.PJ(g
Xr29`r- at X nhp "90~`)-A\J.XJ.XlJ(g .XD
XHxa0XO .\A.X nhJ(gnZcn[Znc[ .pe

f
X .|D
XgP n P gB n P	g4/.a
XXO- at tr0fvJ.f
XHxa
X
Xg n P g n P	gX.`( nr p`6Hnd/.Hnp/.a&Oo- at xJ.pfxJ.hg&J.dg  .h0.dg90Rf
XHxa	JXO .t
XHxa|XO-ndh`}p#nh .|N^NuNVP nB nBB.| n PH

r at f n P_f nV"n"QR.V nR`B nVBHn[atXO- at Rr0f,90RfJ.f
XHxaxXO nr B.|` .Ri
XXOH
XHxaVXO nr  .|N^NuNV| n R
X`(p

Hy1!/9N9POR.|`\/.Hy1%/9N9OoN^NuNVx0910yg
XJ91gV/9HxHxHy1-N9Oop97{/a.XOp97u`/aXO97u

p.}.
X}dr0`r7P@~p..
Xdr0`r7P@/9HxHxHn~N9OoN^NuNVt/.aLXO- at x-@| .|i
Xa*XO`vR.| .|0.xf
XHxaXO.}|fB.|`/.N9XOR



m y (R

` .xP.pi
XF3$"L23)"L
XJ3Z"LH~#"@|#"@##Hz##Tz##z##<z##0z#T"@#"@#<"@#0"@#$"@#`#$3a3f3k3p3u3z344	44444"4'4,41464;4 at 4E4J4O4U4[4`4e4j4o4t4y4~44	44444#"


LV4'"L:V4+$$~4/#LV44#	V49#d)V4>#|9V4C$:~4G#LV4L#V4Q%~4V$,SV4\$CV4b$DcV4h$\sV4n#d+V4s#|;V4x$P~4|#LV5#V5#d$V5#|4V5#lHV5"LV5$DhV5$\xV5##lGV5($DgV5-$\wV51$ V54$f~58#LV5=#V5B#d%V5G#|5V5L$t V5P$t


V5X"LV5\"LV5`#lOV5e$DoV5j$\V5n"L
XV5r$|~5v#LV5{#V5
X$D-V6$\=V6%(~6#LV6#V6"#d&V6'#|6V6,%,~60$,\V65$LV6:$DlV6?$\|V6D%>~6H#LV6M#4V6R#d.V6W#|>V6\#lEV6a"LV6f$DeV6k$\uV6o#lDV6t"LV6y$DdV6~$\tV6"L=V6#l at V6$D`V6$\pV6"LV6%T~6#LV6!#

:#2V6?"L8V6D#lIV6I$DiV6N$\yV6R#lFV6W$DfV6\$\vV6`"L;V6d"L9V6h"LV6l%j~6p#LV6u#V6z#d"V6#|2V7"L

D#V7n$\3V7t#d V7y#|0V7~"L?V7"LV7"LV7
X#`7g#`7j#`7m"@7n0f0f1+-*/%|&^<>1>1?1X1q22212F2Y2j2z22(2B2Zstdin/tmp/asm185XXXXXXw+/tmp/asm285XXXXXXw+r.ow.lwr%4ld %04x: %02x        %s
X:00:00000001ffaborting at end of pass1aborting at end of pass2symbol table overflowinput file errortoo many nested includesinclude syntax errorillegal expressionundefined symbolunknown op codemultiply defined symbolinsufficient operandsvalue too large fo


r fieldunsigned value negativesegment violation----> Error in file %s, line %d: %s
X----> Error in file %s, line %d: %s
X----> %s: %s
X----> %s: %s
Xasm: Abort error: %s
X
X
X
X                     Cross Reference
X
X    %s: 0x%x
Xbssdatadata2endequincludelistofflistonorgsegsetstringadcsadczaddsaddzandsandzbitsbitzcmpscmpzeorseorzldasldazldrsldrzorasorazsbcssbczsubssubzadddsadddzlddslddzstdsstdzstasstazstrsstrzsubdssubdzjsrsjsrzcpxscpxzabaabxadcadcsadciadcxadczaddaddsaddiadddaddds


adddiadddxadddzaddxaddzandandsandiandxandzaslaasldaslxaslasraasrxasrbcbitbitsbitibitxbitzbrabsrcbaclccliclraclrxclrclvcmpcmpscmpicmpxcmpzcomacomxcomcpxcpxscpxicpxxcpxzdaadecadecxdecdesdexeoreorseorieorxeorzincaincxincinsinxjmpxjmpjsrjsrsjsrxjsrzldaldaslda


ildaxldazlddlddslddilddxlddzldrldrsldrildrxldrzlslalsldlslxlsllsralsrdlsrxlsrmulneganegxnegnoporaorasoraioraxorazpshapshxpulapulxrolarolxrolrorarorxrorrtirtssbasbcsbcssbcisbcxsbczsecseisevstastasstaxstazstdstdsstdxstdzstrstrsstrxstrzsubsubssubisubdsubdssu


bdisubdxsubdzsubxsubzswitabtaptbatpatstatstxtsttsxtxswairarbrxspnzzneeqnccgezgzgtlezlelzmovnovpgeltpP
XP at 3PpPbP6@<@B}PPIPX8P^Pb?Pz?P

PRiP\Pd9Pl at vIP~rP@jPlP&HP0HPF@@@@D at H@N at TjPZ@h at ngPt@~?P
X9PSP 9P&,P,iP4,P:nPD,PP at X8P^9PdPl at vgP~9PfP@&P&PP,Pb at n	PvjP~,P>@J	PRjPZ,PnP~P<&P\@bP@@P>@X	P`jPh,P~@@3P.P @*3P2 at 8@B?PJwPV@XP. at 8@B at T&P^&PdP@&PIP@ ?P4&P


:&P at nPLlPViP^@h3Pp at zgPfPfP @&@.jP6fPH@R	PZjPb,PrPx&PjP@(@:P@&PRfPZfPf7Pl@tfP	@		P	,P	2@	8jP	>&P	F&P	P@	^&P	lXP	|jP	@	@	$jP	*@	.@	8lP	H@	N&P	T&P	ZnP	flP	piP	x@
X@
XjP
X@
X@
X(	P
X0jP
X8,P
XRP
XX&P
XjfP
XrfP
X
X@
XfP
X @
X*	P
X4,P
XLfP
XTfP
X`@
Xf@
XnjP
XvfP@	PjP",P2P8&PFjPV@\jPf@p	PxjP
X&PP&P*&P6&PP&PZ@fPl&PDjPL,P^jPd,P
X,PjP,P>jPNfPVfPb at h@pjPxfP&P&P&P,&P<&PF&PL&Pb&P at 8jPD,PR,PtjPfPfP@@&jP.fPL@`&Pd@x@~P@@@0@h at n7P@<@^fPffPr at x@jPfP&@<@z@&PNPxjP at LjPT,PfjP @~PGP&/P7P:P


`P&PlPPl at HP,@<HPPHPpHPzjP@"P>Pl@@4@>@P at ZgPb@hrPn!P&@,rP2!PR at XrP^!Pp at vrP|!P at jP@(8P6@<"PH@X@h@|8P

v at H8PZ"PHPXP@@

DHP!2HP!BHP!JXP!^HP!HP!HP!>HP"HP"HP""@"(rP".!P@@$@(@. at 2@6@<@@@D at J@N at R@X@\@`@f at j@n at t@x@|@@@

@@@T at X@d at h@z@~@@@&@*@<@@@R at V@h at l@~@@@@*@.@@@D at V@Z at l@p@@@@@. at 2@D at H@Z@^@p at t@@
X@@@@@"@&@, at 0@4@:@>@B at H@L at P@V at Z@^@d at h@l at r@v at z@

6@:@>@D at H@L at R@V at Z@`@d at h@n at r@v@|@

@`@d at j@n at r@x@|@

@

@6@:@>@D@H@L@R@V@Z@`@d@h@n@r@v@|@	@	@	
X@	@	@	@	@	 @	&@	*@	.@	4@	8@	<@	B@	F@	J@	P@	T@	X@	^@	b@	f@	l@	p@	t@	z@	~@	@	@	@	@	@	@	@	$@	(@	,@	2@	6@	:@	@@	D@	H@	N@	R@	V@	\@	`@	d@	j@	n@	r@	x@	|@
X@
X@
X
X@
X@
X@
X@
X@
X"@
X&@
X*@
X0@
X4@
X8@
X>@
XB@
XF@
XL@
XP@
XT@
XZ@
X^@
Xb@
Xh@
Xl@
Xp@
Xv@
Xz@
X~@
X@
X@
X@
X@
X@
X@
X @
X$@
X(@
X.@
X2@
X6@
X<@
X@@
XD@
XJ@
XN@
XR@
XX@
X\@
X`@
Xf@
Xj@
Xn@
Xt@
Xx@
X|@@@
X@@@@@"@&@,@0@4@:@>@B@H@L@P@V@Z@^@d@h@l@r@v@z@

6@:@>@D@H@L@R@V@Z@`@d@h@n@r@v@|@

@
X@@@"@*@2@:@B at J@R at Z@b at j@r at z@@*@2 at 6@:@T at X@\@`@d at h@l at p@t at x@|@@@@@%.%$*#l1$t8?F<L&S0f\$|c0^kr$z#T#4$0V,7%(>D%,K^S#<Z0Zctio&0v


%>"d"'$0#8$P?#LG OdY2bhn0Rt0N#(&F# #$(19d>FN#0U~\$d(kHvb|#|Pf4$*29vD%XK#HS$fZb%Bi
XFq0vy~
~FUNKY STUFF~
echo extracting - asm_ops.5
sed 's/^X//' > asm_ops.5 << '~FUNKY STUFF~'
X.so /usr/lib/tmac/tmac.e
X.TH ASM_OPS 5 "1 Nov 1986"
X.SH NAME
Xasm_ops \- generic assembler op-code tables
X.SH DESCRIPTION
XThe generic assembler
X.b asm
Xcan be made to assemble code for a number of different microprocessors. At
Xthe time of this writing, codes have been developed for the Intel 8085,
Xthe Motorola 6803, and the 6502 (Commodore 64). This manual page will
Xdescribe the format of the ops.h file, which contains the processor-specific
Xparts of the assembler. The structures described below are defined in the
Xfile asm.h.
X
XThe opd.h file consists in a series of structure initializations, that
Xgenerate tables in the assembler when it is compiled. All lines are of the
Xform:
X
X	table-type name = {value, ....., value};
X
Xwhere the names are arbitrary (within the c-compiler naming restrictions)
Xand the values may be integers, Flags (i.e., boolean-valued integers),
Xstrings (actually pointers to strings), pointers to other structures
Xwithin the file, and pointers to functions in the assembler itself. The
Xtype Word refers an unsigned byte and Memad refers to a type holding any
Xpossible memory address for the target machine.
X
XThe first structure is opdclass, which defines the kinds of operands that
Xmay appear in an instruction, and their encoding in the corresponding
Xinstruction word:
X
X.nf
Xtypedef struct opdclassitem {   /* This defines an instruction field */
X	int length;                     /* length in bits of field */
X	Flag signed;                    /* else unsigned */
X	Flag byteswapped;               /* data has bytes backwards */
X	Flag relative;                  /* field is relative to $ */
X	int offset;                     /* fixed value added to field */
X} opdclass;
X.fi
X
XAn operand's
X.b length
Xrefers to the number of bits that are allocated for it
Xin the instruction field. If that number is eight, then only numbers from
X-128 through +127 (two's complement assumed) can fit in the field. If the
Xnext flag,
X.b signed ,
Xis set then the range becomes 0 through 255, in this
Xexample. The
X.b byteswapped
Xflag is set if the bytes (in a multibyte field)
Xare to be loaded within a 2 byte word in right-to-left order, rather then
Xthe more conventional left-to-right. The
X.b relative
Xflag is set if the value
Xto be placed in the field must first be decremented by the value of the
Xlocation counter before insertion. Finally,
X.b offset
Xis an integer value
Xto be added to the value of the field before it is inserted. As an
Xexample, an entry for the 6805 reads:
X
Xopdclass o_rmem  = { 8, YES, NO , YES, -2};
X
XThis defines a field that is used in relative-mode instructions. The field
Xis eight bits long, is signed, and is relative to the current lc. In
Xaddition, it is expected to be decremented by two. Given all this, the
Xlegal range of a value to be placed in this field must be from (lc)-126
Xthrough (lc)+129 inclusive, where (lc) is the current value of the
Xlocation counter (which points to the first byte of the current
Xinstruction).
X
XThe second "set" of structures, insclass, define an instruction type.
XEvery generated instruction must fall within one of these types.  They
Xdefine the instruction structure (as a collection of fields) and the
Xwritten form of its invocation:
X
X.nf
Xtypedef struct insclassitem {   /* This defines an instruction type */
X	int length;                     /* instruction length in bytes */
X	int mopds;                      /* number of operands expected */
X	opdclass *type[MAXOPDS];        /* each operand's field type */
X	int offset[MAXOPDS];            /* each operand's bit offset,
X					   from right end of first byte */
X} insclass;
X.fi
X
XThe
X.b length
Xof an instruction type is the number of bytes in the
Xinstruction, including all the fields.  The number of operands expected
X.b mopd
Xmay be 0, 1, or 2 (making this larger would involve changes to asm.h and
Xasm.c). MAXOPDS enforces the current limit on operands to two.  The
Xmembers of the array
X.btype
Xare pointers to the appropriate opdclass defined
Xabove.  When the instruction is scanned, the first operand must fit the
Xfield described in the structure pointed to be xxx.type[0], the second by
Xxxx.type[1]. The array
X.b offset
Xdefines the amount of shifting to be done to
Xproperly align the field in the instruction.  An offset of zero states
Xthat the field's rightmost bit should be placed in the rightmost bit of
Xthe instruction's first byte; a negative offset requires the value to be
Xshifted left that many bits, and a positive value must be shifted right.
XAn example, again from the 6805, shows the format of a relative
Xinstruction:
X
Xinsclass i_rel   = {2, 1, &o_rmem, &o_none,  8, 0};
X
XSuch an instruction is two bytes long, and contains one operand. This
Xoperand is a relative memory operand (from the example above), and it must
Xbe shifted to the right 8 bits (which puts it in the second byte of the
Xinstruction exactly). The second operand must have an address even though
Xits not used; o_none fills this requirement.
X
XAll this is leading, of course to the definition of individual
Xinstructions. These are defined in the opdef structures:
X
X.nf
Xtypedef struct opdefitem {      /* Defines an instruction */
X	char *name;                     /* instruction mnemonic */
X	insclass *class;                /* instruction type */
X	Word mask;                      /* mask for first byte of instruction */
X	int (*action) ();               /* action routine for assembly */
X} opdef;
X.fi
X
XEach instruction has a
X.b name
Xthat is recognized during the source code
Xscanning. It also has a pointer to the insclass
X.b class
Xthat defines both what the
Xscanner should expect and how the finished instruction looks. The
X.b mask
Xis a value to be or'ed in with the assembled operand fields to complete the
Xinstruction. It normally contains the instruction-unique bits known as the
Xopcode. Finally, the routine
X.b action
Xdefined to assemble the instruction
Xmust be given. For all normal instructions, the routine is
X.u geninstr ,
Xwhich generates all normal instructions from the table data. This field is
Xdefined primarily so that pseudo-ops can also use the structure.
X
XNow, the opdef table is defined in a slightly different way than the other
Xtables. The entries in the other tables are all referenced by pointers,
Xso their order is of no consequence.  The opdef table (named optab), on
Xthe other hand, must be searched by the assembler. Therefore, each entry
Xis a member of the array optab, and not a separate statement. In addition,
Xthe entries are all arranged in alphabetical order by
X.b name .
X
XAn example of a defined instruction for the 6803 is
X
X.nf
Xopdef optab [] =
X	....
X	"bra"    , &i_rel  , 0x20, geninstr,
X	....
X};
X.fi
X
XThe unconditional branch instruction has its format defined by the i_rel
Xclass of instruction formats (which, as shown above, defines a two byte
Xinstruction with one operand, etc.).  The mask for the first byte of the
Xinstruction (the opcode for a branch) is hex 20. It is generated by the
Xgeninstr routine.
X
XFollowing the definition of optab is the statement
X
X#define oplen sizeof(optab)/sizeof(opdef)
X
Xwhich reveals the size of the optab to asm.c.
X
XWhat of the microprocessors that have two different instructions that may
Xbe used to perform an operation, such as the 6803 that can load a register
Xfrom a memory location with either a two byte relative instruction or a
Xthree byte extended instruction? The native assembler can generate the
Xshortest instruction that will fulfill the effect; so can the generic
Xassembler, under some circumstances. The third set of structures, called
Xchoicedef, is used in this case:
X
X.nf
Xtypedef struct chcitem {        /* Defines the alternatives for instr choices */
X	char *rname;                    /* restrictive mnemonic */
X	char *nname;                    /* non-restrictive mnemonic */
X	int field;                      /* operand that is restricted */
X	int lorange, hirange;           /* range of restriction inclusive */
X	Flag relative;                  /* to current lc, else absolute value */
X} choicedef;
X.fi
X
XAny choicedef that exists (there may be none, if the microprocessor has no
Xsuch overlapping instructions) describes the tradeoff to be made. The
X.b rname
Xis the mnemonic that may be used in the restrictive case of the
Xchoice (i.e., the one that is more desireable, usually leading to a
Xsmaller instruction).
X.b Nname
Xis the mnemonic to be used otherwise.
XPresumably, the two choices are mutually inclusive of all possibilities,
Xso that the nname mnemonic may be substituted in all cases to achieve the
Xdesired result. The field
X.b field
Xis either one or two, describing which
Xfield the choice hinges on. The
X.b lorange and
X.b hirange
Xvalues are the
Xinclusive limits of the values that the field must fall within in order to
Xqualify for the restrictive choice. Finally, the
X.b relative
Xflag staes that
Xthe ranges are or are not relative to the current location counter. (At
Xthis point, the relative flag is not implemented.)
X
XThe infamous example:
X
X	"add"    , (insclass *)&c_add, 0x00, choiceinstr,
X
XThis entry in the optab table defines an pseudo instruction called add. It
Xmay be expanded as the instruction adds, if conditions are right, or as
Xaddz in any case. Instead of pointing to an instruction class, the second
Xentry in the structure is the address of a choice structure, which is cast
Xas an insclass pointer to keep c and lint happy. The mask is defaulted
X(its value is not used), and the generating routine is changed to
Xchoiceinstr, which handles the cases. The choicedef entry pointed to is:
X
Xchoicedef c_add = {"adds" , "addz" , 2, 0, 0xff, NO};
X
XThis defines a choice of either the adds instruction or the addz
Xinstruction to add a memory location to an accumulator. The second field,
Xthe memory reference, is the key: if the reference is greater than or equal
Xto zero, and less than or equal to hex ff (decimal 255), then adds can be
Xused; otherwise only addz is allowed.
X
XAs I said above, the choice mechanism is restricted in the decisions that
Xit can make in attempting to use the shortest instruction.  Since the
Xchoices are all made during the first pass, the expression in the deciding
Xfield must be completely backward-defined.  That means that all symbols in the
Xexpression must be either constants, be predefined (see below) or have
Xbeen defined in the code physically before the line where the choice
Xresides. In addition, all symbols in the expression must be in the same
Xsegment as the code being generated. This is not to say that using a
Xchoice instruction containing a forward reference is an error; rather, the
Xassembler, in the absence of required data to make the decision, will opt
Xfor the "otherwise" form of the instruction, when it could be possible to
Xuse the other. As Captain Kirk says, "Sie la vie."
X
XThe last set of entries in the ops.h file is a group of predefined symbols
Xthat the assembler "knows" about for all assemblies on this
Xmicroprocessor. An example of these definitions is:
X
X.nf
Xsymbol predef[] = {
X	{"ra"        ,    0x0, &o_reg  , (struct seg *)0 },
X	{"rb"        ,    0x1, &o_reg  , (struct seg *)0 },
X	{"eq"        ,    0x7, &o_cond , (struct seg *)0 },
X	{"nc"        ,    0x4, &o_cond , (struct seg *)0 },
X	{""          ,    0x0, &o_none , (struct seg *)0 },
X};
X.fi
X
XThese predefine the symbols ra, rb, eq, and nc for use in instructions
Xthat reference register a, register b, and the branch conditions eq and nc
X(no carry). Each is given a value, points to an operand type (which is not
Xcurrently used), and defined in the null segment (that is, the only
Xpredefined, default segment). Note the null entry at the end of the table.
X
XNow, given the above description it should be possible to define an ops.h
Xfile to generate an assembler for most any machine. This scheme should
Xwork for almost any 8 or 16 bit microprocessor, although its only been
Xused with eights. Restrictions are enforced by the use of a long
Xvariable for expression solution and for instruction compilation, and
Xprobably other things that will become apparant when the assembler is
Xported to some wierd machine.
X
XChoices for instruction format are arbitrary, of course. I use a branch
Xconditional instruction with the conditional code as an operand to reduce
Xthe size of the optab (simply laziness); it would be easy to have
Xindividual branch instructions instead.
X
XSo it goes.
~FUNKY STUFF~



More information about the Mod.sources mailing list