File:  [MW Coherent from dump] / coherent / b / bin / c / n2 / i8086 / asm.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * The routines in this file assemble buffered code
 * and write the code to the output file.
 * This version is for the SMALL and LARGE models of segmentation.
 */

#ifdef   vax
#include "INC$LIB:cc2.h"
#else
#include "cc2.h"
#endif

#define	W	0x01			/* W (word) bit */
#define	D	0x02			/* D (direction) bit */
#define	ESC	0xD8			/* Escape */
#define	WAIT	0x9B			/* Wait */

static	ADDRESS	pc;			/* Current assembly pc */
static	ADDRESS	pcdot[NSEG];		/* Working copy of seg '.' fields */
static	int	pcseg;			/* Current segment */
static	int	pass;			/* Pass flag; only 1 emits code */

extern	int	hasfloat;		/* function uses floating point */

/*
 * Driving routine.
 * Run pass 0 of the assembly to get sizes.
 * All jumps are assumed to be short.
 * Fix up any that don't reach.
 * Run the second assembly pass to generate the final code.
 */
genfunc()
{
	register INS	*ip1, *ip2;
	register int	i;

	pc = dot;
	pass = 0;
	pcseg = dotseg;
	for (i=0; i<NSEG; ++i)
		pcdot[i] = seg[i].s_dot;
	ip1 = ins.i_fp;
	while (ip1 != &ins) {
		assemble(ip1);
		ip1 = ip1->i_fp;
	}
	sdi();
	pc = dot;
	pass = 1;
	pcseg = dotseg;
	for (i=0; i<NSEG; ++i)
		pcdot[i] = seg[i].s_dot;
	ip1 = ins.i_fp;
	while (ip1 != &ins) {
		asmdbgt(ip1);
		if (isvariant(VASM))
			unassemble(ip1);
		else
			assemble(ip1);
		ip2 = ip1->i_fp;
		free((char *) ip1);
		ip1 = ip2;
	}
	asmdbgt(&ins);
}

/*
 * Generate code for a single instruction.
 * Used to compile external data definitions, etc.
 */
genins(ip)
register INS	*ip;
{
	register int	i;

	for (pass=0; pass!=2; ++pass) {
		pc = dot;
		pcseg = dotseg;
		for (i=0; i<NSEG; ++i)
			pcdot[i] = seg[i].s_dot;
		if (isvariant(VASM) && pass != 0) {
			if (ip->i_type != LINE
			|| isvariant(VLINES))
				unassemble(ip);
		} else
			assemble(ip);
	}
}

/*
 * This function fixes up the span dependent instructions.
 * The only case on the iAPX-86 is the jump, which has limited range.
 * There is nothing to be done with the adjustable displacements,
 * bacause these are always absolute and do not change.
 */
sdi()
{
	register INS	*ip1, *ip2;
	register SYM	*sp;
	register int	bump, changes;
	SIGNEDADDRESS	disp;

	do {
		changes = 0;
		ip1 = ins.i_fp;
		while (ip1 != &ins) {
			if (isoptjump(ip1)) {
				if ((sp=ip1->i_sp) == NULL)
					cbotch("sdi");
				if (ip1->i_pcseg != sp->s_seg)
					cbotch("x seg #1");
				disp = sp->s_value-ip1->i_pc-2;
				if (disp<-128 || disp>127) {
					ip1->i_long = 1;
					changes = 1;
					bump = 1;
					if (ip1->i_rel != ZJMP)
						bump = 3;
					ip2 = ip1->i_fp;
					while (ip2 != &ins) {
						sdibump(ip1, ip2, bump);
						ip2 = ip2->i_fp;
					}
				}
			}
			ip1 = ip1->i_fp;
		}
	} while (changes);
}

/*
 * This routine performs the nitty gritty
 * of bumping an instruction to a higher address because
 * an sdi changed from short to long.
 * The 'ip1' argument is a pointer to the INS of the jump.
 * The 'ip2' argument is the node to be bumped by 'bump' bytes.
 * Only labels and code in the same segment as the 'ip1' node are adjusted.
 */
sdibump(ip1, ip2, bump)
register INS	*ip1;
register INS	*ip2;
{
	register int	type;
	register SYM	*sp;

	if ((type=ip2->i_type) == LLABEL) {
		if ((sp=ip2->i_sp) == NULL)
			cbotch("sdibump");
		if (sp->s_seg == ip1->i_pcseg)
			sp->s_value += bump;
	} else if (type==JUMP || type==CODE) {
		if (ip2->i_pcseg == ip1->i_pcseg)
			ip2->i_pc += bump;
	}
}

/*
 * This routine checks if a node is an optimizable short jump.
 * The node must be a jump,
 * it must be short and it must either be the unconditional
 * jump or one of the jumps that has a reverse.
 */
isoptjump(ip1)
register INS	*ip1;
{
	register int	rel;

	if (ip1->i_type==JUMP && ip1->i_long==0) {
		rel = ip1->i_rel;
		if (rel!=ZJCXZ && rel!=ZLOOP && rel!=ZLOOPE && rel!=ZLOOPNE)
			return (1);
	}
	return (0);
}

/*
 * Assemble a line.
 * If pass 1 the binary goes straight out.
 * The ip1 argument points to the INS node that is to be assembled. 
 */
assemble(ip1)
register INS	*ip1;
{
	SIGNEDADDRESS	disp;
	int	opbits;
	int	escape;
	OPINFO	*opinfop;
	int	opcode;
	SYM	*sp;
	int	ostyle;
	AFIELD	a1;
	int	prefix;
	int	m1, m2, regm, rn;
	int	shortflag;
	sizeof_t length;
	int	segreg;
	int	m3;

	switch (ip1->i_type) {

	case ENTER:
		pcdot[pcseg] =  pc;
		pcseg = ip1->i_seg;
		pc =  pcdot[pcseg];
		if (pass != 0)
			genseg(pcseg);
		break;

	case BLOCK:
		if ((length=ip1->i_len) != 0) {
			if (pcseg == SBSS) {
				pc += length;
				if (pass != 0)
					dot += length;
			} else {
#if	0			/* i8086 outnzb() not implemented yet */
				outnzb(length);
#else
				do {
					asmab(0);
				} while (--length);
#endif
			}
		}
		break;

	case ALIGN:
		if ((pc&01) != 0) {
			if (pcseg == SBSS) {
				++pc;
				if (pass != 0)
					++dot;
			} else
				asmab(0);
		}
		break;

	case JUMP:
		ip1->i_pc = pc;
		ip1->i_pcseg = pcseg;
		if ((sp=ip1->i_sp) == NULL) {
			sp = llookup(ip1->i_labno, 0);
			ip1->i_sp = sp;
		}
		if (pass != 0) {
			if (sp==NULL || (sp->s_flag&S_DEF)==0)
				cbotch("undef");
			if (ip1->i_long == 0) {	
				if (sp->s_seg != ip1->i_pcseg)
					cbotch("x seg #2");
				disp = sp->s_value - pc - 2;
				if (disp<-128 || disp>127)
					cbotch("reach, disp=%d", disp);
			}
		}
		opbits = opinfo[ip1->i_rel].op_opcode;
		if (ip1->i_long == 0) {
			asmab(opbits);
			asmab(disp);
		} else {
			if (ip1->i_rel != ZJMP) {
				asmab(opbits ^ 01);
				asmab(03);
			}
			asmab(0xE9);	/* Jump */
			a1.a_mode = A_DIR;
			a1.a_sp = sp;
			a1.a_value = 0;
			asmxw(&a1, 1);
		}
		break;

	case LLABEL:
		if ((sp=ip1->i_sp) == NULL) {
			sp = llookup(ip1->i_labno, 1);
			ip1->i_sp = sp;
		}
		sp->s_seg = pcseg;
		sp->s_value = pc;
		break;

	case LLLINK:
		if ((sp=ip1->i_sp) == NULL) {
			sp = llookup(ip1->i_labno, 0);
			ip1->i_sp = sp;
		}
		if (pass!=0 && (sp==NULL || (sp->s_flag&S_DEF)==0))
			cbotch("undef");
		a1.a_mode = A_DIR;
		a1.a_sp = sp;
		a1.a_value = 0;
		asmxw(&a1, 0);
		break;

	case CODE:
		ip1->i_pc = pc;
		ip1->i_pcseg = pcseg;
		opcode = ip1->i_op;
		opinfop = &opinfo[opcode];
		opbits = opinfop->op_opcode;
		switch (ostyle = opinfop->op_style) {
	
		case OF_INH2:
			asmab(opbits);
			asmab(0x0A);
			break;

		case OF_INH:
			asmab(opbits);
			break;
	
		case OF_PUSH:
		case OF_POP:
			m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
			rn = ip1->i_af[0].a_mode&A_REGM;
			if (isvariant(V80186)) {
				if ((ostyle == OF_PUSH) && (m1 == A_IMM)) {
					if (isshort(&ip1->i_af[0])) {
						asmab(0x6A);
						asmxb(&ip1->i_af[0], 0);
					}
					else {
						asmab(0x68);
						asmxw(&ip1->i_af[0], 0);
					}
					break;
				}
			}
			if (m1 == A_SR) {
				if (ostyle == OF_PUSH)
					asmab(0x06 | (rn<<3));
				else
					asmab(0x07 | (rn<<3));
				break;
			}
			if (m1 == A_WR) {
				if (ostyle == OF_PUSH)
					asmab(0x50 | rn);
				else
					asmab(0x58 | rn);
				break;
			}
			if (ostyle == OF_PUSH)
				asmgen(0xFF, 0x30, &ip1->i_af[0]);
			else
				asmgen(0x8F, 0x00, &ip1->i_af[0]);
			break;
	
		case OF_SHR:
			prefix = 0xD0 | (opbits&W);
			opbits &= ~W;
			if (ip1->i_af[1].a_mode == A_RCL)
				prefix |= 0x02;
			else if ((ip1->i_af[1].a_mode&A_AMOD) != A_IMM
			     ||   (notvariant(V80186) && ip1->i_af[1].a_value != 1)
			     ||   ip1->i_af[1].a_sp != NULL)
				aerr(ip1);
			if (isvariant(V80186)) {
				disp = ip1->i_af[1].a_value;
				if ((ip1->i_af[1].a_mode != A_RCL) && (disp != 1)) {
					/* 286 shift immediate */
				     	prefix &= 0xEF;	/* Change 0xD0|W to 0xC0|W */
					asmgen(prefix, opbits, &ip1->i_af[0]);
					/* Be wary of shift counts > 16 */
					asmab((disp <= 16) ? disp : 16);
					break;
				}
			}
			asmgen(prefix, opbits, &ip1->i_af[0]);
			break;
	
		case OF_ICALL:
			asmgen(0xFF, opbits, &ip1->i_af[0]);
			break;
	
		case OF_CALL:
			if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR)
				aerr(ip1);
			asmab(0xE8);
			asmxw(&ip1->i_af[0], 1);
			break;

		case OF_XCALL:
			if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR)
				aerr(ip1);
			asmab(0x9A);
			asmxw(&ip1->i_af[0], 0);
			asmsb(&ip1->i_af[0]);
			break;

		case OF_DOPS:
		case OF_DOP:
			m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
			m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX);
			if (m2 == A_IMM) {
				shortflag = 0;
				if (isalax(&ip1->i_af[0])) {
					/* Test[b] */
					if (opbits == 0x85)
						opbits = 0xA9;
					else if (opbits == 0x84)
						opbits = 0xA8;
					else
						opbits |= 0x04;
					asmab(opbits);
				} else {
					/* Test[b] */
					if (opbits==0x84 || opbits==0x85) {
						regm = 0;
						if (opbits == 0x84)
							opbits = 0xF6;
						else
							opbits = 0xF7;
					} else {
						regm = opbits & 0x38;
						opbits = (opbits&W)|0x80;
						if (ostyle == OF_DOPS
						&&  isshort(&ip1->i_af[1])) {
							shortflag = 1;
							opbits |= 0x02;
						}
					}
					asmgen(opbits, regm, &ip1->i_af[0]);
				}
				if (shortflag || (opbits&W)==0)
					asmxb(&ip1->i_af[1], 0);
				else
					asmxw(&ip1->i_af[1], 0);
				break;
			}
			/* To reg */
			if (m1==A_BR || m1==A_WR) {
				/* Test[b] */
				if (opbits!=0x84 && opbits!=0x85)
					opbits |= 0x02; /* D */
				asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3,
					&ip1->i_af[1]);
				break;
			}
			/* To mem */
			asmgen(opbits, (ip1->i_af[1].a_mode&A_REGM)<<3,
				&ip1->i_af[0]);
			break;

		case OF_MUL3:
			if (notvariant(V80186))
				aerr(ip1);
			m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
			m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX);
			m3 = ip1->i_af[2].a_mode&(A_AMOD|A_PREFX);
			if (m1 != A_WR || m3 != A_IMM)
				aerr(ip1);
			shortflag = 0;
			if (isshort(&ip1->i_af[2])) {
				shortflag = 1;
				opbits |= 0x02;	/* Change 0x69 to 0x6B */
			}
			asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3, &ip1->i_af[1]);
			if (shortflag)
				asmxb(&ip1->i_af[2], 0);
			else
				asmxw(&ip1->i_af[2], 0);
			break;

		case OF_SOP:
			m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
			prefix = ((opbits<0x10)?0xFE:0xF6) | (opbits&W);
			opbits &= ~W;
			if (prefix==0xFF && m1==A_WR) {
				asmab(0x40 | opbits |
					(ip1->i_af[0].a_mode&A_REGM));
				break;
			}
			asmgen(prefix, opbits, &ip1->i_af[0]);
			break;
	
		case OF_LEA:
			m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
			m2 = ip1->i_af[1].a_mode&A_AMOD;
			if (m1!=A_WR || (m2!=A_DIR && m2!=A_X))
				aerr(ip1);
			asmgen(opbits, (ip1->i_af[0].a_mode&A_REGM)<<3,
				&ip1->i_af[1]);
			break;
	
		case OF_MOV:
			m1 = ip1->i_af[0].a_mode&(A_AMOD|A_PREFX);
			m2 = ip1->i_af[1].a_mode&(A_AMOD|A_PREFX);
			if (m2 == A_IMM) {
				if (m1 == A_BR) {
					asmab(0xB0 |
						(ip1->i_af[0].a_mode&A_REGM));
					asmxb(&ip1->i_af[1], 0);
					break;
				}
				if (m1 == A_WR) {
					asmab(0xB8 |
						(ip1->i_af[0].a_mode&A_REGM));
					asmxw(&ip1->i_af[1], 0);
					break;
				}
				/* To mem */
				asmgen((0xC6 | (opbits&W)), 0, &ip1->i_af[0]);
				if ((opbits&W) == 0)
					asmxb(&ip1->i_af[1], 0);
				else
					asmxw(&ip1->i_af[1], 0);
				break;
			}
			if (isalax(&ip1->i_af[0]) && m2==A_DIR) {
				asmprefix(&ip1->i_af[1]);
				asmab(0xA0 | (opbits&W));
				asmxw(&ip1->i_af[1], 0);
				break;
			}
			if (m1==A_DIR && isalax(&ip1->i_af[1])) {
				asmprefix(&ip1->i_af[0]);
				asmab(0xA2 | (opbits&W));
				asmxw(&ip1->i_af[0], 0);
				break;
			}
			if (m1 == A_SR) {
				if (m2 != A_SR) {
					asmgen(0x8E, (ip1->i_af[0].a_mode&A_REGM)<<3,
						&ip1->i_af[1]);
				}
				else {	/* Kludge MOV SR1, SR2
					 * into PUSH SR2, POP SR1.
					 * This should not happen but
					 * better safe than sorry...
					 */
					asmab(0x06 | ((ip1->i_af[1].a_mode&A_REGM)<<3));
					asmab(0x07 | ((ip1->i_af[0].a_mode&A_REGM)<<3));
				}
			}
			else if (m2 == A_SR)
				asmgen(0x8C, (ip1->i_af[1].a_mode&A_REGM)<<3,
					&ip1->i_af[0]);
			else if (m1==A_WR || m1==A_BR)
				asmgen(opbits|D,
					(ip1->i_af[0].a_mode&A_REGM)<<3,
					&ip1->i_af[1]);
			else
				asmgen(opbits,
					(ip1->i_af[1].a_mode&A_REGM)<<3,
					&ip1->i_af[0]);
			break;
	
		case OF_MUL:
			prefix = 0xF6 | (opbits&W);
			opbits &= ~W;
			asmgen(prefix, opbits, &ip1->i_af[0]);
			break;
	
		case OF_WORD:
		case OF_BYTE:
		case OF_LPTR:
		case OF_GPTR:
			if ((ip1->i_af[0].a_mode&(A_AMOD|A_PREFX)) != A_DIR)
				aerr(ip1);
			if (ostyle == OF_BYTE)
				asmxb(&ip1->i_af[0], 0);
			else {
				asmxw(&ip1->i_af[0], 0);
				if (ostyle == OF_GPTR)
					asmsb(&ip1->i_af[0]);
			}
			break;

		/*
		 * 8087 or 80287 floating point operations.
		 * See comments preceding "asmfwait()" below.
		 */
		case OF_FWAIT:
			asmfwait();
			break;

		case OF_FD9:
			asmfop(0xD9, 0);
			asmab(opbits);
			break;

		case OF_FDD:
			asmfop(0xDD, 0);
			asmab(opbits);
			break;

		case OF_FDE:
			asmfop(0xDE, 0);
			asmab(opbits);
			break;

		case OF_FRM:
			escape = ESC | (opbits&0x07);
			if ((ip1->i_af[0].a_mode&A_PREFX) != 0) {
				prefix = ip1->i_af[0].a_mode&A_PREFX;
				segreg = (prefix>>8) - 1;
				asmfop(0x26|(segreg<<3), prefix);
				asmab(escape);
			} else
				asmfop(escape, 0);
			asmgen(-1, opbits&0x38, &ip1->i_af[0]);
			break;

		default:
			cbotch("cannot assemble %d", opcode);
		}
	}
}

/*
 * General output.
 * Understands MOD/R/M bytes and all that.
 * An opcode of -1 is a flag that says don't put
 * out the opcode and treat a register address field as an error.
 * It is used for the 8087.
 * The r field is preshifted left by 3 bits.
 */
asmgen(op, r, afp)
register AFIELD	 *afp;
{
	SIGNEDADDRESS	disp;
	int 	mode, regm;

	if (op >= 0) {
		asmprefix(afp);
		asmab(op);
	}
	mode = afp->a_mode & A_AMOD;
	regm = afp->a_mode & A_REGM;
	if (mode==A_IMM || mode==A_SR)
		cbotch("asmgen op=%d r=%d mode=%d regm=%d",
			op, r, mode, regm);
	if (mode==A_BR || mode==A_WR) {
		if (op < 0)
			cbotch("asmgen");
		asmab(0xC0 | r | regm);
		return;
	}
	if (mode == A_DIR) {
		asmab(0x06 | r);
		asmxw(afp, 0);
		return;
	}
	if (afp->a_sp == NULL) {
		disp = afp->a_value;
		if (regm!=6 && disp==0) {
			asmab(r | regm);
			return;
		}
		if (disp>=-128 && disp<=127) {
			asmab(0x40 | r | regm);
			asmab(disp);
			return;
		}
	}
	asmab(0x80 | r | regm);
	asmxw(afp, 0);
}

/*
 * Given an address field description,
 * look at the A_PREFX field of the mode and
 * output an escape prefix byte, if one is required.
 * The codes assigned to the segment registers have been cleverly chosen
 * so that code-1 is the right number to put in the prefix byte.
 */
asmprefix(afp)
register AFIELD	*afp;
{
	register int	segreg;

	if ((afp->a_mode&A_PREFX) != 0) {
		segreg = ((afp->a_mode&A_PREFX)>>8) - 1;
		asmab(0x26 | (segreg<<3));
	}
}

/*
 * Output an absolute byte.
 * Toss the byte away if this is not the second pass.
 * Check for compiling code into the bss segment.
 */
asmab(b)
{
	if (pass != 0) {
		berr();
		outab(b);
	}
	++pc;
}

/*
 * Output an absolute word.
 * Toss the word away if this is not the second pass.
 * Check for compiling code into the bss segment.
 */
asmaw(w)
{
	if (pass != 0) {
		berr();
		outaw(w);
	}
	pc += 2;
}

/*
 * Output a general byte.
 * The 'afp' argument is a pointer to an 'afield'.
 * The 'flag' is true for pc relative addressing.
 */
asmxb(afp, flag)
register AFIELD	*afp;
{
	if (pass != 0) {
		berr();
		outxb(afp->a_sp, afp->a_value, flag);
	}
	++pc;
}

/*
 * Output a general word.
 * The 'afp' parameter is a pointer to an 'afield'.
 * The 'flag' is true for pc relative addressing.
 */
asmxw(afp, flag)
register AFIELD	*afp;
{
	if (pass != 0) {
		berr();
		outxw(afp->a_sp, afp->a_value, flag);
	}
	pc += 2;
}

/*
 * Output a segment base.
 */
asmsb(afp)
register AFIELD *afp;
{
	register SYM	*sp;

	if (pass != 0) {
		berr();
		if ((sp=afp->a_sp) == NULL)
			outaw(0);
		else
			outsb(sp);
	}
	pc += 2;
}

/*
 * Notes on 8087 and 80287 opcode generation:
 * The 8086 does not check the coprocessor BUSY line when it encounters
 * a coprocessor escape (an 8087 opcode).
 * Therefore, an FWAIT must precede every 8087 opcode.
 * Sequences which require coprocessor synchronization
 * (e.g., awaiting completion of store from 8087 to 8086 memory)
 * can include explicit FWAITs which do not precede 8087 ops.
 * The 80286 checks its coprocessor BUSY line when it sees an 80287 opcode.
 * Therefore, the 80287 does not require an FWAIT before each 80287 opcode,
 * but explicit FWAITs are still required for synchronization.
 *
 * If EMUFIXUPS is true when the compiler is built,
 * the OMF output writer targets the FWAIT which precedes an 8087 opcode
 * with a magic "M:..." fixup;
 * this happens only in the OMF output writer n1/i8086/outomf.c.
 * The linker can then create objects which use either 8087 hardware
 * or software floating point emulation.  In the latter case, the
 * linker changes the 8087 instructions into traps to the emulator.
 *
 * If the compile-time variant VEMU87 is set,
 * the compiler writes "call emu87" before each 8087 opcode
 * and suppresses the leading FWAIT.
 * The emulator "emu87" can execute "fwait; ret" or replace "call emu87" with
 * "nop; nop; fwait" if an 8087 is actually present at runtime.
 */

/*
 * Output an explicit FWAIT opcode for the 8087.
 * The byte will be fiddled by an M:_WT fixup #if EMUFIXUPS.
 */
asmfwait()
{
	hasfloat = 1;
	if (isvariant(VEMU87)) {
		asmemucall();		/* call emu87 */
		return;			/* and suppress the FWAIT */
	}
	if (pass != 0) {
		berr();
		outfb(WAIT);
	}
	++pc;
}

/*
 * Output an 8087 opcode for the 8087.
 * The "prefix" argument is just the A_PREFX code from the address.
 * The opcode will be preceded by an FWAIT if necessary,
 * and the FWAIT will be fiddled by an M:_W?S fixup #if EMUFIXUPS.
 */
asmfop(op, prefix)
{
	hasfloat = 1;
	if (isvariant(VEMU87)) {
		asmemucall();		/* call emu87 */
		if (pass != 0)
			outfb(op);	/* and suppress FWAIT */
		pc++;
		return;
	}
#if	!EMUFIXUPS
	if (isvariant(V80287)) {
		if (pass != 0) {
			berr();
			outfb(op);	/* also suppress FWAIT for 80287 */
		}
		pc++;
		return;
	}
#endif
	if (pass != 0) {
		berr();
		outfw(op<<8|WAIT, prefix);
	}
	pc += 2;
}

/*
 * Assemble a call to the IEEE software floating point 8087 emulator.
 */
asmemucall(){
	if (pass != 0) {
		berr();
		outemucall();
	}
	pc += (isvariant(VSMALL)) ? 3 : 5;
}

/*
 * Output a call to the 8087 emulator.
 * Called from above and from genepilog (for FWAIT in epilog).
 */
outemucall(){
	static SYM *emu87p;

	if (emu87p == NULL)
		emu87p = glookup("emu87", 0);
	if (isvariant(VSMALL)) {	/* SMALL model */
		outab(0xE8);		/* near call */
		outxw(emu87p, 0, 1);	/* emu87, pc-relative */
	} else {			/* LARGE model */
		outab(0x9A);		/* far call */
		outxw(emu87p, 0, 0);	/* offset, absolute */
		outsb(emu87p);		/* segment */
	}
}

aerr(ip1)
register INS *ip1;
{
	register SYM	*sp;
	register int	i;

	printf("aerr: op=%d\n", ip1->i_op);
	for (i=0; i<ip1->i_naddr; ++i) {
		printf("Operand %d:", i);
		printf(" mode=%04x", ip1->i_af[i].a_mode);
		printf(" offs=%d",  ip1->i_af[i].a_value);
		if ((sp=ip1->i_af[i].a_sp) != NULL) {
			if ((sp->s_flag&S_LABNO) != 0)
				printf(" off L%d", sp->s_labno);
			else
				printf(" off %s", sp->s_id);
		}
		printf("\n");
	}
	cbotch("aerr");
}

berr()
{
	if (pcseg == SBSS)
		cbotch("bss");
}

isalax(afp)
register AFIELD *afp;
{
	if (afp->a_mode==A_RAX || afp->a_mode==A_RAL)
		return (1);
	return (0);
}

/*
 * This routine checks if the argument AFIELD is a valid short word immediate,
 * as used by the special s:w encoding on some instructions.
 * True return if so.
 * The legality of the mode and the fact that
 * the AFIELD is an immediate have already been checked.
 */
isshort(afp)
register AFIELD *afp;
{
	register ADDRESS value;

	if (afp->a_sp == NULL) {
		value = afp->a_value & 0xFF80;		/* Top 9 */
		if (value==0xFF80 || value==0x0000)
			return (1);
	}
	return (0);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.