/*
	Copyright 1983
	Alcyon Corporation
	8716 Production Ave.
	San Diego, Ca.  92121
*/

/*	Pass 1 and pass 2 directive handling routines */
/*	code to handle conditional assembly directives */

#include "as68.h"

int p1gi();
int p2gi();
int igrst();

/*directive to define an opcode*/
hopd()
{
	if(!lbt[0]) {
		xerr(4);		/*no label*/
		return;
	}
	setname();					/*move label into main table*/
	if((lblpt=lemt(TRUE,oirt))!=lmte) {
		xerr(5);				/*opcode redefined*/
		return;
	}
	mmte();						/*make main table entry*/
	expr(&p1gi);				/*get instruction format*/
	if(itype!=ITCN || ival<0 || ival>OPFF) {
		xerr(18);			/*illegal format specifier*/
		return;
	}
	lblpt->flags |= ival|SYIN;		/*remember format*/
	if(fchr != ',') {			/*field separator*/
		xerr(10);
		return;
	}
	expr(&p1gi);				/*get opcode value*/
	if(itype != ITCN) {
		xerr(17);		/*not a constant*/
		return;
	}
	lblpt->vl1 = ival;			/*put value in main table*/
	igrst();					/*ignore rest of statement-comment*/
}

/* equate directive*/
hequ()
{
	if(lbt[0] == 0) {
		xerr(4);		/*no label*/
		return;
	}
	setname();
	if((lblpt=lemt(FALSE,sirt))!=lmte) {	/*aready there*/
		if(lbt[0] == '~') {	/*local symbol*/
			lblpt = lmte;
			mmte();
		}
	}
	else
		mmte();
	if(lblpt->flags&SYXR) {
		xerr(29);
		return;
	}
	lblpt->flags |= SYDF|SYEQ;	/*defined & equate*/
	equflg = 1;
	modelen = LONGSIZ;
	expr(&p1gi);
	equflg = 0;
	if(itype == ITSY && ival.ptrw2->flags&SYER) {
		lblpt->flags |= SYER;	/*equated register*/
		ival = ival.ptrw2->vl1;
	}
	else if(itype != ITCN) {
		xerr(7);				/*not a constant*/
		return;
	}
	if (inoffset && reloc != ABS) {	/* [vlh] */
		xerr(11);
		return;
	}
	if(initflg)					/*doing symbol table initialization*/
		lblpt->flags |= SYIN;	/*internal symbol*/
	lblpt->vl1 = ival;
	if(reloc == DATA)			/*check relocation*/
	{
		lblpt->flags |= SYRA;	/*DATA relocatable*/
	}
	else if(reloc == TEXT)
		lblpt->flags |= SYRO;	/*TEXT relocatable*/
	else if(reloc == BSS)
		lblpt->flags |= SYBS;	/*BSS relocatable*/
	else if(fchr==',' && (fchr=gchr())=='r')
		lblpt->flags |= SYER;	/*equated register*/
	if (refpc)		/*[vlh] flag directive is pc relative */
		lblpt->flags |= SYPC;
	igrst();
}

/* process dsect directive*/
hdsect()
{
	dorlst(DATA);
}

dorlst(xrtyp)
int xrtyp;
{
	inoffset = 0;	/* [vlh] offset mode terminated my sect directive */
	chkeven();		/*sw adjust boundary if need be*/
	dlabl();		/*define label on old base if there is one*/
	savelc[rlflg] = loctr;	/*save old base relocation*/
	rlflg = xrtyp;
	loctr = savelc[xrtyp];	/*set new base relocation ctr*/
	opitb();
	stbuf[0].itrl = itwc;
	wostb();
	igrst();
}

/*process psect directive*/
hpsect()
{
	dorlst(TEXT);
}

hbss()
{
	dorlst(BSS);
}

/*make pc even*/
heven()
{
	modelen = 2;		/*sw Set up so chkeven() won't barf ...*/
	if(loctr&1) {		/*have to make it even*/
		dorlst(rlflg);
	}
	else {
		igrst();
	}
}

/*process globl directive*/
hent()
{
	while(1) {
		gterm(TRUE);					/*get entry symbol*/
		if(itype!=ITSY) {				/*error if not symbol*/
			xerr(28);
			return;
		}
		if((lblpt=lemt(FALSE,sirt)) == lmte)	/*look up in main table*/
			mmte();						/*not there, make new entry*/
		else
			if(lblpt->flags&SYER)		/*already there*/
				uerr(29);
		lblpt->flags |= SYGL;			/*symbol is an entry*/
		if(lblpt->flags&SYXR)			/*been thru hext code*/
			lblpt->flags &= ~(SYXR|SYDF);	/*reset for init of .comm*/
		if (inoffset && reloc != ABS) {	/* [vlh] */
			xerr(11);
			return;
		}
		if(fchr == ',')					/*skip ',' between entries*/
			fchr = gchr();
		else {
			igrst();					/*statement finished*/
			return;
		}
	}
}

/*process comm directive*/
hext()
{
	gterm(TRUE);					/*get external symbol*/
	if(itype!=ITSY) {				/*error if not symbol*/
		xerr(28);
		return;
	}
	if((lblpt=lemt(FALSE,sirt)) == lmte)	/*look up in main table*/
		mmte();						/*not there, make new entry*/
	else
		if(lblpt->flags&SYDF && (lblpt->flags&SYXR)==0)	/*already there*/
			uerr(29);
	lblpt->flags |= SYXR | SYDF;	/*symbol is an external*/
	mkextidx(lblpt);	/*put into external table*/
	if(fchr == ',') {				/*skip ',' between operands*/
		fchr = gchr();
		gterm(TRUE);
		if(itype != ITCN) {
			xerr(17);
			return;
		}
		lblpt->vl1 = ival;		/* # bytes of storage required*/
	}
	else
		lblpt->vl1 = 1;			/* default # bytes*/
	igrst();
}

mkextidx(p)
struct symtab *p;
{
	if(extindx >= EXTSZ) {	/*check for overflow of external symbol tbl*/
		rpterr("overflow of external table\n");
		endit();
	}
	p->vextno = (int)(pexti - extbl);	/* external symbol index #*/
	*pexti++ = p;		/*save external in external table*/
	extindx++;
}

/* end statement*/
hend()
{
	register short i;

	inoffset = 0;	/*[vlh] turn off inoffset mode*/
	lblpt = 0;	/*no label*/
	opitb();	/*output beginning of statement*/
	igrst();	/* [vlh] ignore operands */
	stbuf[0].itrl = itwc;	/*number of it entries*/
	wostb();	/*write out statement buffer*/
	if(pitix > itbuf)	/*some it in buffer*/
		if(write(itfn,itbuf,ITBSZ*(sizeof i)) != ITBSZ*(sizeof i)) {
			rpterr("I/O write error on it file\n");
			endit();
		}
	if(initflg) {
		putsymtab();
		printf("68000 assembler initialized\n");
		endit();
	}
	if((fchr=gchr())!=EOF)
		rpterr("end statement not at end of source\n");
	savelc[rlflg] = loctr;	/*last location on current reloc base*/
	fixunds();				/*make golbals and maybe undefineds external*/
	if(!didorg)				/*did not assign to location counter*/
		pass1a();			/*resolve short branches*/
	pass2();				/*assembler pass 2*/
}

/* define storage given number of bytes*/
hds()
{
	chkeven();			/*may need to make pc even*/
	dlabl();			/*define label maybe*/
	if (!inoffset)	/* [vlh] */
		opitb();		/*output it for beginning of statement*/
	refpc = 0;
	expr(&p1gi);
	if(itype!=ITCN) {
		xerr(17);		/*must be constant*/
		return;
	}
	if(reloc != ABS)  {
		xerr(9);		/*must be absolute*/
		return;
	}
	if (!inoffset) {	/* [vlh] don't generate it if in offset */
		opitoo();			/*output one operand*/
		stbuf[0].itrl = itwc;
		wostb();			/*write out statement buffer*/
	}
	loctr += (ival*modelen);
	igrst();
}

/* make pc even if necessary for .dc and .ds */
chkeven()
{
	register char *pi;

	if (modelen>BYTESIZ && (loctr&1)) {
		pi = opcpt;
		opcpt = evenptr;
		opitb();
		stbuf[0].itrl = itwc;
		wostb();
		opcpt = pi;
		loctr++;
	}
}

/* define byte directive*/
hdc()
{
	chkeven();
	hdata(modelen);
}

/*
 * define bytes or words of data
 *	call with:
 *		1 => defining bytes
 *		2 => defining words
 *		4 => defining long words
 */
hdata(mul)
int mul;
{
	dlabl();		/*define label*/
	opitb();		/*beginning of statement*/
	numops = 0;		/*initialize count for number of operands*/
	opito();		/*output it for operands*/
	stbuf[0].itrl = itwc;	/* # of it entries*/
	wostb();		/*write out statement buffer*/
	loctr += numops*mul;	/* count by bytes or words*/
}

/* handle org statement*/
horg()
{
	if(rlflg==TEXT && loctr!=0)
		didorg++;	/*can't do branch optimization as separate pass now*/
	expr(&p1gi);	/*value of new relocation counter*/
	if(reloc != rlflg && reloc != ABS) {
		xerr(27);
		return;
	}
	if(ival < loctr) {
		xerr(40);		/*trying to go backwards*/
		return;
	}
	opcpt = orgptr;		/*org directive for pass 2*/
	opitb();
	opitoo();
	stbuf[0].itrl = itwc;
	wostb();
	loctr = ival;
	dlabl();		/*define label*/
}

/* Assemble for mask2 (R9M), ignore... */
hmask2()	/* [vlh] */
{
	igrst();
}

/* Define register list */
hreg()		/* [vlh] */
{
	short mask;

	if(lbt[0]==0) {
		xerr(4);		/*no label*/
		return;
	}
	setname();					/*move label into main table*/
	if((lblpt=lemt(FALSE,sirt))!=lmte) {
		xerr(5);				/*opcode redefined*/
		return;
	}
	if (inoffset)
		if (reloc != ABS) {
			xerr(11);
			return;
		}
	mmte();						/*make main table entry*/
	if ((mask = mkmask()) == -1) {
		xerr(6);
		return;
	}
	lblpt->flags |= SYDF|SYEQ|SYRM;	/* register mask, defined & equated */
	lblpt->vl1 = mask;
	igrst();
}

short regmsk[] = {0100000,040000,020000,010000,04000,02000,01000,0400,0200,
				0100,040,020,010,4,2,1};
/* make a register mask for the reg routine */
mkmask()	/* [vlh] */
{
	register short *p, i, j, mask;

	p = &regmsk;	mask = 0;
	while ((i = chkreg()) != -1) {
		if (fchr == '-') {
			fchr = gchr();
			if ((j = chkreg()) == -1) {
				xerr(40);
				return(-1);
			}
			while (i <= j)
				mask |= p[i++];
		}
		else mask |= p[i];
		if (fchr != '/' && fchr != ',') break; /*[vlh] Signetics fix*/
		fchr = gchr();
	}
	return(mask);
}

/* get a register # from file, return -1 if none or illegal */
chkreg()	/* [vlh] */
{
	register short i, j;

	i = j = 0;
	if (fchr == 'a' || fchr == 'A')
		i = 8;
	else if (fchr != 'd' && fchr != 'r' && fchr != 'D' && fchr != 'R')
		return(-1);
	fchr = gchr();
	do {
		j = (j*10) + (fchr - '0');
		fchr = gchr();
	} while (isdigit(fchr));
	if (j < 0 || j > AREGHI) return(-1);
	i += j;
	if (i >= 0 && i <= AREGHI) return(i);
	else return(-1);
}

/* Define constant block */
hdcb()		/* [vlh] */
{
	chkeven();	/* on even boundary if not byte block. */
	dlabl();		/* define label... */
	opitb();
	opito();
	stbuf[0].itrl = itwc;
	numops = stbuf[ITOP1].itop;
	loctr += numops * modelen;
	wostb();		/* write out statement buffer */
}

/* Command line, similar to ds.b */
hcomline()	/* [vlh] */
{
	dlabl();			/*define label maybe*/
	modelen = BYTESIZ;		/* byte store... */
	opitb();			/*output it for beginning of statement*/
	refpc = 0;
	expr(&p1gi);
	if(itype!=ITCN) {
		xerr(17);		/*must be constant*/
		return;
	}
	if(reloc != ABS)  {
		xerr(9);		/*must be absolute*/
		return;
	}
	opitoo();			/*output one operand*/
	stbuf[0].itrl = itwc;
	wostb();			/*write out statement buffer*/
	loctr += ival;
	igrst();
}

/* Relocateable id record, ignore */
hidnt()	/* [vlh] */
{
	igrst();
}

/* Define offsets */
hoffset()	/* [vlh] */
{
	inoffset = 1;
	expr(&p1gi);	/* get new location counter */
	if (itype != ITCN) {
		xerr(17);	/* constant required */
		return;
	}
	if (reloc != ABS) {
		xerr(9);	/* must be absolute */
		return;
	}
	savelc[rlflg] = loctr;		/* Save old section loctr */
	loctr = ival;
	rlflg = ABS;				/* This section is absolute */
	igrst();
}

/* define sections: map to bss, text and data */
hsection()	/* [vlh] */
{
	inoffset = 0;	/* reseting section turns off offset mode */
	dlabl();		/* define label on old base if there is one */
	savelc[rlflg] = loctr;	/* save old base relocation */
	opitb();		/* intermediate table... */
	expr(&p1gi);	/* get section # */
	if (itype != ITCN) {
		xerr(17);	/* must be a constant */
		return;
	}
	if (ival > 15 || ival < 0) {
		xerr(9);	/* proper range 0..15 */
		return;
	}
	rlflg = (ival==14) ? DATA : (ival==15) ? BSS : TEXT;
	loctr = savelc[rlflg];
	stbuf[3].itop = loctr;		/* pass 1 location counter */
	stbuf[3].itrl = rlflg;		/* relocation base */
	stbuf[0].itrl = itwc;
	wostb();
	igrst();
}

/* hopt -- ignore, set up assembler options */
hopt()	/* vlh */
{
	igrst();
}
#ifndef	CPM				/*sw*/
/* hpage - page directive, ignore */
hpage()		/* vlh */
{
	igrst();
}
spage()
{
	return(0);
}
#endif

/* httl - title directive, ignore */
httl()	/* vlh */
{
	igrst();
}

/****	Second pass directive handling routines ****/

/* second pass end statement*/
send()
{
	register short i;

	savelc[rlflg] = loctr;
	if(savelc[TEXT]&1) {
		rlflg = TEXT;
		outbyte(0,DABS);
		savelc[TEXT]++;			/*SW need correct count here*/
	}
	if(savelc[DATA]&1) {
		rlflg = DATA;
		outbyte(0,DABS);
		savelc[DATA]++;			/*SW need correct count here*/
	}
	if(savelc[BSS]&1) {
		savelc[BSS]++;
	}
	ival = 0;
	reloc = ABS;
	ckeop(9);
	print(0);
	cpdata();			/*copy data to loader file*/
	osymt();			/*output symbol table*/
	myfflush(&tbuf);	/*flush text relocation bits*/
	cprlbits();			/*copy relocation bits*/
	myfflush(&lbuf);
	i = (sizeof couthd.ch_magic) + 3*(sizeof couthd.ch_tsize);
	if((lseek(lfn,(long)i,0) == -1L) || 			/*sw */
		write(lfn,&stlen,sizeof(stlen)) !=sizeof(stlen))
			rpterr("I/O error on loader output file\n");
	endit();			/*end*/
}

/*second pass define storage - ds*/
sds()
{
	print(0);
	if(rlflg == TEXT || rlflg==DATA) {
		expr(&p2gi);
		if(itype != ITCN) {
			uerr(13);
			return;
		}
		ival *= modelen;
		while(ival) {
			outbyte(0,DABS);
			loctr++;
			ival--;
		}
	}
	else
		loctr += stbuf[ITOP1].itop*modelen;		/*reserve storage*/
}

/* second pass - define block storage, initialized */
sdcb()	/* [vlh] */
{
	register short pfg, i, hflg, len;

	i = pfg = hflg = 0;
	expr(&p2gi);
	if (itype != ITCN || reloc != ABS) {
		uerr(13);	/* must be absolute constant */
		return;
	}
	len = ival;
	expr(&p2gi);
	if (modelen == BYTESIZ && (ival<-128 || ival>=256 || reloc != ABS)) {
		uerr(20);
		ival = 0;
		reloc = ABS;
	}
	while (len--) {
		if (modelen == BYTESIZ) {
			if (!hflg) {
				ins[i].hibyte = ival;
				outbyte((int)ival.loword,DABS);
				hflg++;
			}
			else {
				ins[i++].lobyte = ival;
				outbyte((int)ival.loword,DABS);
				hflg=0;
			}
			goto sdbl2;
		}
		else if (modelen == WORDSIZ) {
sdbl1:
			ins[i++] = ival.loword;
			outword((int)ival.loword, reloc);
sdbl2:
			if (i>3) {
				instrlen = i*2;
				print ((pfg++) ? 2 : 1);
				loctr += instrlen;
				i=0;
			}
		}
		else {		/* long word... */
			ins[i++] = ival.hiword;
			outword((int)ival.hiword,LUPPER);
			goto sdbl1;
		}
	}
	if (i) {	/* more printing */
		instrlen = i*2 - hflg;
		print ((pfg) ? 2 : 1);
		loctr += instrlen;
	}
}

/*second pass data*/
sdsect()
{
	savelc[rlflg] = loctr;
	rlflg = DATA;
	loctr = savelc[DATA];
	print(0);			/*print the new location counter*/
}

/*second pass text*/
spsect()
{
	savelc[rlflg] = loctr;
	rlflg = TEXT;
	loctr = savelc[TEXT];
	print(0);			/*print the new location counter*/
}

sbss()
{
	savelc[rlflg] = loctr;
	rlflg = BSS;
	loctr = savelc[BSS];
	print(0);			/*print the new location counter*/
}

/* make loctr even*/
seven()
{
	if(loctr&1) {
		if(rlflg==TEXT || rlflg==DATA)
			outbyte(0,DABS);
		loctr++;
	}
	print(0);
}

/* second pass org*/
sorg()
{
	register long l;

	if(rlflg==TEXT || rlflg==DATA) {	/*must put out zeros*/
		l = stbuf[ITOP1].itop - loctr;	/*# zeroes to output*/
		ins[0] = 0;
		print(1);
		while(l > 0) {
			outbyte(0,DABS);
			loctr++;
			l--;
		}
	}
	else {	/*BSS*/
		loctr = stbuf[ITOP1].itop;		/*new location counter*/
		print(0);
	}
}

/*
 *second pass define data (words or bytes)
 * call with
 *	2 => defining words
 *	1 => defining bytes
 *	4 => defining long words
 */
sdata(dtyp)
int dtyp;
{
	register short pfg,i, hflg;

	hflg = i = pfg = 0;
	while(1) {
		expr(&p2gi);			/*evaluate expression*/
		if(pitw < pnite)
			pitw--;		/*expr passed a token*/
		if(itype!=ITCN && reloc != EXTRN) {	/*must be constant*/
			uerr(13);
			ival=0;
			reloc = ABS;
		}
		if(reloc == EXTRN)
			reloc = (extref<<3)|EXTVAR;	/*gen extern reference*/
		if(dtyp==1) {			/*defining a byte*/
			if(ival<-128 || ival>=256 || reloc!=ABS) {	        /*not a byte*/
				uerr(20);
				ival=0;
				reloc = ABS;
			}
			if(!hflg) {
				ins[i].hibyte = ival;
				outbyte((int)ival.loword,DABS);
				hflg++;
			}
			else {
				ins[i++].lobyte = ival;
				hflg = 0;
				outbyte((int)ival.loword,DABS);
			}
			goto sdal2;
		}
		else if(dtyp == 2) {	/*defining a word*/
sdal1:
			ins[i++] = ival.loword;
			outword((int)ival.loword, reloc);
sdal2:
			if(i>3) {
				instrlen = i*2;
				print ((pfg++) ? 2 : 1);
				loctr += instrlen;
				i=0;
			}
		}
		else {	/*long words*/
			ins[i++] = ival.hiword;
			outword((int)ival.hiword,LUPPER);
			goto sdal1;
		}
		if(!ckeop(15))	/*should be end of operand*/
			return;
		pitw++;
		if(ckein()) {
			if(hflg) {
				ins[i++].lobyte = 0;
			}
			if(i) {		/*more printing*/
				instrlen = i*2 - hflg;
				print ((pfg) ? 2 : 1);
				loctr += instrlen;
			}
			return;
		}
	}
}

sdc()
{
	sdata(modelen);
}

ssection()	/* [vlh] */
{
	short sect;

	sect = stbuf[3].itrl;
	if (sect==DATA) 
		sdsect();
	else if (sect==BSS) 
		sbss();
	else 
		spsect();
}

/****	Conditional assembly directives ****/

hifeq()	/* [vlh] */
{
	if (!acok()) 
		return;
	if (ival) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hifne()	/* [vlh] */
{
	if (!acok()) 
		return;
	if (!ival) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hiflt()	/* [vlh] */
{
	if (!acok()) 
		return;
	if (ival >= 0) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hifle()	/* [vlh] */
{
	if (!acok()) 
		return;
	if (ival > 0) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hifgt()	/* [vlh] */
{
	if (!acok()) 
		return;
	if (ival <= 0) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hifge()	/* [vlh] */
{
	if (!acok()) 
		return;
	if (ival < 0) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hifc()	/* [vlh] */
{
	if (!cmp_ops()) {
		if (ca_true) ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hifnc()	/* [vlh] */
{
	if (cmp_ops()) {
		if (ca_true) 
			ca_level = ca;
		ca_true = 0;
	}
	ca++;
}

hendc()	/* [vlh] */
{
	if (!ca) {
		xerr(25);	/* unexpected endc */
		return;
	}
	ca--;
	if (!ca_true)
		if (ca_level == ca) ca_true = 1;
	igrst();
}

acok()
{
	expr(&p1gi);
	if (itype != ITCN) {
		xerr(7);	/* must be a constant */
		return(0);
	}
	if (reloc != ABS) {
		xerr(11);	/* must be absolute, no forward references */
		return(0);
	}
	igrst();
	return(1);
}

cmp_ops()				/* return 1 true, 0 false */
{
	char str1[25], str2[25];
	register short len1, len2;

	if (fchr != '\'') { 
		xerr(9); 
		return(0);
	}
	len1 = len2 = 0;
	while ((fchr = gchr()) && fchr != '\'') {
		if (fchr == EOLC) 
			return(0);
		str1[len1++] = fchr;
	}
	if ((fchr=gchr()) != ',') {
		xerr(9); 
		return(0); 
	}
	if ((fchr=gchr()) != '\'') { 
		xerr(10); 
		return(0);
	}
	while ((fchr = gchr()) && fchr != '\'') {
		if (fchr == EOLC) 
			return(0);
		str2[len2++] = fchr;
	}
	igrst();
	if (len1 != len2) 
		return(0);
	str1[len1] = str2[len2] = NULL;
	return((strcmp(str1,str2) == 0));
}

strcmp(s,t)
register char *s, *t;
{
	for( ; *s == *t; s++, t++ )
		if( *s == '\0' )
			return(0);
	return( *s - *t );
}
