6502 Assembler ( Part 3 of 3)

Eric C. Brown brownc at utah-cs.UUCP
Sat May 4 01:53:12 AEST 1985


#!/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 the files:
#	assm2.c
#	assm3.c
# This archive created: Tue Apr  2 14:21:24 1985
# By:	James Van Ornum (AT&T-Bell Laboratories)
export PATH; PATH=/bin:$PATH
if test -f 'assm2.c'
then
	echo shar: over-writing existing file "'assm2.c'"
fi
cat << \SHAR_EOF > 'assm2.c'
#include "stdio.h"
#include "assm.d1"
#include "assm.d2"

extern	int	optab[];
extern	int	step[];

/* translate source line to machine language */

assemble()
{
	int	flg;
	int	i;		/* prlnbuf pointer */

	if ((prlnbuf[SFIELD] == ';') | (prlnbuf[SFIELD] == 0)) {
		if (pass == LAST_PASS)
			println();
		return;
	}
	lablptr = -1;
	i = SFIELD;
	udtype = UNDEF;
	if (colsym(&i) != 0 && (lablptr = stlook()) == -1)
		return;
	while (prlnbuf[++i] == ' ');	/* find first non-space */
	if ((flg = oplook(&i)) < 0) {	/* collect operation code */
		labldef(loccnt);
		if (flg == -1)
			error("Invalid operation code");
		if ((flg == -2) && (pass == LAST_PASS)) {
			if (lablptr != -1)
				loadlc(loccnt, 1, 0);
			println();
		}
		return;
	}
	if (opflg == PSEUDO)
		pseudo(&i);
	else if (labldef(loccnt) == -1)
		return;
	else {
		if (opflg == CLASS1)
			class1();
		else if (opflg == CLASS2)
			class2(&i);
		else class3(&i);
	}
}

/****************************************************************************/

/* printline prints the contents of prlnbuf */

println()
{
	if (lflag > 0)
		fprintf(stdout, "%s\n", prlnbuf);
}

/* colsym() collects a symbol from prlnbuf into symbol[],
 *    leaves prlnbuf pointer at first invalid symbol character,
 *    returns 0 if no symbol collected
 */

colsym(ip)
    int *ip;
{
	int	valid;
	int	i;
	char	ch;

	valid = 1;
	i = 0;
	while (valid == 1) {
		ch = prlnbuf[*ip];
		if (ch == '_' || ch == '.');
		else if (ch >= 'a' && ch <= 'z');
		else if (ch >= 'A' && ch <= 'Z');
		else if (i >= 1 && ch >= '0' && ch <= '9');
		else if (i == 1 && ch == '=');
		else valid = 0;
		if (valid == 1) {
			if (i < SBOLSZ - 1)
				symbol[++i] = ch;
			(*ip)++;
		}
	}
	if (i == 1) {
		switch (symbol[1]) {
		case 'A': case 'a':
		case 'X': case 'x':
		case 'Y': case 'y':
			error("Symbol is reserved (A, X or Y)");
			i = 0;
		}
	}
	symbol[0] = i;
	return(i);
}

/* symbol table lookup
 *	if found, return pointer to symbol
 *	else, install symbol as undefined, and return pointer
 */

stlook()
{
	int	found;
	int	hptr;
	int	j;
	int	nptr;
	int	pptr;
	int	ptr;

	hptr = 0;
	for (j = 0; j < symbol[0]; j++)
		hptr += symbol[j];
	hptr %= 128;
	ptr = hash_tbl[hptr];
	if (ptr == -1) {		/* no entry for this link */
		hash_tbl[hptr] = nxt_free;
		return(stinstal());
	}
	while (symtab[ptr] != 0) {	/* 0 count = end of table */
		found = 1;
		for (j = 0; j <= symbol[0]; j++) {
			if (symbol[j] != symtab[ptr + j]) {
				found = 0;
				pptr = ptr + symtab[ptr] + 4;
				nptr = (symtab[pptr + 1] << 8) + (symtab[pptr] & 0xff);
				nptr &= 0xffff;
				if (nptr == 0) {
					symtab[ptr + symtab[ptr] + 4] = nxt_free & 0xff;
					symtab[ptr + symtab[ptr] + 5] = (nxt_free >> 8) & 0xff;
					return(stinstal());
				}
				ptr = nptr;
				break;
			}
		}
		if (found == 1)
			return(ptr);
	}
	error("Symbol not found");
	return(-1);
}

/*  instal symbol into symtab
 */
stinstal()
{
register	int	j;
register	int	ptr1;
register	int	ptr2;

	ptr1 = ptr2 = nxt_free;
	if ((ptr1 + symbol[0] + 6) >= STABSZ) {
		error("Symbol table full");
		return(-1);
	}
	for (j = 0; j <= symbol[0]; j++)
		symtab[ptr1++] = symbol[j];
	symtab[ptr1] = udtype;
	nxt_free = ptr1 + 5;
	return(ptr2);
}

/* operation code table lookup
 *	if found, return pointer to symbol,
 *	else, return -1
 */

oplook(ip)
   int	*ip;
{
register	char	ch;
register	int	i;
register	int	j;
	int	k;
	int	temp[2];

	i = j = 0;
	temp[0] = temp[1] = 0;
	while((ch=prlnbuf[*ip])!= ' ' && ch!= 0 && ch!= '\t' && ch!= ';') {
		if (ch >= 'A' && ch <= 'Z')
			ch &= 0x1f;
		else if (ch >= 'a' && ch <= 'z')
			ch &= 0x1f;
		else if (ch == '.')
			ch = 31;
		else if (ch == '*')
			ch = 30;
		else if (ch == '=')
			ch = 29;
		else return(-1);
		temp[j] = (temp[j] * 0x20) + (ch & 0xff);
		if (ch == 29)
			break;
		++(*ip);
		if (++i >= 3) {
			i = 0;
			if (++j >= 2) {
				return(-1);
			}
		}
	}
	if ((j = temp[0]^temp[1]) == 0)
		return(-2);
	k = 0;
	i = step[k] - 3;
	do {
		if (j == optab[i]) {
			opflg = optab[++i];
			opval = optab[++i];
			return(i);
		}
		else if (j < optab[i])
			i -= step[++k];
		else i += step[++k];
	} while (step[k] != 0);
	return(-1);
}

/* error printing routine */

error(stptr)
   char *stptr;
{
	loadlc(loccnt, 0, 1);
	loccnt += 3;
	loadv(0,0,0);
	loadv(0,1,0);
	loadv(0,2,0);
	fprintf(stderr, "%s\n", prlnbuf);
	fprintf(stderr, "%s\n", stptr);
	errcnt++;
}

/* load 16 bit value in printable form into prlnbuf */

loadlc(val, f, outflg)
    int val;
    int f;
    int outflg;
{
	int	i;

	i = 6 + 7*f;
	hexcon(4, val);
	if (nflag == 0) {
		prlnbuf[i++]  = hex[3];
		prlnbuf[i++]  = hex[4];
		prlnbuf[i++]  = ':';
		prlnbuf[i++]  = hex[1];
		prlnbuf[i] = hex[2];
	}
	else {
		prlnbuf[i++] = hex[1];
		prlnbuf[i++] = hex[2];
		prlnbuf[i++] = hex[3];
		prlnbuf[i] = hex[4];
	}
	if ((pass == LAST_PASS)&&(oflag != 0)&&(objcnt <= 0)&&(outflg != 0)) {
		fprintf(optr, "\n;%c%c%c%c", hex[3], hex[4], hex[1], hex[2]);
		objcnt = 16;
	}
}



/* load value in hex into prlnbuf[contents[i]] */
/* and output hex characters to obuf if LAST_PASS & oflag == 1 */

loadv(val,f,outflg)
   int	val;
   int	f;		/* contents field subscript */
   int	outflg;		/* flag to output object bytes */
{

	hexcon(2, val);
	prlnbuf[13 + 3*f] = hex[1];
	prlnbuf[14 + 3*f] = hex[2];
	if ((pass == LAST_PASS) && (oflag != 0) && (outflg != 0)) {
		fputc(hex[1], optr);
		fputc(hex[2], optr);
		--objcnt;
	}
}

/* convert number supplied as argument to hexadecimal in hex[digit] (lsd)
		through hex[1] (msd)		*/

hexcon(digit, num)
    int digit;
   int	num;
{

	for (; digit > 0; digit--) {
		hex[digit] = (num & 0x0f) + '0';
		if (hex[digit] > '9')
			hex[digit] += 'A' -'9' - 1;
		num >>= 4;
	}
}

/* assign <value> to label pointed to by lablptr,
 *	checking for valid definition, etc.
 */

labldef(lval)
    int lval;
{
	int	i;

	if (lablptr != -1) {
		lablptr += symtab[lablptr] + 1;
		if (pass == FIRST_PASS) {
			if (symtab[lablptr] == UNDEF) {
				symtab[lablptr + 1] = lval & 0xff;
				i = symtab[lablptr + 2] = (lval >> 8) & 0xff;
				if (i == 0)
					symtab[lablptr] = DEFZRO;
				else	symtab[lablptr] = DEFABS;
			}
			else if (symtab[lablptr] == UNDEFAB) {
				symtab[lablptr] = DEFABS;
				symtab[lablptr + 1] = lval & 0xff;
				symtab[lablptr + 2] = (lval >> 8) & 0xff;
			}
			else {
				symtab[lablptr] = MDEF;
				symtab[lablptr + 1] = 0;
				symtab[lablptr + 2] = 0;
				error("Label multiply defined");
				return(-1);
			}
		}
		else {
			i = (symtab[lablptr + 2] << 8) +
				(symtab[lablptr+1] & 0xff);
			i &= 0xffff;
			if (i != lval && pass == LAST_PASS) {
				error("Sync error");
				return(-1);
			}
		}
	}
	return(0);
}

/* determine the value of the symbol,
 * given pointer to first character of symbol in symtab
 */

symval(ip)
    int *ip;
{
	int	ptr;
	int	svalue;

	svalue = 0;
	colsym(ip);
	if ((ptr = stlook()) == -1)
		undef = 1;		/* no room error */
	else if (symtab[ptr + symtab[ptr] + 1] == UNDEF)
		undef = 1;
	else if (symtab[ptr + symtab[ptr] + 1] == UNDEFAB)
		undef = 1;
	else svalue = ((symtab[ptr + symtab[ptr] + 3] << 8) +
		(symtab[ptr + symtab[ptr] + 2] & 0xff)) & 0xffff;
	if (symtab[ptr + symtab[ptr] + 1] == DEFABS)
		zpref = 1;
	if (undef != 0)
		zpref = 1;
	return(svalue);
}
SHAR_EOF
if test -f 'assm3.c'
then
	echo shar: over-writing existing file "'assm3.c'"
fi
cat << \SHAR_EOF > 'assm3.c'
#include "stdio.h"
#include "assm.d1"
#include "assm.d2"

/* class 1 machine operations processor - 1 byte, no operand field */

class1()
{
	if (pass == LAST_PASS) {
		loadlc(loccnt, 0, 1);
		loadv(opval, 0, 1);
		println();
	}
	loccnt++;
}


/* class 2 machine operations processor - 2 byte, relative addressing */

class2(ip)
    int *ip;
{

	if (pass == LAST_PASS) {
		loadlc(loccnt, 0, 1);
		loadv(opval, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');
		if (evaluate(ip) != 0) {
			loccnt += 2;
			return;
		}
		loccnt += 2;
		if ((value -= loccnt) >= -128 && value < 128) {
			loadv(value, 1, 1);
			println();
		}
		else error("Invalid branch address");
	}
	else loccnt += 2;
}


/* class 3 machine operations processor - various addressing modes */

class3(ip)
    int *ip;
{
	char	ch;
	int	code;
	int	flag;
	int	i;
	int	ztmask;

	while ((ch = prlnbuf[++(*ip)]) == ' ');
	switch(ch) {
	case 0:
	case ';':
		error("Operand field missing");
		return;
	case 'A':
	case 'a':
		if ((ch = prlnbuf[*ip + 1]) == ' ' || ch == 0) {
			flag = ACC;
			break;
		}
	default:
		switch(ch = prlnbuf[*ip]) {
		case '#': case '=':
			flag = IMM1 | IMM2;
			++(*ip);
			break;
		case '(':
			flag = IND | INDX | INDY;
			++(*ip);
			break;
		default:
			flag = ABS | ZER | ZERX | ABSX | ABSY | ABSY2 | ZERY;
		}
		if ((flag & (INDX | INDY | ZER | ZERX | ZERY) & opflg) != 0)
			udtype = UNDEFAB;
		if (evaluate(ip) != 0)
			return;
		if (zpref != 0) {
			flag &= (ABS | ABSX | ABSY | ABSY2 | IND | IMM1 | IMM2);
			ztmask = 0;
		}
		else ztmask = ZER | ZERX | ZERY;
		code = 0;
		i = 0;
		while (( ch = prlnbuf[(*ip)++]) != ' ' && ch != 0 && i++ < 4) {
			code *= 8;
			switch(ch) {
			case ')':		/* ) = 4 */
				++code;
			case ',':		/* , = 3 */
				++code;
			case 'X':		/* X = 2 */
			case 'x':
				++code;
			case 'Y':		/* Y = 1 */
			case 'y':
				++code;
				break;
			default:
				flag = 0;
			}
		}
		switch(code) {
		case 0:		/* no termination characters */
			flag &= (ABS | ZER | IMM1 | IMM2);
			break;
		case 4:		/* termination = ) */
			flag &= IND;
			break;
		case 25:		/* termination = ,Y */
			flag &= (ABSY | ABSY2 | ZERY);
			break;
		case 26:		/* termination = ,X */
			flag &= (ABSX | ZERX);
			break;
		case 212:		/* termination = ,X) */
			flag &= INDX;
			break;
		case 281:		/* termination = ),Y */
			flag &= INDY;
			break;
		default:
			flag = 0;
		}
	}
	if ((opflg &= flag) == 0) {
		error("Invalid addressing mode");
		return;
	}
	if ((opflg & ztmask) != 0)
		opflg &= ztmask;
	switch(opflg) {
	case ACC:		/* single byte - class 3 */
		if (pass == LAST_PASS) {
			loadlc(loccnt, 0, 1);
			loadv(opval + 8, 0, 1);
			println();
		}
		loccnt++;
		return;
	case ZERX: case ZERY:	/* double byte - class 3 */
		opval += 4;
	case INDY:
		opval += 8;
	case IMM2:
		opval += 4;
	case ZER:
		opval += 4;
	case INDX: case IMM1:
		if (pass == LAST_PASS) {
			loadlc(loccnt, 0, 1);
			loadv(opval, 0, 1);
			loadv(value, 1, 1);
			println();
		}
		loccnt += 2;
		return;
	case IND:		/* triple byte - class 3 */
		opval += 16;
	case ABSX:
	case ABSY2:
		opval += 4;
	case ABSY:
		opval += 12;
	case ABS:
		if (pass == LAST_PASS) {
			opval += 12;
			loadlc(loccnt, 0, 1);
			loadv(opval, 0, 1);
			loadv(value, 1, 1);
			loadv(value >> 8, 2, 1);
			println();
		}
		loccnt += 3;
		return;
	default:
		error("Invalid addressing mode");
		return;
	}
}

/* pseudo operations processor */

pseudo(ip)
    int *ip;
{
	int	count;
	int	i;
	int	tvalue;

	switch(opval) {
	case 0:				/* .byte pseudo */
		labldef(loccnt);
		loadlc(loccnt, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');	/*    field	*/
		count = 0;
		do {
			if (prlnbuf[*ip] == '"') {
				while ((tvalue = prlnbuf[++(*ip)]) != '"') {
					if (tvalue == 0) {
						error("Unterminated ASCII string");
						return;
					}
					if (tvalue == '\\')
						switch(tvalue = prlnbuf[++(*ip)]) {
						case 'n':
							tvalue = '\n';
							break;
						case 't':
							tvalue = '\t';
							break;
						}
					loccnt++;
					if (pass == LAST_PASS) {
						loadv(tvalue, count, 1);
						if (++count >= 3) {
							println();
							for (i = 0; i < SFIELD; i++)
								prlnbuf[i] = ' ';
							prlnbuf[i] = 0;
							count = 0;
							loadlc(loccnt, 0, 1);
						}
					}
				}
				++(*ip);
			}
			else {
				if (evaluate(ip) != 0) {
					loccnt++;
					return;
				}
				loccnt++;
				if (value > 0xff) {
					error("Operand field size error");
					return;
				}
				else if (pass == LAST_PASS) {
					loadv(value, count, 1);
					if (++count >= 3) {
						println();
						for (i = 0; i < SFIELD; i++)
							prlnbuf[i] = ' ';
						prlnbuf[i] = 0;
						count = 0;
						loadlc(loccnt, 0, 1);
					}
				}
			}
		} while (prlnbuf[(*ip)++] == ',');
		if ((pass == LAST_PASS) && (count != 0))
			println();
		return;
	case 1:				/* = pseudo */
		while (prlnbuf[++(*ip)] == ' ');
		if (evaluate(ip) != 0)
			return;
		labldef(value);
		if (pass == LAST_PASS) {
			loadlc(value, 1, 0);
			println();
		}
		return;
	case 2:				/* .word pseudo */
		labldef(loccnt);
		loadlc(loccnt, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');
		do {
			if (evaluate(ip) != 0) {
				loccnt += 2;
				return;
			}
			loccnt += 2;
			if (pass == LAST_PASS) {
				loadv(value, 0, 1);
				loadv(value>>8, 1, 1);
				println();
				for (i = 0; i < SFIELD; i++)
					prlnbuf[i] = ' ';
				prlnbuf[i] = 0;
				loadlc(loccnt, 0, 1);
			}
		} while (prlnbuf[(*ip)++] == ',');
		return;
	case 3:				/* *= pseudo */
		while (prlnbuf[++(*ip)] == ' ');
		if (prlnbuf[*ip] == '*') {
			if (evaluate(ip) != 0)
				return;
			if (undef != 0) {
				error("Undefined symbol in operand field.");
				return;
			}
			tvalue = loccnt;
		}
		else {
			if (evaluate(ip) != 0)
				return;
			if (undef != 0) {
				error("Undefined symbol in operand field.");
				return;
			}
			tvalue = value;
		}
		loccnt = value;
		labldef(tvalue);
		if (pass == LAST_PASS) {
			objcnt = 0;
			loadlc(tvalue, 1, 0);
			println();
		}
		return;
	case 4:				/* .list pseudo */
		if (lflag >= 0)
			lflag = 1;
		return;
	case 5:				/* .nlst pseudo */
		if (lflag >= 0)
			lflag = iflag;
		return;
	case 6:				/* .dbyt pseudo */
		labldef(loccnt);
		loadlc(loccnt, 0, 1);
		while (prlnbuf[++(*ip)] == ' ');
		do {
			if (evaluate(ip) != 0) {
				loccnt += 2;
				return;
			}
			loccnt += 2;
			if (pass == LAST_PASS) {
				loadv(value>>8, 0, 1);
				loadv(value, 1, 1);
				println();
				for (i = 0; i < SFIELD; i++)
					prlnbuf[i] = ' ';
				prlnbuf[i] = 0;
				loadlc(loccnt, 0, 1);
			}
		} while (prlnbuf[(*ip)++] == ',');
		return;
	}
}

/* evaluate expression */

evaluate(ip)
   int	*ip;
{
	int	tvalue;
	int	invalid;
	int	parflg, value2;
	char	ch;
	char	op;
	char	op2;

	op = '+';
	parflg = zpref = undef = value = invalid = 0;
/* hcj: zpref should reflect the value of the expression, not the value of
   the intermediate symbols
*/
	while ((ch=prlnbuf[*ip]) != ' ' && ch != ')' && ch != ',' && ch != ';') {
		tvalue = 0;
		if (ch == '$' || ch == '@' || ch == '%')
			tvalue = colnum(ip);
		else if (ch >= '0' && ch <= '9')
			tvalue = colnum(ip);
		else if (ch >= 'a' && ch <= 'z')
			tvalue = symval(ip);
		else if (ch >= 'A' && ch <= 'Z')
			tvalue = symval(ip);
		else if ((ch == '_') || (ch == '.'))
			tvalue = symval(ip);
		else if (ch == '*') {
			tvalue = loccnt;
			++(*ip);
		}
		else if (ch == '\'') {
			++(*ip);
			tvalue = prlnbuf[*ip] & 0xff;
			++(*ip);
		}
		else if (ch == '[') {
			if (parflg == 1) {
				error("Too many ['s in expression");
				invalid++;
			}
			else {
				value2 = value;
				op2 = op;
				value = tvalue = 0;
				op = '+';
				parflg = 1;
			}
			goto next;
		}
		else if (ch == ']') {
			if (parflg == 0) {
				error("No matching [ for ] in expression");
				invalid++;
			}
			else {
				parflg = 0;
				tvalue = value;
				value = value2;
				op = op2;
			}
			++(*ip);
		}
		switch(op) {
		case '+':
			value += tvalue;
			break;
		case '-':
			value -= tvalue;
			break;
		case '/':
			value = (unsigned) value/tvalue;
			break;
		case '*':
			value *= tvalue;
			break;
		case '%':
			value = (unsigned) value%tvalue;
			break;
		case '^':
			value ^= tvalue;
			break;
		case '~':
			value = ~tvalue;
			break;
		case '&':
			value &= tvalue;
			break;
		case '|':
			value |= tvalue;
			break;
		case '>':
			tvalue >>= 8;		/* fall through to '<' */
		case '<':
			if (value != 0) {
				error("High or low byte operator not first in operand field");
			}
			value = tvalue & 0xff;
			zpref = 0;
			break;
		default:
			invalid++;
		}
		if ((op=prlnbuf[*ip]) == ' '
				|| op == ')'
				|| op == ','
				|| op == ';')
			break;
		else if (op != ']')
next:			++(*ip);
	}
	if (parflg == 1) {
		error("Missing ] in expression");
		return(1);
	}
	if (value < 0 || value >= 256) {
		zpref = 1;
	}
	if (undef != 0) {
		if (pass != FIRST_PASS) {
			error("Undefined symbol in operand field");
			invalid++;
		}
		value = 0;
	}
	else if (invalid != 0)
	{
		error("Invalid operand field");
	}
	else {
/*
 This is the only way out that may not signal error
*/
		if (value < 0 || value >= 256) {
			zpref = 1;
		}
		else {
			zpref = 0;
		}
	}
	return(invalid);
}

/* collect number operand		*/

colnum(ip)
	int	*ip;
{
	int	mul;
	int	nval;
	char	ch;

	nval = 0;
	if ((ch = prlnbuf[*ip]) == '$')
		mul = 16;
	else if (ch >= '1' && ch <= '9') {
		mul = 10;
		nval = ch - '0';
	}
	else if (ch == '@' || ch == '0')
		mul = 8;
	else if (ch == '%')
		mul = 2;
	while ((ch = prlnbuf[++(*ip)] - '0') >= 0) {
		if (ch > 9) {
			ch -= ('A' - '9' - 1);
			if (ch > 15)
				ch -= ('a' - 'A');
			if (ch > 15)
				break;
			if (ch < 10)
				break;
		}
		if (ch >= mul)
			break;
		nval = (nval * mul) + ch;
	}
	return(nval);
}
SHAR_EOF
#	End of shell archive
exit 0



More information about the Comp.sources.unix mailing list