[comp.sources.misc] Z-80 cross assembler for Unix

allbery@ncoast.UUCP (05/27/87)

Here is the source for a Z-80 cross assembler for Unix. I didn't write
it. It was posted to net.sources previously, but I've sped it up and
cleaned it up considerably. I hope it is useful to someone. I have
successfully used it to compile assembler generated by Small-C, until
my CP/M machine broke down.

	Ken

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	as81.c
#	as82.c
#	as83.c
#	as85.c
#	asm.c
#	asm.h
#	asm80.1
#	asm80.doc
# This archive created: Wed May 27 04:10:53 1987
# By:	Ken Yap ()
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(209 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# @(#)makefile        1.1
#
CFLAGS=-O

asm80:	asm.o as81.o as82.o as83.o as85.o
	cc $(CFLAGS) asm.o as81.o as82.o as83.o as85.o -o asm80

asm.o:	asm.h
as81.o: asm.h
as82.o:	asm.h
as83.o:	asm.h
as85.o:	asm.h
SHAR_EOF
if test 209 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 209 characters)'
fi
fi
echo shar: "extracting 'as81.c'" '(5430 characters)'
if test -f 'as81.c'
then
	echo shar: "will not over-write existing file 'as81.c'"
else
cat << \SHAR_EOF > 'as81.c'
/*
* as81.c
* Assemble a line.
*/
#include <stdio.h>
#include "asm.h"

#ifndef lint
static char *sccsid="@(#)as81.c        1.3";
#endif

extern int mkobj, nflag;

/*
* Assemble a line.
*/
asmline()
{
	register struct sym *sp,*lsp;
	register int rs, rd;
	char        *ptr;
	int        n;
	int a, c, opcode;
	char id[NCPS];

	listaddr = dot->s_value;
	listmode = skip ? NLIST : SLIST; /* if skiping then no list */
	lsp = NULL;
	c = getnb();

	do{
		if(c=='\0' || c==';' || c=='\n' || c=='\f') /* + ^L gpv */ 
			break;

		if( c == '-' ){   /* --- gpv 3april'86  */
			mkobj = 0;
			break; 
		}
		if( c == '+') {
			mkobj = nflag;
			break; 
		}

		if( c == '!' )
			c = getnb();
		if(!alpha(c)) {
			if( !skip )
				err('L');
			break;
		}
		getid(c, id);

		if(( c = getnb()) == ':' ) {
			if( skip )
				break;
			sp=install(id, 'd');
			if(pass==0) {
				if(sp->s_type!=S_UND &&
				    (sp->s_flag&SF_ASG)==0)
					sp->s_flag |= SF_MDF;
				sp->s_type = S_ABS;
				sp->s_value = dot->s_value;
			} 
			else {
				if((sp->s_flag&SF_MDF)!=0)
					err('L');
				if(sp->s_type!=S_ABS ||
				    sp->s_value!=dot->s_value)
					err('L');
			}
			listmode = ALIST;
			continue;
		} 
		else
			putback(c);
		if((sp=lookup(id)) == NULL){
			if( !skip ){
				lsp = install( id, '=' );
				c = getnb();
				getid( c , id );
				if((sp = lookup(id)) == NULL){
					err('O');
					break;
				}
			}
			else
				return;
		}
		else if (skip &&(sp->s_type != S_ENDIF))
			return;
		else if((skip || inif)&&(sp->s_type == S_ENDIF)) { 
			skip = 0;
			if(!(--inif))
				inif=0;
			listmode = NLIST;
			return;
		}
		listmode = CLIST;
		if( lsp != NULL ){
			switch( sp->s_type){
			case S_EQU:
			case S_SET:
				if( lsp->s_type != S_UND &&
				    ( lsp->s_flag&SF_ASG) == 0)
					err('L');
				lsp->s_type = S_ABS;
				lsp->s_flag |= SF_ASG;
				lsp->s_value = listaddr = expr();
				listmode = ALIST;        
				lsp = NULL;
				break;
			case S_MACRO:
				lsp = NULL;
				err('M');
				break;
			}
		}
		if( lsp != NULL ){
			if(pass==0) {
				if(lsp->s_type!=S_UND &&
				    (lsp->s_flag&SF_ASG)==0)
					lsp->s_flag |= SF_MDF;
				lsp->s_type = S_ABS;
				lsp->s_value = dot->s_value;
			} 
			else {
				if((lsp->s_flag&SF_MDF)!=0)
					err('L');
				if(lsp->s_type!=S_ABS ||
				    lsp->s_value!=dot->s_value)
					err('p');
			}
			lsp = NULL;
		}
		listmode = CLIST;
		opcode = sp->s_value;
		switch(sp->s_type) {

		case S_EQU:
		case S_SET:
		case S_MACRO:
			break;

		case S_IF:
			inif += 1;
			skip = (expr()==0);
			listmode = NLIST;
			return;

		case S_NAME:
			n = TITLE_LN;
			c=getnb();
			ptr = title;
			while((*ptr++ = getraw())!=c && --n>0);
			*(--ptr) = '\0';
			return;

		case S_ORG:
			listaddr = dot->s_value = expr();
			break;

		case S_ENTRY:
			entaddr = expr();
			return;

		case S_BYTE:
			do {
				if ( (c=getnb())=='\'')
					ascii(c);
				else{
					putback( c );
					a = expr();
					byte(a);
					codeb(a);
				}
			}
			while((c=getnb()) == ',');
			putback(c);
			break;

		case S_WORD:
			do {
				codew(expr());
			} 
			while((c=getnb()) == ',');
			putback(c);
			break;

		case S_BLKB:
			a = expr();
/*
			while(a--)
				codeb(0);
*/
			dot->s_value += a;
			listmode = ALIST;
			break;

		case S_OP1:
			codeb(opcode);
			break;

		case S_OP2:
			a = expr();
			byte(a);
			codeb(opcode);
			codeb(a);
			break;

		case S_OP3:
			rd = getreg(S_REG);
			comma();
			a = expr();
			byte(a);
			code3(opcode, rd);
			codeb(a);
			break;

		case S_OP4:
			rd = getreg(S_REG);
			comma();
			rs = getreg(S_REG);
			codeb(opcode | rd<<3 | rs);
			break;

		case S_OP5:
			if((rd=getreg(S_REG))!=B && rd!=D)
				err('a');
			code4(opcode, rd);
			break;

		case S_OP6:
			if((rd=getreg(S_REG)) == PSW){
				err('R');
			}
			code4(opcode, rd);
			break;

		case S_OP7:
			if((rd=getreg(S_REG)) == SP)
				err('a');
			code4(opcode, rd);
			break;

		case S_OP8:
			a = expr();
			if(a<0 || a>7)
				err('t');
			code3(opcode, a&07);
			break;

		case S_OP9:
			rs = getreg(S_REG);
			if(opcode==INR || opcode==DCR)
				code3(opcode, rs);
			else
				codeb(opcode | rs);
			break;

		case S_OP10:
			if((rd=getreg(S_REG)) == PSW)
				err('a');
			comma();
			a = expr();
			code4(opcode, rd);
			codew(a);
			break;

		case S_OP11:
			a = expr();
			codeb(opcode);
			codew(a);
			break;

		default:
			err('C');
		}        /* end of case statement */
	} 
	while( ( c = getnb()) != '\0' && c != ';' );
}

/*
 * Process the body of .ascii
 * and .asciz pseudo ops.
 * The z flag is true for a
 * .asciz
 */
ascii(delim)
char delim;
{
	register int c;

	while((c=getmap())!='\0' && c!=delim)
		codeb(c);
	if(c == '\0')
		err('S');
}

/*
 * Get a register.
 * Type is either S_REG or S_REGP.
 */
getreg(type)
{
	register struct sym *sp;
	register int c;
	char id[NCPS];

	if(!alpha(c=getnb())) {
		err('R');
		putback(c);
		return(0);
	}
	getid(c, id);
	if((sp=lookupreg(id))==NULL || type != sp->s_type) {
		err('R');
		return(0);
	}
	return(sp->s_value);
}

/*
 * Insure that the value of
 * an expression is a legal
 * byte value.
 * Error if not.
 */
byte(b)
{
	if((b&0200)!=0)
		b |= ~0377;
	if(b>127 || b<-128)
		err('R');
}

/*
 * Check for `,'.
 */
comma()
{
	if(getnb() != ',')
		err('a');
}

/*
 * Build instructions of the
 * general form xxrrrxxx.
 */
code3(x, r)
{
	codeb(x | r<<3);
}

/*
 * Build instructions of the
 * general form xxrrxxxx.
 */
code4(x, r)
{
	codeb(x | (r&6)<<3);
}
SHAR_EOF
if test 5430 -ne "`wc -c < 'as81.c'`"
then
	echo shar: "error transmitting 'as81.c'" '(should have been 5430 characters)'
fi
fi
echo shar: "extracting 'as82.c'" '(2878 characters)'
if test -f 'as82.c'
then
	echo shar: "will not over-write existing file 'as82.c'"
else
cat << \SHAR_EOF > 'as82.c'
/*
 * as82.c
 * Expressions.
 */
#include <stdio.h>
#include "asm.h"

#ifndef lint
static char *sccsid="@(#)as82.c        1.2";
#endif

/*
 * Read an expression.
 * Return its value.
 * All expressions are evaluated
 * left to right; parentheses
 * may be used to alter the order
 * of evaluation.
 */
int
expr()
{
	register int c;
	int l, r;

	if(!term(&l))
		return(0);
	while(validop(c=getopr())) {
		if(!term(&r)) {
			err('e');
			return(l);
		}
		switch(c) {

		case '+':
			l += r;
			break;

		case '-':
			l -= r;
			break;

		case '*':
			l *= r;
			break;

		case '/':
			l /= r;
			break;

		case '&':
			l &= r;
			break;

		case '|':
			l |= r;
			break;
		case '^':
			l ^= r;
			break;
		case '%':
			l %= r;
			break;
		case '<':
			l <<= r;
			break;
		case '>':
			l >>= r;
			break;
		}
	}
	putback(c);
	return(l);
}

/*
 * Check for valid arithmetic
 * operators.
 */
validop(c)
{
	return( instr( c,"+-*/%&|<>^") >= 0);
}

/*
 * Get a term.
 * Store its value in the
 * indicated place.
 * Return true if a term is
 * found.
 * If no term is found no
 * characters are read and
 * false is returned.
 */
int
term(vp)
int *vp;
{
	register struct sym *sp;
	register int c;
	char id[NCPS];

	/*
	 * Number.
	 */
	if(digit(c=getnb())) {
		*vp = getnum(c);
		return(1);
		/*
		 * Id.
		 */
	} 
	else if(alpha(c)) {
		getid(c, id);
		if( strcmp(id,"not")== 0){ /* if the id is 'not' */
			term(vp);
			*vp = ~*vp;
		}
		else {
			sp = install(id, 'e');
			if(sp == NULL )
				err( 'U');
			else if(sp->s_type == S_UND)
				err('u');
			*vp = sp->s_value;
		}
		return(1);

		/*
		 * Unary ops.
		 */
	} 
	else if(c=='-') {
		if(!term(vp)) {
			err('e');
			return(0);
		} 
		*vp = -*vp;
		/*
		 * Parentheses.
		 */
	} 
	else if(c == '(') {
		*vp = expr();
		if(getnb() != ')')
			err('(');
		return(1);

		/*
		 * Character constant.
		 */
	} 
	else if(c == '\'') {
		*vp = getmap();
		if(getnb() != '\'')
		{
			putback(c);
			*vp = *vp+(getmap()<<8);
			if(getnb() != '\'')
				err('\'');
		}
		return(1);

		/*
		 * The current value of DOT
		 */

	} 
	else if ( c == CDOT ){
		*vp = dot->s_value;
		return(1);

		/*
		 * None.
		 */
	} 
	else {
		putback(c);
		return(0);
	}
}

/*
 * getopr()
 *
 * Get a valid operator.
 *
 * Finds non-unix type operators and returns them as valid
 * Unix operators.
 *
 */
getopr()
{
	char ch;
	char id[ NCPS ];
	int index;

	if( validop(ch=getnb()) )
		return(ch);
	if( alpha(ch))
		getid( ch, id);
	else
		return(ch);
	if( strcmp( id , "and") == 0)
		return('&');
	else if( strcmp( id, "or") == 0)
		return('|');
	else if( strcmp( id, "xor") == 0)
		return('^');
	else if( strcmp( id, "mod") == 0)
		return('%');
	else if( strcmp( id, "shr") == 0)
		return('>');
	else if( strcmp( id, "shl") == 0)
		return('<');
	else
		for( index = strlen(id); index==1 ;index--)
			putback( id[ index] );        
	return( id[ 0 ]);
}
SHAR_EOF
if test 2878 -ne "`wc -c < 'as82.c'`"
then
	echo shar: "error transmitting 'as82.c'" '(should have been 2878 characters)'
fi
fi
echo shar: "extracting 'as83.c'" '(2594 characters)'
if test -f 'as83.c'
then
	echo shar: "will not over-write existing file 'as83.c'"
else
cat << \SHAR_EOF > 'as83.c'
/*
 * Lex.
 */
#include <stdio.h>
#include "asm.h"

#ifndef lint
static char *sccsid="@(#)as83.c        1.2";
#endif


/*
 * Get the next non white
 * character.
 */
int _getnb()
{
	register int c;

	while(space(c=getraw()))
		;
	return(c);
}

/*
 * Get next character from
 * the input.
 * Apply string mappings.
 */
getmap()
{
	register int n, c, v;

	if((c=getraw()) == '\\')
		switch(c = getraw()) {

		case 'n':
			c = '\n';
			break;

		case 'r':
			c = '\r';
			break;

		case 't':
			c = '\t';
			break;

		case 'b':
			c = '\b';
			break;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
			v = n = 0;
			while(++n<=3 && c>='0' && c<='7') {
				v = 8*v + c - '0';
				c = getraw();
			}
			putback(c);
			c = v;
			break;

		default:
			putback(c);
			c = '\\';
		}
	return(c);
}

/*
 * Read in an indentifier.
 * Store it (padded with nulls) into the
 * supplied buffer.
 */
getid(c, id)
register int c;
char *id;
{
	register char *p, *end;

	p = id; end = &id[NCPS];
	while(alpha(c) || digit(c) || c== '$') {
		if(p < end){
			if (upper(c))
				c |= ' '; 
			if (c != '$')
				*p++ = c;
		}
		c = getraw();
	}
	*p = '\0';
	putback(c);
}

/*
 * instr( c,str)
 *
 * returns the index to locate c in str if c is in str.
 * if c is not in str then returns -1.
 */

int
instr( c, str )
char c;
char *str;
{
	register char *lp;
	lp = str;
	while( *lp != '\0' )
		if( *lp++ == c )
			return( lp-str-1 );
	return( -1 );
}

/*
 * get a number;
 *
 */
static  char *hexstr = "0123456789ABCDEF";
int
getnum(c)
char c;
{
	static  char *radix = "BDHOQ";                
	static int radv[]={ 10,2,10,16,8,8	};
	char numbstr[ 16 ];
	char *np;

	np = numbstr;
	while( instr( ucase( c ), hexstr) >= 0 ){
		*np++=ucase( c );
		c = getraw();
	}
	*np-- = '\0';
	if( instr( ucase( c ), radix ) < 0 ){
		putback(c );                        /* if terminal not right */
		c = *np;                        /* then the previous is         */
		if( instr( ucase( c ), radix ) >= 0 )
			*np = '\0';
	}
	/*
	 * The following code uses the index into the radix array to
	 * calculate the correct index into radix value table and 
	 * use the value found to determine the correct conversion 
	 * routine.
	 *
         * Think carefully before changing the following code.
	 *
	 */
	return( scnnumb( numbstr, radv[ 1 + instr( ucase( c ), radix )]));
}

int
scnnumb( str ,radix )
char *str;
int        radix;
{
	int v ,d;
	v = 0;
	while( *str )
		if( (d=instr( *str++, hexstr)) >= 0 && d < radix )
			v = v*radix + d;
		else
			return( err( 'N' ), 0 );
	return( v );
}
SHAR_EOF
if test 2594 -ne "`wc -c < 'as83.c'`"
then
	echo shar: "error transmitting 'as83.c'" '(should have been 2594 characters)'
fi
fi
echo shar: "extracting 'as85.c'" '(8133 characters)'
if test -f 'as85.c'
then
	echo shar: "will not over-write existing file 'as85.c'"
else
cat << \SHAR_EOF > 'as85.c'
/*
 * as85.c
 * Tables.
 *         Added 'rim' and 'sim' to keyword list. 3Apr'86 -- gpv 
 */
#include <stdio.h>
#include "asm.h"

/*
 * Assorted variables.
 */

#ifndef lint
static char *sccsid="@(#)as85.c        1.2";
#endif

int	listmode;	/* Listing control */
int	listaddr;	/* Listing control */
int	entaddr;	/* Entry address */
FILE	*src;		/* Source */
FILE	*lst;		/* Listing */
FILE	*obj;		/* Object */
int	lflag;		/* -l flag */
int	nflag;		/* -n flag */
int	sflag;		/* -s flag */
int	pass;		/* Which pass? */
int	skip;		/* skipping code */
int	inif;		/* in an if block */
int	lineno;		/* Line number */
char	*sptr;		/* Source pointer */
char	sbuf[SRCMAX];	/* Source buffer */
char	*cptr;		/* Listing code pointer */
char	cbuf[CLMAX];	/* Listing code buffer */
char	*eptr;		/* Error pointer */
char	ebuf[ERRMAX];	/* Error buffer */
int	cadr;		/* Object address */
int	crec;		/* Object index */
char	crbf[CBMAX];	/* Object buffer */
int	errcnt;		/* error count   */
int	page;		/* current page number */
int	pline;		/* lines on the current page */
char	title[TITLE_LN+1];		/* program listing title */

char	chartype[128]	= {		/* character class */
/* | 00 nul| 01 soh| 02 stx| 03 etx| 04 eot| 05 enq| 06 ack| 07 bel| */
	UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si | */
	UNKNOWN, SPACE, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 10 dle| 11 dc1| 12 dc2| 13 dc3| 14 dc4| 15 nak| 16 syn| 17 etb| */
	UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 18 can| 19 em | 1a sub| 1b esc| 1c fs | 1d gs | 1e rs | 1f us | */
	UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 20 sp | 21  ! | 22  " | 23  # | 24  $ | 25  % | 26  & | 27  ' | */
	SPACE, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 28  ( | 29  ) | 2a  * | 2b  + | 2c  , | 2d  - | 2e  . | 2f  / | */
	UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 30  0 | 31  1 | 32  2 | 33  3 | 34  4 | 35  5 | 36  6 | 37  7 | */
	DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT,
/* | 38  8 | 39  9 | 3a  : | 3b  ; | 3c  < | 3d  = | 3e  > | 3f  ? | */
	DIGIT, DIGIT, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, OTHER,
/* | 40  @ | 41  A | 42  B | 43  C | 44  D | 45  E | 46  F | 47  G | */
	OTHER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER,
/* | 48  H | 49  I | 4a  J | 4b  K | 4c  L | 4d  M | 4e  N | 4f  O | */
	UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER,
/* | 50  P | 51  Q | 52  R | 53  S | 54  T | 55  U | 56  V | 57  W | */
	UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER,
/* | 58  X | 59  Y | 5a  Z | 5b  [ | 5c  \ | 5d  ] | 5e  ^ | 5f  _ | */
	UPPER, UPPER, UPPER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
/* | 60  ` | 61  a | 62  b | 63  c | 64  d | 65  e | 66  f | 67  g | */
	UNKNOWN, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER,
/* | 68  h | 69  i | 6a  j | 6b  k | 6c  l | 6d  m | 6e  n | 6f  o | */
	LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER,
/* | 70  p | 71  q | 72  r | 73  s | 74  t | 75  u | 76  v | 77  w | */
	LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER,
/* | 78  x | 79  y | 7a  z | 7b  { | 7c  | | 7d  } | 7e  ~ | 7f del| */
	LOWER, LOWER, LOWER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,
};

struct sym	*hashtbl[HASH];		/* symbol table hashbuckets */

/*
 * User symbol table.
 * The first item must be '$'.
 */
struct sym ust[USERMAX] = {"$", NULL,NULL, S_ABS, SF_ASG, 0};

/*
 * Opcode table.
 * Also contains pseudo operations.
 */
struct sym pst[] = {
	"aci", NULL, NULL, S_OP2, 0, 0316, NULL, 
	"adc", NULL, NULL, S_OP9, 0, 0210, NULL, 
	"add", NULL, NULL, S_OP9, 0, 0200, NULL, 
	"adi", NULL, NULL, S_OP2, 0, 0306, NULL, 
	"ana", NULL, NULL, S_OP9, 0, 0240, NULL, 
	"ani", NULL, NULL, S_OP2, 0, 0346, NULL, 
	"call", NULL, NULL, S_OP11, 0, 0315, NULL, 
	"cc", NULL, NULL, S_OP11, 0, 0334, NULL, 
	"cm", NULL, NULL, S_OP11, 0, 0374, NULL, 
	"cma", NULL, NULL, S_OP1, 0, 0057, NULL, 
	"cmc", NULL, NULL, S_OP1, 0, 0077, NULL, 
	"cmp", NULL, NULL, S_OP9, 0, 0270, NULL, 
	"cnc", NULL, NULL, S_OP11, 0, 0324, NULL, 
	"cnz", NULL, NULL, S_OP11, 0, 0304, NULL, 
	"cp", NULL, NULL, S_OP11, 0, 0364, NULL, 
	"cpe", NULL, NULL, S_OP11, 0, 0354, NULL, 
	"cpi", NULL, NULL, S_OP2, 0, 0376, NULL, 
	"cpo", NULL, NULL, S_OP11, 0, 0344, NULL, 
	"cz", NULL, NULL, S_OP11, 0, 0314, NULL, 
	"daa", NULL, NULL, S_OP1, 0, 0047, NULL, 
	"dad", NULL, NULL, S_OP6, 0, 0011, NULL, 
	"db", NULL, NULL, S_BYTE, 0, 0, NULL, 
	"dcr", NULL, NULL, S_OP9, 0, 0005, NULL, 
	"dcx", NULL, NULL, S_OP6, 0, 0013, NULL, 
	"di", NULL, NULL, S_OP1, 0, 0363, NULL, 
	"ds", NULL, NULL, S_BLKB, 0, 0, NULL, 
	"dw", NULL, NULL, S_WORD, 0, 0, NULL, 
	"ei", NULL, NULL, S_OP1, 0, 0373, NULL, 
	"end", NULL, NULL, S_ENTRY, 0, 0, NULL, 
	"endif", NULL, NULL, S_ENDIF, 0, 0, NULL, 
	"endm", NULL, NULL, S_ENDM, 0, 0, NULL, 
	"equ", NULL, NULL, S_EQU, 0, 0, NULL, 
	"hlt", NULL, NULL, S_OP1, 0, 0166, NULL, 
	"if", NULL, NULL, S_IF, 0, 0, NULL, 
	"in", NULL, NULL, S_OP2, 0, 0333, NULL, 
	"inr", NULL, NULL, S_OP9, 0, 0004, NULL, 
	"inx", NULL, NULL, S_OP6, 0, 0003, NULL, 
	"jc", NULL, NULL, S_OP11, 0, 0332, NULL, 
	"jm", NULL, NULL, S_OP11, 0, 0372, NULL, 
	"jmp", NULL, NULL, S_OP11, 0, 0303, NULL, 
	"jnc", NULL, NULL, S_OP11, 0, 0322, NULL, 
	"jnz", NULL, NULL, S_OP11, 0, 0302, NULL, 
	"jp", NULL, NULL, S_OP11, 0, 0362, NULL, 
	"jpe", NULL, NULL, S_OP11, 0, 0352, NULL, 
	"jpo", NULL, NULL, S_OP11, 0, 0342, NULL, 
	"jz", NULL, NULL, S_OP11, 0, 0312, NULL, 
	"lda", NULL, NULL, S_OP11, 0, 0072, NULL, 
	"ldax", NULL, NULL, S_OP5, 0, 0012, NULL, 
	"lhld", NULL, NULL, S_OP11, 0, 0052, NULL, 
	"lxi", NULL, NULL, S_OP10, 0, 0001, NULL, 
	"macro", NULL, NULL, S_MACRO, 0, 0, NULL, 
	"mov", NULL, NULL, S_OP4, 0, 0100, NULL, 
	"mvi", NULL, NULL, S_OP3, 0, 0006, NULL, 
	"nop", NULL, NULL, S_OP1, 0, 0000, NULL, 
	"ora", NULL, NULL, S_OP9, 0, 0260, NULL, 
	"org", NULL, NULL, S_ORG, 0, 0, NULL, 
	"ori", NULL, NULL, S_OP2, 0, 0366, NULL, 
	"out", NULL, NULL, S_OP2, 0, 0323, NULL, 
	"pchl", NULL, NULL, S_OP1, 0, 0351, NULL, 
	"pop", NULL, NULL, S_OP7, 0, 0301, NULL, 
	"push", NULL, NULL, S_OP7, 0, 0305, NULL, 
	"ral", NULL, NULL, S_OP1, 0, 0027, NULL, 
	"rar", NULL, NULL, S_OP1, 0, 0037, NULL, 
	"rc", NULL, NULL, S_OP1, 0, 0330, NULL, 
	"ret", NULL, NULL, S_OP1, 0, 0311, NULL, 
	"rim", NULL, NULL, S_OP1, 0, 0040, NULL, 
	"rlc", NULL, NULL, S_OP1, 0, 0007, NULL, 
	"rm", NULL, NULL, S_OP1, 0, 0370, NULL, 
	"rnc", NULL, NULL, S_OP1, 0, 0320, NULL, 
	"rnz", NULL, NULL, S_OP1, 0, 0300, NULL, 
	"rp", NULL, NULL, S_OP1, 0, 0360, NULL, 
	"rpe", NULL, NULL, S_OP1, 0, 0350, NULL, 
	"rpo", NULL, NULL, S_OP1, 0, 0340, NULL, 
	"rrc", NULL, NULL, S_OP1, 0, 0017, NULL, 
	"rst", NULL, NULL, S_OP8, 0, 0307, NULL, 
	"rz", NULL, NULL, S_OP1, 0, 0310, NULL, 
	"sbb", NULL, NULL, S_OP9, 0, 0230, NULL, 
	"sbi", NULL, NULL, S_OP2, 0, 0336, NULL, 
	"set", NULL, NULL, S_SET, 0, 0, NULL, 
	"shld", NULL, NULL, S_OP11, 0, 0042, NULL, 
	"sim", NULL, NULL, S_OP1, 0, 0060, NULL, 
	"sphl", NULL, NULL, S_OP1, 0, 0371, NULL, 
	"sta", NULL, NULL, S_OP11, 0, 0062, NULL, 
	"stax", NULL, NULL, S_OP5, 0, 0002, NULL, 
	"stc", NULL, NULL, S_OP1, 0, 0067, NULL, 
	"sub", NULL, NULL, S_OP9, 0, 0220, NULL, 
	"sui", NULL, NULL, S_OP2, 0, 0326, NULL, 
	"title", NULL, NULL, S_NAME, 0, 0, NULL, 
	"xchg", NULL, NULL, S_OP1, 0, 0353, NULL, 
	"xra", NULL, NULL, S_OP9, 0, 0250, NULL, 
	"xri", NULL, NULL, S_OP2, 0, 0356, NULL, 
	"xthl", NULL, NULL, S_OP1, 0, 0343, NULL, 
};

/*
 * Register symbol table
 */
struct sym rst[] = {
	"a", NULL, NULL, S_REG, 0, 7, NULL, 
	"b", NULL, NULL, S_REG, 0, 0, NULL, 
	"c", NULL, NULL, S_REG, 0, 1, NULL, 
	"d", NULL, NULL, S_REG, 0, 2, NULL, 
	"e", NULL, NULL, S_REG, 0, 3, NULL, 
	"h", NULL, NULL, S_REG, 0, 4, NULL, 
	"l", NULL, NULL, S_REG, 0, 5, NULL, 
	"m", NULL, NULL, S_REG, 0, 6, NULL, 
	"psw", NULL, NULL, S_REG, 0, PSW, NULL, 
	"sp", NULL, NULL, S_REG, 0, SP, NULL
};

/*
 * Size of tables.
 * Must be here!
 */
int pstsiz = (sizeof(pst)/sizeof(pst[0]));
int rstsiz = (sizeof(rst)/sizeof(rst[0]));
SHAR_EOF
if test 8133 -ne "`wc -c < 'as85.c'`"
then
	echo shar: "error transmitting 'as85.c'" '(should have been 8133 characters)'
fi
fi
echo shar: "extracting 'asm.c'" '(11527 characters)'
if test -f 'asm.c'
then
	echo shar: "will not over-write existing file 'asm.c'"
else
cat << \SHAR_EOF > 'asm.c'
/*
 * asm.c
 * Mainline.
 *
 * Revisions:
 * 
 * ------------------------------------------------------------------------
 * Simple changes by Gordon P. Vickers @ Sigfac on 3 April '86:
 *        edited as83.c so '@' will be allowed in label, variable fields.
 *        edited as85.c, add 'rim' and 'sim' to keyword list.
 *        edited as81.c, asm.c: add variable 'mkobj' to allow source file
 *        contents to turn on/off hex file generation. 
 *  NOTE: for specific changes use the search key: gpv
 * -----------------------------------------------------------------------
 *
 */
#include <stdio.h>
#include "asm.h"

#ifndef lint
static char *sccsid="@(#)asmain.c        1.4";
#endif

char *malloc();

/*
 * This is the mainline.
 * It scans the command line,
 * collects up a source file,
 * sets option flags and calls
 * the assembler proper.
 */
int mkobj = 1;                  /* hex file generation switch. - gpv */
static int cflag = 0;                /* cross reference on flag        */

main(argc, argv)
char *argv[];
{
	register int i, c;
	register char *p;
	char *file;

	file = NULL;
	for(i=1; i<argc; ++i) {
		p = argv[i];
		if(*p++ == '-') {
			while(c = *p++)
				switch(c) {

				case 'l':
				case 'L':
					++lflag;
					break;
				case 'c':
				case 'C':
					++lflag;
					++cflag;
					break;

				case 'n':
				case 'N':
					++nflag;
					break;

				case 's':
				case 'S':
					++lflag;
					++sflag;
					break;
				default:
					usage();
				}
		}
		else
		{
			file = argv[i];
			if(file == NULL)
				usage();
			assemble(file);
		}
	}
}

/*
 * Assemble a file.
 */

assemble(file)
char *file;
{
	char fn[40];
	int index;

	strncpy(title,file,20);
	for ( index = 0 ; index < HASH ; index ++)
		hashtbl[ index ] = NULL;
	name(fn, file, "asm", 0);
	if((src=fopen(fn, "r")) == NULL) {
		fprintf(stderr, "%s: cannot open\n", fn);
		exit(1);
	}
	if(lflag) {
		name(fn, file, "lst", 1);
		if((lst=fopen(fn, "w")) == NULL) {
			fprintf(stderr, "%s: cannot create\n", fn);
			exit(1);
		}
	}
	if(mkobj) {  /* mkobj - 3April'86 -- gpv */
		name(fn, file, "hex", 1);
		if((obj=fopen(fn, "w")) == NULL) {
			fprintf(stderr, "%s: cannot create\n", fn);
			exit(1);
		}
	}
	page = 1;
	for(pass=0; pass<2; ++pass) {
		skip = 0;                         /* not currently skipping*/
		rewind(src);
		errcnt = 0;
		lineno = 0;
		dot->s_type = S_ABS;
		dot->s_flag = SF_ASG;
		dot->s_value = 0;
		if(pass && lflag )
			top(0);

		while(fgets(sbuf, SRCMAX , src) != NULL) {
			++lineno;
			sptr = sbuf;
			cptr = cbuf;
			eptr = ebuf;
			asmline();
			if(pass) {
				outerrors();
				if(lflag)
					outlisting();
			}
		}
	}
	if(errcnt)
		printf(" Total errors = %5d\n",errcnt);
	if(lflag){
		if(errcnt){
			fprintf(lst,"\n Total number of errors = %5d \n",errcnt)
				;
		}
		table();
		fclose(lst);
	}
	if(mkobj){ /* mkobj 3 April'86 -- gpv */
		cflush(1);
		fclose(obj);
	}
	printf(" Total bytes assembled = %04X\n", dot->s_value);
	fclose(src);
}

/*
 * If the user screws up, put out
 * a usage message.
 * Then quit.
 * Not much sense staying around.
 */
usage()
{
	fprintf(stderr, "Usage:%4s  [-ln] file file ...\n",TASK);
	fprintf(stderr, "where: \n");
	fprintf(stderr, "      l = make a listing \n");
	fprintf(stderr, " and  n = don't make an object file\n");
	exit(1);
}

/*
 * Build RSX file names.
 * The mode argument is either 0
 * which means default, or 1 which
 * means replace with.
 */
name(fn, file, type, mode)
char *fn, *file, *type;
{
	register char *p1, *p2;
	register int c;

	p1 = fn;
	p2 = file;
	while((c = *p2++) && c!='.')
		*p1++ = c;
	if(mode == 0) {
		if(c == '.') {
			do {
				*p1++ = c;
			} 
			while(c = *p2++);
		} 
		else {
			*p1++ = '.';
			p2 = type;
			while(c = *p2++)
				*p1++ = c;
		}
	} 
	else {
		*p1++ = '.';
		p2 = type;
		while(c = *p2++)
			*p1++ = c;
	}
	*p1 = '\0';
}

/*
 * Output code byte.
 * Save it in the per line
 * buffer for outlisting.
 * Update dot.
 */
codeb(b)
	int	b;
{
	b &= 0377;
	if(cptr < &cbuf[CLMAX])
		*cptr++ = b;
	if(pass && mkobj) {  /* mkobj 3 April'86 -- gpv */
		if(crec>=CBMAX || cadr+crec!=dot->s_value) {
			cflush(0);
			cadr = dot->s_value;
		}
		crbf[crec++] = b;
	}
	++dot->s_value;
}

/*
 * Output a word.
 * Low then high.
 */
codew(w)
{
	if(BSWAP)codeb(w>>8);
	codeb(w);
	if(!BSWAP)codeb(w>>8);
}

/*
 * Signal error.
 * Add it to the error buffer
 * if not already there.
 */
err(c)
{
	register char *p;

	errcnt+=1;
	p = ebuf;
	if(eptr == &ebuf[ERRMAX-1]) c ='*';
	while(p < eptr)
		if(*p++ == c)
			return;
	*p++ = c;
	if ( p> &ebuf[ERRMAX])
		--p;
	eptr = p;
}

/*
 * Format a line for the
 * listing.
 * More work than you would
 * think.
 * Only called if -l.
 */
outlisting()
{
	register int nbytes;
	register char *cp;
	int w1, w2, w3, w4;

	if(listmode == NLIST)
		return;
	for(cp = eptr; cp < &ebuf[ERRMAX-1]; *cp++ = ' ');
	*cp='\0';
	if(!(--pline ))
		top(1);
	if(listmode == SLIST)
		fprintf(lst, "%.6s      ", ebuf);
	else
		fprintf(lst, "%.6s %04X ", ebuf, listaddr);
	if(listmode == ALIST)
		fprintf(lst, "%9s%4d %s", "", lineno, sbuf);
	else {
		nbytes = cptr-cbuf;
		w1 = cbuf[0]&0377;
		w2 = cbuf[1]&0377;
		w3 = cbuf[2]&0377;
		w4 = cbuf[3]&0377;
		switch(nbytes) {
		case 0:
			fprintf(lst, "%9s", ""); 
			break;
		case 1:
			fprintf(lst, "%02X%7s", w1, ""); 
			break;
		case 2:
			fprintf(lst, "%02X%02X%5s", w1, w2, ""); 
			break;
		case 3:
			fprintf(lst, "%02X%02X%02X%3s", w1, w2, w3,""); 
			break;
		default:
			fprintf(lst, "%02X%02X%02X%02X%1s", w1, w2, w3,w4,"");
		}
		fprintf(lst, "%4d\t%s", lineno, sbuf);
		cp = &cbuf[4];
		while((nbytes -= 4) > 0) {
			if( --pline < 0  )
				top(1);
			listaddr += 4;
			fprintf(lst, "%5s%04X ", "",listaddr );
			switch(nbytes) {
			case 0:        
				break;
			case 1:
				w1 = cp[0]&0377;
				fprintf(lst, "%02X\n", w1);
				break;
			case 2:
				w1 = cp[0]&0377;
				w2 = cp[1]&0377;
				fprintf(lst, "%02X%02X\n", w1, w2);
				break;
			case 3:
				w1 = cp[0]&0377;
				w2 = cp[1]&0377;
				w3 = cp[2]&0377;
				fprintf(lst, "%02X%02X%02X\n", w1, w2, w3);
				break;
			default:
				w1 = cp[0]&0377;
				w2 = cp[1]&0377;
				w3 = cp[2]&0377;
				w4 = cp[3]&0377;
				fprintf(lst, "%02X%02X%02X%02X\n", w1, w2, w3,w4);
			}
			cp += 4;
		}
	}
}

/*
 * Write errors to the tty.
 */
outerrors()
{
	if( lflag )
		return;
	if( eptr > ebuf ){
		*eptr='\0';
		printf("%s\t%04d\t%s", ebuf, lineno, sbuf);
	}
}

/*
 * Flush the binary code
 * buffer.
 */

cflush(lf)
int lf;
{
	int chksum;                /* checksum for hex file format */
	register int i;

	if(crec == 0)
		return;
	putc(':', obj);
	ohb(obj, crec & 0xff);
	ohb(obj, (cadr >> 8) & 0xff);
	ohb(obj, cadr & 0xff);
	putc('0', obj);
	putc('0', obj);
	chksum = 0;
	chksum += crec;
	chksum += (( cadr >> 8)& 0xFF);
	chksum += ( cadr & 0xFF);
	for(i=0; i<crec; ++i){
		ohb(obj, crbf[i] & 0xff);
		chksum += crbf[ i ]&0xFF;
	}
	ohb(obj, (0-(chksum & 0xff)) & 0xff);
	putc('\n', obj);
	crec = 0;
	if(lf)
		fprintf(obj,":00000000\n");
}

ohb (filep, byte)
	FILE		*filep;
	int		byte;
/*
**	More efficient than using the general purpose fprintf
*/
{
	static char	hex[] = "0123456789ABCDEF";

	putc ( hex[(byte >> 4) & 0xf], filep );
	putc ( hex[byte & 0xf], filep );
}

/* 
 * Print out the user symbol table
 */
table()
{
	register struct sym *mine ;
	register struct hu *howu;
	int line,indx,count;

	count =line = 0;
	page = 1;
	fprintf(lst,"\f\n%-40s  Symbol table dump \t\t  Page %3d\n\n\n",
	title,page++) ;
	for( indx = 0 ; indx < HASH ; indx++){
		for(mine = hashtbl[ indx ]; mine != NULL; mine = mine->right ){
			if( line >= mxline ){
				fprintf(lst,
				"\f\n Symbol table dump page %3d\n\n\n"
				    ,page++);
				line = 0;
			}
			fprintf(lst,"%10s = %04X  ",mine->s_name,mine->s_value);
			if( cflag ){
				for( howu = mine->howused; howu != NULL ;
                                                 howu = howu->next ){
					    if( count >= 10 ){
						fprintf(lst,"\n                   ");
						line++;
						count = 0;
					}
					fprintf(lst,"%6d %c :", howu->line, howu->how );
					count++;
				}
				count = 0;
				line++;
				fprintf(lst,"\n");
			}
			else{ 
				if( count >= 4 ){
					line++;
					count = 0;
					fprintf(lst,"\n");
				}
				count++;
			}
		}
	}
	fprintf(lst,"\f\n");
	fflush(lst);
}

/*
 *
 * Top - Print the label at the top of the page
 *
 */

top(mode)
int mode;
{

	if(mode)putc('\f',lst);
	pline = mxline;
	fprintf(lst,"\n %-40s KSE cross assembler for the %-5s",title,MICRO);
	fprintf(lst,"      page %3d",page++);
	fprintf(lst," \n\n\n");
}

int
hash( id )
char *id;
{
	register unsigned	u;
	register char		*p;

	u = 0; p = id;
	while (*p != '\0')
		u = (u << 1) + *p++;
	return (u % HASH);
}

struct sym *
lkup( id , howu )
char *id;
char howu;
{
	struct sym *np;
	struct hu  *usage;

	for( np = hashtbl[hash(id)]; np != NULL; np = np->right ){
		if( strcmp( id, np->s_name ) == 0){
			if( cflag ){
				for( usage = np->howused;
                                usage->line != lineno && usage->next != NULL;
                                usage = usage->next )
					    ;
				if( usage->line != lineno ){
					usage->next =(struct hu *) 
						malloc( sizeof( *usage));
					if( usage->next != NULL){
						usage->next->line = lineno;
						usage->next->how  =howu;
						usage->next->next = NULL;
					} 
				}
			}
			return( np );
		}
	}
	return(NULL );
}

struct sym *
install( id , howu )
char *id;
char howu;
{
	struct sym *np,*lp;
	struct sym *lkup();
	int hashval;

	if( (np = lkup( id , howu ) ) == NULL ) {
		np= ( struct sym *)malloc( sizeof( *np ));
		if(np == NULL ){
			fprintf(stderr,"in line %d ",lineno);
			fprintf(stderr,"Symbol table overflow\n");
			return( NULL );
		}
		np->right = NULL;
		np->left  = NULL;
		np->s_type= 0;
		np->s_flag= 0;
		np->s_value = 0;
		if( cflag ){
			np->howused = (struct hu *)malloc( sizeof( *np->howused));
			if( np->howused != NULL ){
				np->howused->how = howu;
				np->howused->line = lineno;
				np->howused->next = NULL;
			}
		}
		strcpy(np->s_name,id);
		hashval = hash( id );
		if( hashtbl[ hashval ] == NULL ){
			hashtbl[ hashval ] = np;
		}
		else if( strcmp( id , hashtbl[hashval]->s_name ) > 0 ){
			hashtbl[ hashval ]->left = np;
			np->right = hashtbl[ hashval ];
			hashtbl[ hashval] = np;
		} 
		else
			for( lp = hashtbl[hashval];lp != NULL;lp = lp->right) {
				if( lp->right == NULL ){
					lp->right = np;
					np->left  = lp;
					break;        
				}
				else if ( strcmp( id, lp->right->s_name ) < 0){
					np->right = lp->right;
					lp->right->left = np;
					lp->right = np;
					np->left  = lp;
					break;
				}
			}
	}
	return( np );
}

/*
 * Lookup id in pst.
 */
struct sym *
lookup(id)
char *id;
{
	register int		i, lo, hi, mid;
	register char		*p, *name;
	register struct sym	*s;

	for (lo = 0, hi = pstsiz - 1; lo <= hi; )
	{
		mid = (lo + hi) / 2;
		p = id;
		name = pst[mid].s_name;
		while (*p != '\0' && *p == *name)
			++p, ++name;
		if ((i = *p - *name) == 0)
			break;
		else if (i < 0)
			hi = mid - 1;
		else
			lo = mid + 1;
	}
	if (lo > hi)
		return( NULL);
	else
		return( &pst[mid] );
}

/*
 * Lookup id in rst.
 */
struct sym *
lookupreg(id)
char *id;
{
	register int		i, lo, hi, mid;
	register char		*p, *name;

	for (lo = 0, hi = rstsiz - 1; lo <= hi; )
	{
		mid = (lo + hi) / 2;
		p = id;
		name = rst[mid].s_name;
		while (*p != '\0' && *p == *name)
			++p, ++name;
		if ((i = *p - *name) == 0)
			break;
		else if (i < 0)
			hi = mid - 1;
		else
			lo = mid + 1;
	}
	if (lo > hi)
		return( NULL);
	else
		return( &rst[mid] );
}
SHAR_EOF
if test 11527 -ne "`wc -c < 'asm.c'`"
then
	echo shar: "error transmitting 'asm.c'" '(should have been 11527 characters)'
fi
fi
echo shar: "extracting 'asm.h'" '(5187 characters)'
if test -f 'asm.h'
then
	echo shar: "will not over-write existing file 'asm.h'"
else
cat << \SHAR_EOF > 'asm.h'
/*
 * @(#)asm.h        1.3
 * Header.
 *
 * General assembler header. With this structure you
 * can define the majority of the simple assembler
 * dependent variables.
 *
 * David A Klotzbach
 *
 * Sizes of tables.
 */

#define NCPS	16	/* Characters per symbol */
#define CLMAX	256	/* Code bytes, line */
#define CBMAX	16	/* Code bytes, object */
#define USERMAX	2	/* User names */
#define SRCMAX	128	/* Source line length */
#define ERRMAX	5	/* Maximum errors per line +1 */
#define FALSE	0	/* not true */
#define TRUE	1	/* You should be able to guess */
#define mxline	9999	/* maximum lines per page*/

#define dot	(&ust[0])	/* Location counter */
#define CDOT	'$'	/* Character that means current PC */
#define BSWAP	0	/* 1 = High first; 0 = Low first */
#define MICRO	"8080"
#define TASK	"ASM80"	/* The task that is to be run */
#define HASH	1009

/*
 * Listing control modes.
 * Go in `listmode'.
 */
#define NLIST	0	/* No list */
#define SLIST	1	/* Source only list */
#define ALIST	2	/* Just address */
#define CLIST	3	/* Address and code */

/*
 * Symbol table structure.
 * Used in both the user symbol table and
 * the opcode table.
 */
struct hu{
	struct hu	*next;	/* Next usage */
	int	line;	/* Line used */
	char	how;	/* How it was used */
};

#define	U_DEFINE	'd'	/* Defined */
#define U_EXPR	'e'	/* used in expres */
#define U_EQU	'='	/* EQU or SET */

struct sym {
	char	s_name[NCPS];	/* Name */
	struct	sym *left;	/* left member */
	struct	sym *right;	/* right member */
	char	s_type;	/* Type */
	char	s_flag;	/* Some flags */
	int	s_value;	/* Value */
	struct	hu	*howused;	/* First entry in */
};

struct sym *hashtbl[ ];	/* Hash buckets for symbol table */

#define	B	0
#define C	1
#define D	2
#define E	3
#define H	4
#define L	5
#define M	6
#define A	7
#define PSW	6
#define SP	7
#define INR	4
#define DCR	5

/*
 * Types.
 */
#define S_UND	0	/* Undefined */
#define S_ABS	1	/* Absolute */
#define S_REG	2	/* Register */
#define S_REGP	3	/* Register pair */
#define S_ENTRY	4	/* .entry */
#define S_BYTE	5	/* .byte */
#define S_WORD	6	/* .word */
#define S_ASCII	7	/* .ascii */
#define S_ASCIZ	8	/* .asciz */
#define S_BLKB	9	/* .blkb */
#define S_OP1	10	/* Opcode */
#define S_OP2	11	/* Accumulator and Memory */
#define S_OP3	12	/* Index Register and stack */
#define S_OP4	13	/* Branch */
#define S_OP5	14	/* Jump */
#define S_OP6	15	/* Condition codes */
#define S_OP7	16	/* limitted to extnd and indexed */
#define S_OP8	17	/* limitted to direct,extnd and indx */
#define S_OP9	18	/* */
#define S_OP10	19	/* */
#define S_OP11	20	/* */
#define S_EQU	21	/* */
#define S_SET	22	/* */
#define	S_NAME	23	/* Name the program listing */
#define S_ORG	24	/* Program section origin statement */
#define	S_IF	100	/* IF directive */
#define S_ENDIF	102	/* ENDIF directive */
#define S_MACRO	200	/* Define a macro */
#define S_ENDM	202	/* Define macro end */

/*
 * Flags.
 */
#define SF_MDF	01	/* Multiply defined */
#define SF_ASG	02	/* Defined by assignment */
#define SF_MAC	04	/* is a MACRO definition */

/*
 * Variables.
 */
#define	TITLE_LN	40	/* Length of the title */
extern	struct	sym pst[];	/* Opcode table */
extern	int	pstsiz;		/* size of pst */
extern	struct	sym rst[];	/* Register table */
extern	int	rstsiz;		/* size of pst */
extern	struct	sym ust[];	/* User symbols */
extern	struct	sym *uptr;	/* End of ust */
extern	int	page;	/* Current page number */
extern	int	pline;	/* Lines on the current page */
extern	int	listmode;	/* Listing control */
extern	int	listaddr;	/* Listing control */
extern	int	entaddr;	/* .entry address */
extern	FILE	*src;	/* Source */
extern	FILE	*lst;	/* Listing */
extern	FILE	*obj;	/* Object */
extern	int	lflag;	/* -l flag */
extern	int	nflag;	/* -n flag */
extern	int	sflag;	/* -s flag */
extern	int	pass;	/* Which pass? */
extern	int	skip;	/* Skipping code lines */
extern	int	inif;	/* in an if block of inif */
extern	int	lineno;	/* Line number */
extern	char	*sptr;	/* Source pointer */
extern	char	sbuf[];	/* Source buffer */
extern	char	*cptr;	/* Listing code pointer */
extern	char	cbuf[];	/* Listing code buffer */
extern	char	*eptr;	/* Error pointer */
extern	char	ebuf[];	/* Error buffer */
extern	int	cadr;	/* Object address */
extern	int	crec;	/* Object index */
extern	char	crbf[];	/* Object buffer */
extern	char	title[];	/* Title buffer */
extern	int	errcnt;	/* number of errors encounterd */
extern	int	optype;	/* Type of current operand */

#define	getraw()	(*sptr != '\0' ? *sptr++ : '\0')
#define	putback(c)	((c) != '\0' && --sptr < sbuf && abort())
#define	getnb()		(space(*sptr) ? _getnb() : getraw())

#define UNKNOWN 0
#define	SPACE	0x01
#define	LOWER	0x02
#define UPPER   0x04
#define	OTHER	0x08
#define	ALPHA	(LOWER|UPPER|OTHER)
#define DIGIT   0x10

extern	char	chartype[];

#define	space(c)	(chartype[(c)] & SPACE)
#define	lower(c)	(chartype[(c)] & LOWER)
#define	upper(c)	(chartype[(c)] & UPPER)
#define	alpha(c)	(chartype[(c)] & ALPHA)
#define	digit(c)	(chartype[(c)] & DIGIT)

#define	ucase(c)	(lower(c) ? ((c) - ('a' - 'A')) : c)

/*
 * Functions.
 */
extern	struct	sym *lookup();	/* Search pst */
extern	struct	sym *lookupreg();	/* Search rst */
extern	struct	sym *install();	/* Search ust */
SHAR_EOF
if test 5187 -ne "`wc -c < 'asm.h'`"
then
	echo shar: "error transmitting 'asm.h'" '(should have been 5187 characters)'
fi
fi
echo shar: "extracting 'asm80.1'" '(531 characters)'
if test -f 'asm80.1'
then
	echo shar: "will not over-write existing file 'asm80.1'"
else
cat << \SHAR_EOF > 'asm80.1'
.TH ASM80 1 "1 November 1986"
.SH NAME
asm80 \- Intel 8080 assembler
.SH SYNOPSIS
.B asm80
[
.B \-cln
]
file
.SH DESCRIPTION
.I Asm80
is an assembler for Intel 8080 assembler programs.
The input is taken from file.asm
and the Intel hex output is in file.hex.
The
.B \-l
flag enables the listing output, which goes to file.lst.
If the
.B \-c
flag is specified, cross references are also generated.
The
.B \-n
flag supresses hex output.
.PP
For example,
.sp
.ti +5
asm80 -l foo
.sp
assembles foo.asm, generating foo.hex and foo.lst.
SHAR_EOF
if test 531 -ne "`wc -c < 'asm80.1'`"
then
	echo shar: "error transmitting 'asm80.1'" '(should have been 531 characters)'
fi
fi
echo shar: "extracting 'asm80.doc'" '(12964 characters)'
if test -f 'asm80.doc'
then
	echo shar: "will not over-write existing file 'asm80.doc'"
else
cat << \SHAR_EOF > 'asm80.doc'




                       A Cross Assembler            

                    for the Intel 8080-8085

                       With CPM[tm] syntax
                             - by -

                       David A. Klotzbach





                          Introduction





     ASM80  is  a  two  pass assembler for the Intel 8080 and the
     8085. The input syntax is, in general, similar in  style  to
     the  CPM[tm]  assembler.  It  is  also  possible  to use the
     assembler for the z80 since it  is  object  code  compatible
     with the 8080.





     CP/M is a registered trademark of Digital Research Inc.



          ASM80                                            User Manual


                                The Cross Assembler







             Usage 

               asm80 is invoked from as follows:
                           asm80 [-n] [-l] file [file ...]

               The  specified  files  are assembled separately and the
               object code is placed in a file (in the same directory)
               having the same name as the  source  file  but  with  a
               filetype  of HEX. The default filetype for source files
               is ASM. File type must not be specified.
               
               The  optional  -n  argument  causes  the  assembler  to
               produce  no  object file. This option is primarily used
               to prevent creating a lot of useless object files  when
               debugging the assembler; however, it may be of use when
               one wishes to simply check a file for errors.
               
               The optional -l argument causes the assembler to create
               a listing file of name <file>.LST.
               
               The  object  file  is  in standard CP/M HEX format. The
               title of the object file is always set to the first six
               characters of the source file name.


             Lexical Convention

               Assembler tokens  consist  of  identifiers  ('symbols',
               'names','labels') , constants and operators.


             Identifier

               An  identifier  consists  of a sequence of alphanumeric
               characters (including the period '.', at sign (@), and
               the  question mark  '?')  the first of which may not
               be numeric. Only the first nine characters of the name
               are  significant; the  rest  are  discarded.
               Upper  and  lower  case are treated as the same.


                                     - 3 -                            


          ASM80                                            User Manual


             Constants

               All numeric constants, octal, binary, hex  or  decimal,
               must  start  with a a digit 0 through 9. A HEX constant
               is a sequence of digits and the alpha characters A,  B,
               C,  D, E, and F. The number is truncated to 16 bits and
               interpreted in twos complement notation.  If  the  base
               type symbol is omitted the base is taken to be decimal.
               The  magnitude  of the constant should be representable
               in 15 bits; i.e., be less than 32,768.


                       b = Binary
                       o,q = octal
                       d = decimal
                       H = hexidecimal


               A single character  constant  consists  of  the  single
               quote   (')  followed by any  ASCII  character  (except  the
               newline)  and  terminated   with   another   (').   The
               constant's  value  is  the code for the character right
               justified in the word, with zeros on the left.


             Blanks and Tabs 

               Blanks and tabs may be used freely between tokens,  but
               may  not appear within identifiers. A blank or a tab is
               required to  separate  adjacent  tokens  not  otherwise
               separated.


             Comments

               The character ';' introduces a comment, which continues
               until  the  end  of  line.  Comments are ignored by the
               assembler.


             The Location Counter

               The special symbol '$' is  the  location  counter.  Its
               value  is the offset into the current programme section
               of the start of the statement in which it appears.




                                     - 4 -                            


          ASM80                                            User Manual


             Statements

               A program consists of a sequence of  newline  separated
               statements.  There  are three kinds of statements; null
               statements,   assignment   statements    and    keyword
               statements.
                              
               Any statement may be preceeded by any number of labels.


             Labels

               A  name  label  consists of an identifier followed by a
               colon (':'). The value of the label is set to  that  of
               the location counter. It is an error for the value of a
               label to change between pass 1 and pass2.


             Null Statements

               A  null statement is just an empty line (which may have
               labels and be followed by a comment).  Null  statements
               are  ignored  by the assembler. Common examples of null
               statements are empty lines or lines consisting of  only
               a label. A line containing only a ^L (line feed) is 
               also considered as a null line.


             Assignment Statements 

               An  assignment  statement  consists  of  an  identifier
               followed by the 'EQU' or 'SET' and an  expression.  The
               value   of  the  identifier  is  set  to  that  of  the
               expression. Any symbol defined by  an  'EQU'  statement
               may   be   redefined,   either  by  another  assignment
               statement or by a label.


             Keyword Statements

               Keyword statements are the most common type; all of the
               machine operations and assembler pseudo operations  are
               of  this  type.  A keyword statement begins with one of
               the assembler's predefined keywords,  followed  by  any
               operands  required by that keyword.
               The 8085 instructions 'rim' and 'sim' are supported. 


                                     - 5 -                            


          ASM80                                            User Manual




             Expressions 

               An  expression  is a sequence of symbols representing a
               value.  Expressions  are  made   up   of   identifiers,
               constants,   operators   and  parentheses.  All  binary
               operators have equal precidence and are executed  in  a
               strict   left   to   right  order  (unless  altered  by
               parentheses).

             Types

               Every expression has a type determined by its operands.
               The types that will be met explicitly are:
                    Undefined 
                         Upon  first   encounter,   each   symbol   is
                         undefined. A symbol may also become undefined
                         if it is assigned to an undefined expression.
                         It  is  an  error  to  assemble  an undefined
                         expression in pass 2. Pass 1 allows  assembly
                         of  undefined  expressions,  but phase errors
                         may result if undefined expressions are  used
                         in certain contexts (i.e., in a ds).

                    Absolute 

                         An  absolute symbol is one defined untimately
                         from a constant or from the difference of two
                         relocatable values.

             Operators 

               The operators are:

         '+'        Addition
         '-'        Subtraction
         '*'        Multiplication
         '^' - XOR  Exclusive or
         '%' - MOD  Modulo
         '&' - AND  Bitwise AND
         '|' - OR   Bitwise OR
         '-'        Unary negation
         '!' - NOT  Unary ones complement
         '<' - SHL  Shift left
         '>' - SHR  Shift right

               Expressions may be grouped by means  of  parentheses.

                                     - 6 -                            


          ASM80                                            User Manual



      db expression [ , expression ] ...
               
               The   expressions  in  the  comma  separated  list  are
               truncated to 8 bits and are assembled  into  successive
               bytes.  The  expressions  must be absolute. Strings are
               also supported by this construct.
               


       dw expression [ , expression ] ...

               The  expressions  in  the  comma  separated  list   are
               assembled into successive byte pairs, high byte first.
               


       ds expression
               
               This  statement  assembles  into expression null bytes.
               The expression must be absolute.
               


       title s
               
               This statement allows  the  programmer  to  change  the
               title  line  on  the top of each listing page. Only the
               first 20 characters in the string are  considered.  The
               rest of the line is ignored.


       ORG expression

               The   program   counter  is  set  equal  to  the  value
               expression. It is not considered good form to  set  the
               porgram  counter  to a value less than the current one.
               There is no limit to the number of times this statement
               is used in a program.


                                     - 7 -                            


          ASM80                                            User Manual




       END expression

               This directive informs the assembler of the entry point
               into the program.


       OBJ expression (switch)

                A source code line may begin with '-obj' or '+obj' 
            as a means to control the hex file generation. This is
            particularly usefull if the hex file is intended to be
            sent to a PROM programmer. By using the -obj expression,
            the hex file will not contain bytes addressed to declared
            ram areas ( ds, dw, etc).

             Error messages

               Syntactic or semantic errors in the source are reported
               by displaying the offending line on the console <  your
               terminal> , preceeded by the appropriate error flag.

                       a        Addressing
                       b        Branching out of range
                       c        Constant expression
                       e        General error in expression
                       m        Multiply defined symbol
                       n        Error in number
                       o        Unknown opcode
                       p        Phasing / Port select
                       q        Questionable syntax
                       t        Byte truncation
                       u        Undefined 
                       z        Code tabel overflow
                       '        Character constant
                       .        Illegal use of DOT
                       (        Parentheses inbalance



               Errors  encountered  in  the  accessing  of files or in
               internal assembler operations are reported  in  english
               on the console.


                                     - 8 -                            






       Shortcomings and Caveats 

               The  assembler  has  some limitations. Some of the more
               important ones are listed below, and are classified  as
               H  (hard to fix), L (likely to remain), F (fixable, and
               likely to be fixed) and G (go away).

                       L        No macro facilities
        8080                                Instruction Summary



































                             - 9 -


                               Psuedo Operations 




      The following are extentions to the instructions set:


            1) ORG expression
            2) dw expression,expression,... , expression
            3) db expression,expression,... , expression
            4) ds  expression
            5) END expression
            6) TITLE string
























                                    - 10 -                           
SHAR_EOF
if test 12964 -ne "`wc -c < 'asm80.doc'`"
then
	echo shar: "error transmitting 'asm80.doc'" '(should have been 12964 characters)'
fi
fi
exit 0
#	End of shell archive