/*	M6800 Cross Assembler				*/
/*	Overlay Segment SEG2.C		Version A.1	*/
/*	Pass Two of X68 M6800 cross assembler		*/

/*
 *	PERMISSION IS GRANTED FOR THE PUBLIC DOMAIN
 *	NON COMMERCIAL USE OF THIS SOFTWARE.
 *
 *	(C) CHRIS UNDERY 25th OCTOBER 1982
 *	11 MARGARET ST NEWTOWN 2042
 *	SYDNEY, AUSTRALIA
 */

/*
	This pass of X68 reads the UFN.TMP searching for
 undefined hex code signified by a '?' in the I2 field of
 and instruction. If the I3 field is also undefined, a word
 reference is assumed. The program looks up the operand in the
 symbol table and fills in the blanks. If the symbol is still
 undefined, a fatal error is assumed.

	This module is an overlay, loaded by the swapin function
in X68.c

*/
 
#include "x68.h"

main()
{

	struct nlist *lookup(), *install(), *ptr;
	char asfile[15], temp[150], listfile[15];
	char hbuf[BUFSIZ];

	pageno = linecnt = 0;
	printf("Pass two (Version A.1)\n");
	strcpy(asfile,filename);	/* get primary file name */
	strcat(asfile,".TMP");		/* add temp filetype	*/
	if (fopen(asfile,ibuf) == ERROR ) {
		printf("Cannot open %s\007\n",asfile);
		exit();			/* Halt progress 	*/
	}
	if (xing) {
		if (fcreat(hexname,hbuf) == ERROR) {
			printf("Disk probably full: Cannot create hex file\n");
			exit();
		}
	}
	if (listing) {
		if (fcreat(lstname,obuf) == ERROR ) {
			printf("Disk probably full: Cannot create %s\007\n",listfile);
			exit();
		}
	}
	lineno = 0;
	header();
	while (fgets(line,ibuf)) {
		pass2();		/* Do pass 2 */
		if (line[0] != ';') makeline();
		else {
			if (listing) {
				putc(TAB,obuf); /* Pretty up the listing */
				putc(TAB,obuf);
			}
			if (printing) printf("\t\t");
		}
		if (linecnt++ == 55) header();
		if (xing) wrhex(hbuf);		/* Write hex file */
		if (listing) fputs(line,obuf);
		if (printing) printf("%s",line);
	}
	putsym();				/* Write symbols to lst */
	if (listing) {
		fprintf(obuf,"\n\nEND OF ASSEMBLY ");
		fprintf(obuf,"%d FATAL ERROR(S) DETECTED\n",errors);
		putc(0x1a,obuf);
		fflush(obuf);
		fclose(obuf);
	}
	fclose(ibuf);
	if (xing) {
		fprintf(hbuf,":00000001FF\n");
		putc(0x1a,hbuf);
		fflush(hbuf);
		fclose(hbuf);
	}
	if (!debug) unlink(asfile);
}				/* PAss 2 done */


pass2()
{
	struct nlist *ptr, *alt, *lookup();
	unsigned current, branch, relative;
	char swopper[16], fiddled;

	current = branch = relative = 0;
	lineno++;
	tokenise();		/* Get tokens */
	if (temp[8] != '?') return(1);	/* No wuckers */

/* Version A.1 has expression evaluator in root module x68.com */
/* the old version was in seg1 overlay and as result, seg2 could */
/* not be very intelligent. This version can evaluate failed */
/* operand complexes from pass 1 */

	fiddled = 0;	
	if (operand[0] == '#') {
		strcpy(swopper,&operand[1]);
		strcpy(operand,swopper);
		fiddled = 1;
	}
	getsub(operand);	/* split operand down the middle */
	if ((ptr = lookup(xp1)) != NULL) goto itil;
	if ((alt = lookup(xp2)) == NULL) {
		B1090();	/* Total failure undefined symbol */
		return(1);
	}
itil:	if ((index(alt->def,"??") >=0) || (index(ptr->def,"??") >= 0)) {
		B1090();	/* trap unresolved references */
		return(1);
	}
	if (!evaluate(operand)) { /* only now is it safe to evaluate it */
		B1090();
		return(1);
	}

/* if this line has a label then install the label now in case further */
/* references are made to it, this takes care of foward refs on an equ */

	getok(label,&line[18],1,16);	/* extract label from line */
	tohex(labrec,dec);	/* convert result to hex string */
	if (label[0] != '\0') { /* install label reference */
		if ((alt = install(label,labrec)) == NULL) {
			printf("I just creamed the symbol table boss!\n");
			exit();
		}
	}
	if (fiddled) {
		strcpy(swopper,"#");
		strcat(swopper,operand);
		strcpy(operand,swopper);
	}
	strcpy(labad,labrec);
	if (line[10] == '?' ) {		/* Word reference eg JMP */
		if (index(mnem,"EQU") >= 0) {
			temp[13] = labrec[0];
			temp[14] = labrec[1];
			temp[15] = labrec[2];
			temp[16] = labrec[3];
			temp[8] = ' ';
			temp[9] = ' ';
			temp[10] = ' '; temp[11] = ' ';
		}
		else {
			temp[8] = labrec[0];
			temp[9] = labrec[1];
			temp[10] = labrec[2];
			temp[11] = labrec[3];
		}
	return(1);
	}
	smov(hex,&temp[0],4); 		/* Rel brnch, get current address */
	current = todec(hex,16);		/* Convert to hex	*/
	branch = todec(labrec,16);		/* ready for diff test  */
	relative = branch - current + 254;
	if (relative < 128 ) B1095();
	if (relative > 383 ) B1095();
	tohex(hex,relative);		/* convert back to hex   */
	temp[8] = hex[2];
	temp[9] = hex[3];		/* Replace ?? with result */
	temp[13] = labad[0];		/* Now pretty up with label addr */
	temp[14] = labad[1];
	temp[15] = labad[2];
	temp[16] = labad[3];
	return(1);
}				/* While not end of file 	*/

B1090()
{
	printf("Variable <%s> not defined at line <%u> in module %s\n",operand,lineno,title);
	printf("%s\n",line);
	if (listing) fprintf(obuf,"*** ERROR *** UNDEFINED VARIABLE: %s \n",operand);
	errors++;
	if (lineno++ == 55) header();
	return(1);
}


B1095()
{	
	printf("Branch out of range at line <%u> in module %s\n",lineno,title);
	printf("%s\n",line);
	if (listing) fprintf(obuf,"*** ERROR ***  BRANCH DISPLACEMENT OUT OF RANGE \n");
	errors++;
	if (lineno++ == 55) header();
	return(1);
}

/*	Get set of tokens from temporary pass 1 file */

tokenise()
{
	int slew_count;

	getok(temp,line,1,30);	/* Will also get LABEL code field */
	getok(mnem,line,2,9);	/* Get mnemonic field */
	getok(operand,line,3,80);	/* Get operand field */
	getcomment(line);
	if (index(mnem,"TITLE") >= 0) smov(title,operand,32);
	if (index(mnem,"PAGE") >= 0) header();
	if (index(mnem,"NOLIST") >= 0) printing = 0;
	if (index(mnem,"LIST") >= 0) printing = 1;
	if (index(mnem,"SPACE") >= 0) {	/* accomodate excesses of tek ass */
		if (evaluate(operand)) {
			slew_count = 0;
			while (slew_count++ < dec) {
				if (listing) fprintf(obuf,"\n");
				if (printing) printf("\n");
				if (lineno++ == 55) header();
			}
		}
	}
}

makeline()		/* Build up output line */
{
	int adjuster;


	strcpy(line,temp);	/* First stuff incl label */
	adjuster = 30 - strlen(temp);
	while (adjuster--) strcat(line," ");
	strcat(line,"\t");
	strcat(line,mnem);
	strcat(line,"\t");
	strcat(line,operand);
	strcat(line,"\t");
	strcat(line,comment);
}

header()		/* Produce page header */
{
	if (listing) {
		putc(0x0c,obuf);	/* Form feed */
		fprintf(obuf,"X68 Motorola 6800 Cross Assembler Version A.1");
		fprintf(obuf,"           Page # %5d  File: %s ",++pageno,filename);
		fprintf(obuf,"Module name: %s\n\n",title);
		fprintf(obuf,"Addr Code			Source Statement\n\n");
		linecnt = 0;
	}
	if (printing) {
		if (!listing) pageno++;	/* dont double up page numbering */
		putc(0x0c,1);
		printf("X68 Motorola 6800 Cross Assembler Version A.1");
		printf("           Page # %5d File: %s ",pageno,filename);
		printf("Module name: %s\n\n",title);
		printf("Addr Code		Source Statement\n\n");
		if (!listing) linecnt = 0;
	}
}

gethex()		/* Get hex record from output line */
{			/* Returning numberof data bytes */
	int count;
	int k, i;
	char fudge[10];

	count = i = 0;
	hexrec[0] = '0';
	hexrec[1] = '0';
	hexrec[2] = NULL;
	smov(fudge,temp,4);
	k = todec(fudge,16);	/* convert address to dec */
	k = (k - bias);
	tohex(fudge,k);
	hexrec[2] = fudge[0];
	hexrec[3] = fudge[1];
	hexrec[4] = fudge[2];
	hexrec[5] = fudge[3];
	hexrec[6] = '\0';
	i = 6;
	strcat(hexrec,"00");	/* record type */
	i += 2;
	if (!isspace(temp[5])) {
		hexrec[i++] = temp[5];
		hexrec[i++] = temp[6];
		count++;
	}
	if (!isspace(temp[8])) {
		hexrec[i++] = temp[8];
		hexrec[i++] = temp[9];
		count++;
	}
	if (!isspace(temp[10])) {
		hexrec[i++] = temp[10];
		hexrec[i++] = temp[11];
		count++;
	}
	hexrec[i] = '\0';
	hexrec[1] = (0x30 + count);
	return(count);	/* one more for checksum */
}

genbin(c)		/* Generate binary image of hex record */
int c;		/* Count for countfield */
{
	int m, i, g, j, k;	/* Indices	*/
	char tb[5];
	bcc = i = j = k = m = 0;
	g = (strlen(hexrec)-1);
	while (m < g) {		/* Loop converting hexrec to binary */
		tb[0] = hexrec[m++];
		tb[1] = hexrec[m++];
		tb[2] = '\0';
		k = todec(tb,16);
		bcc += k;	/* update checksum */
	}
	bcc=(~bcc)+1;		/* Take twos complement */
	return(1);		/* number of characters to send */
}

wrhex(h)				/* Write hex record */
char *h;
{
	int c, e, d;

	d = 0;
	if (temp[0] == ';' || temp[0] == '*') return(1);
	if (index(mnem,"SPACE") >= 0) return(1);  /*PA - return if directive*/
	if (index(mnem,"NOLIST") >= 0) return(1);
	if (index(mnem,"LIST") >= 0) return(1);
	if (index(mnem,"PAGE") >= 0) return(1);
	if (index(mnem,"TITLE") >= 0) return(1);
	if (index(mnem,"PURGE") >= 0) return(1);
	if (!gethex()) return(0);	/* no stuff to write */
	c = genbin(e);
	fprintf(h,":");
	fprintf(h,"%s",hexrec);
	tohex(temp,bcc);
	putc(temp[2],h);
	putc(temp[3],h);
	fprintf(h,"\n");
}

/*	Write symbol table to listing device */

putsym()
{
	struct nlist *tp, *lookup();
	int bucket, num;

	bucket = num = 0;
	if ((!listing) && (!printing)) return(1);
	if (listing) {
		putc(0x0c,obuf);
		fprintf(obuf,"Symbols:\n\n");
	}
	if (printing) {
		putc(0x0c);
		printf("Symbols:\n\n");
	}
	while (bucket < HASHSIZE) {
		for (tp = hashtab[bucket]; tp != NULL; tp = tp->next) {
			if (listing) {
				fprintf(obuf,"%s\t%s\t",tp->name,tp->def);
				if (num == 5) {
					 fprintf(obuf,"\n");
	 				 if (linecnt++ == 55)  header();
					 num = 0;
				}
			}
			if (printing) {	/* to console or printer */
				printf("%s\t%s\t",tp->name,tp->def);
				if (num == 4) {
					 printf("\n");
					 if (linecnt++ == 55) header();
					 num = 0;
				}
			}
			num++;
		}
	bucket++;
	}
	if (printing) putc(0x0c,1);
}

