/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
 /* $Header:ascode.c 12.0$ */
 /* $ACIS:ascode.c 12.0$ */
 /* $Source: /ibm/acis/usr/src/bin/as_ca/RCS/ascode.c,v $ */
#ifndef lint
static char rcsid[] = "$Header:ascode.c 12.0$";
#endif
/* $Source: /ibm/acis/usr/src/bin/as_ca/RCS/ascode.c,v $ */
/*
 *	Copyright (c) 1982 Regents of the University of California
 */
#ifndef lint
static char sccsid[] = "@(#)ascode.c 4.11 6/30/83";
#endif not lint

#include <stdio.h>
#include "as.h"
#include "assyms.h"

extern	int	d4error;	/* note failure of -d4 and get of $data */
extern	int	strictbounds;	/* Must displacements be correct? */
int	load_store_flag = 0;	/* signal putins to relocate the disp */
int	get_flag = 0;		/* signal putins that CAL is from a get */

#define	U4BIT_VAL(x)	( (x)>=0 && (x)<=15 )
#define NO_MSG		0
#define W_MSG		1

insout(opcode, ap, nact, itoktype)
	struct	Opcode	opcode;		/* defined in as.h */
	struct	arg	*ap;		/* also defined in as.h */
	int	nact;			/* number of actual arguments */
	int	itoktype;		/* instruction token type */
{
	reg	struct	instab	*ip;	/* the instruction (defined inas.h) */
	reg	struct	arg	*ap_walk;  /* actual param walk */
	reg	int	i;
	reg	int	ap_type;	/* actual param type */
	reg	int	ap_type_mask;	/* masked actual param */
		int	instr_opnd;	/* operand type from instab */
		int	idelta;		/* used to calculate operand number */

	idelta = extendedop ? -1 : 0 ;	/* flag for extended mnemonics
					   which is set in asparse.c */
	if (itoktype == ISPEC) {  /* Special macro instructions */
		macro(&opcode, ap, nact);
		return;
	/*
	 * It would have been better to define ISPEC's via
	 * OP rather than PSEUDO, and define the argument types in instrs.
	 * The following code could then have been used to check number and
	 * type of arguments.
	 */
	}

	if (!(ITABCHECK(opcode)))
		panic("Botched reference into itab");
	ip = ITABFETCH(opcode);	/* get pointer to instruction
				   in instab */
	if (nact < ip->i_nargs)
		yyerror("Too few arguments");
	if (nact > ip->i_nargs) {
		yyerror("Too many arguments");
		nact = ip->i_nargs;
	}
	    /*
	     *	Check argument compatability with instruction template
	     */
	if (passno == 1) /* do pass 1 checks, primarily format of args */
	    for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){
		ap_type = ap_walk->a_atype;
		if (ap_type&AINDX) {
			yyerror("Indexing not valid for operand %d",i+idelta);
		}
		if (ap_type&ALEN) {
		yyerror("Length specification not valid, operand %d",i+idelta);
		}
		ap_type_mask = ap_type & ~(AINDX|ALEN);
		instr_opnd=fetcharg(ip, i-1);  /* get the next argument */

		switch( (instr_opnd & ARGTMASK) >> ACCTLN){
		case ARGTI >> ACCTLN:
			switch(ap_type_mask) {
			   case AEXP:
			   case AIMM:
				break;
			   default:
				yyerror("Invalid format for immediate operand, operand %d",i+idelta);
				break;
			 }
			 break;
		case ARGTG >> ACCTLN:
			if (ap_type_mask != AREG) {
				yyerror("Invalid format for register operand, operand %d",i+idelta);
			}
			break;
		case ARGTX >> ACCTLN:
			switch(ap_type_mask) {
			   case AEXP:
				if (lastnam == 0 && opcode.Op_eopcode != ESBA)
				   yyerror("Destination not a label");
				break;
			   default:
				yyerror("Invalid format for address operand, operand %d",i+idelta);
				break;
			}
			break;
		case ARGTA >> ACCTLN:
			switch(ap_type_mask) {
			   case ADISP:
			   case ALIT:
			   case AEXP:
				break;
			   default:
				yyerror("Invalid format for address operand, operand %d",i+idelta);
				break;
			}
		} /* end of switch or arg type (pass 1) */
	   }		/* end of arg walk pass 1 */

	if (itoktype == IJXXX)
		ijxout(opcode, ap, nact);
	else
		putins(opcode, ap, nact);		
}

macro(opcodep, ap, nact)
	struct	Opcode	*opcodep;
	register struct arg *ap;
	int	nact;
{
	reg	int	i;
	struct	exp	*xp;
	struct	exp	*locxp;
	struct	Opcode	opcode;
	struct	arg	*firstarg;	/* remeber what is passed */
	struct	arg	*ap1, *ap2;	/* pointer to first and second
					   arguments */
	int	saved_xvalue;		/* saves xp->e_xvalue */
	int	saved_areg1;		/* saves ap->a_areg1 */
	int	spec_op;		/* which special code */
	short	low;			/* low half of 32-bit addr
					   for load/store macros; logic
					   depends on sign-extension
					   of the short value, so don't
					   make it an int! */

	opcode = *opcodep;
	firstarg = ap;

	if (nact < 2) yyerror("Two or three arguments required");
	if (ap->a_atype != AREG) 
		yyerror("First argument must be a register");
	ap1 = ap++; /* save the first and get the second arg */
	xp = ap->a_xp;
	if ((opcode.Op_popcode & (GET_PUT|LD_STO))== GET_PUT) {	/* begin IF */ 
		/* JSW added support for AIMIND type '$expr(rx)' */
		if (ap->a_atype == AIMM || ap->a_atype == AIMIND) {
			u_char	specop = opcode.Op_popcode;
			opcode = imops[specop & GP_MSK];
			if (ap->a_atype == AIMM)
				ap->a_areg1 = 0;
			if (specop==GET_SPEC)
				get_flag = 1;
			if (specop==GETC_SPEC && passno==2) {
			  if (xp->e_xvalue>MAXUBYTE || xp->e_xvalue<MINBYTE)
			    yywarning("Immediate value larger character value");
			}
			/* gets of immed data turn into CAL_OP or CAL16_OP */
			/* or into LIS_OP if data's small and nonindexed. */
			if ( opcode.Op_popcode == CAL_OP && 
				ap->a_atype == AIMM &&
				(xp->e_xtype&XTYPE) == XABS &&
				!(xp->e_xtype&XFORW) &&
				U4BIT_VAL(xp->e_xvalue) ) {
			   opcode.Op_eopcode = CORE;
			   opcode.Op_popcode = LIS_OP;
			   get_flag = 0;
			}
			else 
			    ap->a_atype = ADISP;	/* All but LIS */
		} else {
		   /* for most cases expression is defined before use */
		   if (ap->a_atype == ADISP && (xp->e_xtype&XTYPE) == XABS
			   && !(xp->e_xtype&XFORW) && xp->e_xvalue >= 0) {
			i = opcode.Op_popcode & GP_MSK ;
			if (xp->e_xvalue == (xp->e_xvalue & shortop_maxd[i]))
				opcode = shortops[i];
			else
				opcode = normops[i];
		   } else {
			opcode = normops[opcode.Op_popcode & GP_MSK];
		   }
		}	/* end of GET_PUT */
	} else							/* ELSE */
	if (opcode.Op_popcode & ASC_GRP) switch(opcode.Op_popcode) {
		case SI_SPEC:
			ap++;		/* point to third argument */
			locxp = ap->a_xp;	/* the exp structure */
			ap--;
			locxp->e_xvalue = (- locxp->e_xvalue);
					/* negate the value and use ai */
			opcode.Op_popcode = AI_OP;
			opcode.Op_eopcode = ESDI;
			break;
		case MR_SPEC:
			ap++;		/* point to third arg slot */
			/* create a third arg of 'r0' */
			ap->a_atype = AREG;
			ap->a_areg1 = 0;
			nact++;
			opcode.Op_eopcode = ESCX;
			opcode.Op_popcode = CAS_OP;
			ap--;
			break;
		default:
		switch( nact ) {
	   case 2:
	   switch(ap->a_atype) {
		case AREG:
			/* assume r,r format. get opcodes and pass on */
			opcode = normops[opcode.Op_popcode-ADD_SPEC+GP_CNT];
			break;
		case AIMM:
		case AEXP:
			i = opcode.Op_popcode - ADD_SPEC;
			opcode = imops[i+GP_CNT];
			if (i == CMPL_SPEC-ADD_SPEC) break;
			if (i == CMP_SPEC-ADD_SPEC ) {
			    if ( (xp->e_xtype&XTYPE) == XABS &&
					!(xp->e_xtype&XFORW) &&
					U4BIT_VAL(xp->e_xvalue) ) 
					opcode = shortops[i + GP_CNT];
			    break;
			}
			/* two arg add and sub are rare at this time */
			/* make it a three arg add, with r1 = r2 */
/* not needed ?
			if (i == SUB_SPEC-ADD_SPEC) {
				xp->e_xvalue = - xp->e_xvalue;
				i = 0;
			}
*/
			*(ap+1) = *ap;
			*ap = *(ap-1);
			nact++;
			goto three_arg_AS;
		default:
			yyerror("Invalid argument type, operand 2");
	   }	/* end switch on arg type for 2 args - ASC_GRP */
	   break;	/* end of 2 arg case */
		
	   case 3:
		i = opcode.Op_popcode - ADD_SPEC;
		opcode = imops[i+GP_CNT];
		if (i > SUB_SPEC-ADD_SPEC) break;

		if (ap->a_atype != AREG) 
			yyerror("Second argument must be a register");
three_arg_AS:
		ap++;  /* step to third arg. */
		xp = ap->a_xp;
		if (xp->e_xvalue < 0) {
			xp->e_xvalue = - xp->e_xvalue;
			i ^= 1; /* flip add and sub */
		}
		if ( (ap-2)->a_areg1 == (ap-1)->a_areg1 &&
				(xp->e_xtype&XTYPE) == XABS &&
				!(xp->e_xtype&XFORW) &&
				xp->e_xvalue <= 15) {
			opcode = shortops[i + GP_CNT];
			/* make a two arg instruction */
			*(ap-1) = *(ap);
			nact--;
		} else {
		    if (i == SUB_SPEC-ADD_SPEC) 
			xp->e_xvalue = - xp->e_xvalue;
		}
		ap--;
		break;	/* end of 3 arg case -- ASC GRP */
	   default:
			yyerror("Too many arguments");
	   }	/* end of switch on nact */
	} else  /* end of SI, MR, ... */			/* ELSE */
		if (opcode.Op_popcode & LD_STO) {
		    if (ap->a_atype != ADISP && ap->a_atype != AEXP) {
			    yyerror("Invalid format for second operand.");
			    return;
		    }
		    i = opcode.Op_popcode & LDSTO_MSK;
			/* could there be a base available ? */
			xp = ap->a_xp;
			/* compute the hi and low portions */
			low = xp->e_xvalue & 0xffff;	/* low 16 bits */
			/* compute high side */
			xp->e_xvalue = ((xp->e_xvalue - low)>>16) & 0xffff; 
			ap2 = ap++;
			if (i >= LOAD_CNT) { /* a store */
			    if (nact<3 || ap->a_atype != AREG) {
				yyerror("Third operand must be a register");
				return;
			    }
			    saved_areg1 = ap1->a_areg1;
			    ap1->a_areg1 = ap->a_areg1;	/* use third arg */
			}
			if (ap2->a_atype == AEXP) { /* make it disp */
				ap2->a_atype = ADISP;
				ap2->a_areg1 = 0;
			}
			nact = 2;
			opcode.Op_eopcode = ESCDUP;
			opcode.Op_popcode = CAU_OP;
			load_store_flag = 1;
			putins(opcode, firstarg, nact);
			load_store_flag = 0;
			/* set up for load or store instr */
			ap2->a_atype = ADISP;  /* must be a disp */
			ap2->a_areg1 = ap1->a_areg1;	/* use old arg1 reg */
			xp->e_xvalue = low & 0xffff;
			xp->e_xtype = (xp->e_xtype & ~XTYPE) | XABS;
			if (i >= LOAD_CNT) 	/* store */
				ap1->a_areg1 = saved_areg1;
			opcode = loadstops[i];
			/* fall into call to putins */
	} else		/* end of LD_STO */			/* ELSE */
		/*  code that was moved from asparse.c: */
		switch (opcode.Op_popcode) {

		case SHL_SPEC:
		case SHLA_SPEC:
		case SHR_SPEC:
		case SHRA_SPEC:
			locxp = ap->a_xp;	/* the exp structure */
			if (locxp->e_xvalue < 16) {
			   opcode = shiftops[opcode.Op_popcode&SPEC_MSK];
			} else {
			   opcode = shiftops[(opcode.Op_popcode&SPEC_MSK)
						+ SH_OP_CNT];
			   if (locxp->e_xvalue < 32) {
					locxp->e_xvalue -= 16;
			   } else {
					locxp->e_xvalue = 15;
					yyerror("Expression value greater than 31, operand 2");
				}
			}
			break;

		case NI_SPEC:
			if (nact < 3) {
				yyerror("Need three arguments");
				return;
			}
			ap++;		/* point to third argument */
			locxp = ap->a_xp;	/* the exp structure */
			if (locxp->e_xvalue < 0) {
				opcode.Op_popcode = NILO_OP;
			} else {
				opcode.Op_popcode = NILZ_OP;
			}
			opcode.Op_eopcode = ESDIUS;
			ap--;
			break;

		case OI_SPEC:
		case XI_SPEC:		/* exclusive or immediate special */
					/* ap points to second argument */
			if (nact <3) {
				yyerror("Three arguments needed");
				return;
			}
			if (ap->a_atype != AREG) {
			   yyerror("First two arguments must be registers");
			   return;
			}

			ap2 = ap++;	/* save ptr to second argument */
					/* and point to third argument */
			locxp = ap->a_xp;	/* point to exp structure */
			ap--;
			saved_xvalue = locxp->e_xvalue;  /* pick up its value */

			spec_op = opcode.Op_popcode & SPEC_MSK;
			if ((saved_xvalue & 0xffff0000) == 0) {
					/* if the high 16 bits are 0, use oil
					   and leave locxp->e_xvalue as is */
			   	opcode = nxo_ops[spec_op];
				break;
			}		/* end of high 16 bits == 0 code */
			if ((saved_xvalue & 0xffff0000) &&
			   ((saved_xvalue & 0xffff) == 0)) {
					/* if high 16 bits are non-zero and
					   low 16 bits are zero, use oiu */
			    locxp->e_xvalue = ((locxp->e_xvalue>>16) & 0xffff);
			   	opcode = nxo_ops[spec_op + NXO_CNT];
				break;
			}		/* end of high 16 bits != 0 */
			if ((saved_xvalue & 0xffff8000) == 0xffff8000 &&
					(ap1->a_areg1 != ap2->a_areg1)) {
					/* if -32768 < third operand < 0,
					   and two register NOT the same,
					   use cal and x */
				ap2->a_atype = ADISP;  /* second arg is disp */
				saved_areg1 = ap2->a_areg1;  /* save register */
				ap2->a_areg1 = 0;  /* use register 0 in disp */
				ap2->a_xp = locxp;	/* point to third arg's
						   	exp structure */
				nact -= 1;
				opcode.Op_popcode = CAL_OP;
				opcode.Op_eopcode = ESCD;
				putins(opcode, firstarg, nact);
					/* now build the x instruction,
					   using the same arg and explist
					   structures */
			/*	locxp = ap2->a_xp;  /* restore xp [??] *xx/
				locxp->e_xtype &= ~XABS; IS THIS NEEDED ?*/ 
				ap2->a_atype = AREG;  /* second arg is reg */
				ap2->a_areg1 = saved_areg1;  /* restore reg */
				opcode = nxo_ops[spec_op + 2*NXO_CNT];
				break;
			}		/* end of -32768 < n < 0 code */
			/* the default is to generate an
				xiu followed by an xil instruction */
			locxp->e_xvalue = ((locxp->e_xvalue>>16) & 0xffff);
			opcode = nxo_ops[spec_op + NXO_CNT];
			putins(opcode, firstarg, nact);
					/* now build the xil instruction,
					   using the same arg and explist
					   structures and same opcode
					   (almost); note that ap still
					   points to the second argument */
		/*	locxp = ap->a_xp;  /* restore xp [??]*/
			locxp->e_xvalue = (saved_xvalue & 0xffff);
			opcode = nxo_ops[spec_op];
		/*	ap1 = arglist;	/* point to first argument [??]*/
			ap2->a_areg1 = ap1->a_areg1;  /* set second operand's
					   register equal to the first operand's
					   register */
			break;

		}			/* end of switch */  /* end of IF */

	      if (opcode.Op_popcode == 0)
			yyerror("as botch: imops, normops, or shortops table");
	      ap--;   /* restore ap to point to first arg */
		putins(opcode, firstarg, nact);		
}

extern	int d124;

#define NBR_NIBS	3		/* maximum of 3 nibbles to be built */

				/* Check displacement bounds, possibly print
				 * error message, return 1 if failure.
				 */
int checkbounds(val,low,high)
int val, low, high;
{
	if (val < low || val > high) {
	    if (strictbounds || val < MAX_NEG_16BITS 
		    || val > MAX_POS_16BITS*2+1 )
		yyerror("Displacement %d not in range %d to %d",val,low,high);
	    return 1;
	}
	return 0;
}

putins(opcode, ap, n)
	struct	Opcode	opcode;
	register struct arg *ap;
	int	n;			/* Must be positive */
{
	reg	struct exp 	*xp;
		struct arg	*apsave;
		struct instab	*ip;
	reg	int 	argtype;
		int 	i;
		int	reloc_how;
		int	reg_nbr;	/* base register number */
		int	nib[NBR_NIBS];	/* collect half-bytes */
		int	instr_opnd;	/* argument type from instrs */
		int	idelta;		/* used to calculate operand number */
		int	rel_disp;	/* relative displacement for BI and 
					   BIB format branch displacements */

		int	op;		/* JSW - holds operation code when
					   writing out 8 byte instructions */

	static	int	hwwarn = 0;
	static	int	blxflg = 0;	/* Prior opcode was balrx, balix, or balax */
		int	laddr,haddr;	/* bounds for legal 16-bit disp */

#ifdef DEBUG
	fflush(stdout);
#endif
	idelta = extendedop ? -1 : 0 ;
	if (passno == 2)
		goto PASS2;
#ifdef DEBUG
	if (debug) printf("\nline: %d, .=%d ",lineno,(dotp->e_xvalue) );
#endif

	switch(opcode.Op_eopcode){

	case ESJI:			/* 5 bit op code, JI format */
		if (blxflg) {
			yyerror("jump may not follow bal?x instruction");
			blxflg = 0;
		}
		dotp->e_xvalue += 2;
		break;
	case CORE:			/* 8 bit op code, R and RI formats */
		if (opcode.Op_popcode == BALRX_OP) {
			if (blxflg) {
				yyerror("balrx may not follow bal?x.");
				dotp->e_xvalue += 4;
			} else {
				blxflg = 1;
				dotp->e_xvalue += 2;
			}
		} else
			/* FALLTHROUGH */
	case ESCX:			/* 4 bit op code, X format instruction */
	case ESDS:			/* 4 bit op code, D Short format */
	case ESRD:			/* 8 bit op code, RD format */
		if (blxflg) {
			blxflg = 0;
			dotp->e_xvalue += 4;
		} else
			dotp->e_xvalue += 2;
		break;
	/* The following generate four (or more) bytes */
	case ESCD:		/* 8 bit op code, D, DB, and D1 formats */
	case ESCDUS:
	case ESCDUP:
		if (opcode.Op_popcode == CAL_OP && get_flag) {
			ap++;  /* address the second arg */
			xp = ap->a_xp;
			get_flag = 0;
			/* if -d4 then assume a data basereg for data immed. */
			if ( (xp->e_xtype&XTYPE) == XDATA &&
				!(xp->e_xtype&XFORW) &&
				ap->a_dispsize & DATAOPT )
				;
			else
			if ( (xp->e_xtype&XTYPE) != XABS ||
			     (xp->e_xtype&XFORW ) )
					dotp->e_xvalue += 4;
			else if ( (xp->e_xvalue > MAX_POS_16BITS ||
				xp->e_xvalue < MAX_NEG_16BITS ) &&
				(xp->e_xvalue&0xffff) &&
				(xp->e_xvalue&0xffff0000) )
					dotp->e_xvalue += 4;
		}
		blxflg = 0;
		dotp->e_xvalue += 4;
		break;

	case ESBI:			/* 8 bit op code, BI and BIB formats */
		if (blxflg) yyerror("bxxx  may not follow a bal?x");
		if (opcode.Op_popcode == BALIX_OP) 
			blxflg = 1;
		else 
			blxflg = 0;
		dotp->e_xvalue += 4;
		break;
	case ESBA:			/* 8 bit op code, BA format */
		if (blxflg) yyerror("bal?? may not follow a bal?x");
		if (opcode.Op_popcode & WITH_X) blxflg = 1;
		else	blxflg = 0;
		dotp->e_xvalue += 4;
		break;
	case ESDI:		/* 8 bit op code, DI, DIN, and D2 formats */
	case ESDIUS:
		blxflg = 0;
		dotp->e_xvalue +=4;
		break;
	default:
		yyerror("as botch: invalid escape op code during pass 1: %x", 
				opcode.Op_popcode);
	}

	return;

PASS2:
#ifdef DEBUG
	if (debug) printf("\n line: %d .=%d ",lineno,(dotp->e_xvalue));
#endif
	if (dotp->e_xvalue&HW) {
	    if (!hwwarn) {
		yyerror("Instruction not on half-word boundary");
		hwwarn++;
	    }
	} else 
		hwwarn = 0;
	/*
	 *	Output the opcode
	 */
	/* this should be (carefully) merged with the loop below */
	for (i = 0; i < NBR_NIBS; i++) {  /* initialize the nibbles */
		nib[i] = 0;
	}

	/* Check immediate and register operands */
	ip = ITABFETCH(opcode);
	apsave = ap;
	for (i=0; i<n; i++, ap++) {
		argtype = ap->a_atype;
		if (argtype&AINDX) {
			yyerror("Indexing not valid for operand %d",i+idelta+1);
			ap->a_atype &= ~AINDX;
		}
		if (argtype&ALEN) {
	yyerror("Length specification not valid, operand %d",i+idelta+1);
			ap->a_atype &= ~ALEN;
		}
		argtype &= ~(AINDX|ALEN);
		xp = ap->a_xp;
		instr_opnd = fetcharg(ip, i);
		switch( (instr_opnd & ARGTMASK) >> ACCTLN) {
		case ARGTI >> ACCTLN:
		    nib[i] = 0;
		    switch (argtype) {
			case AEXP:
			case AIMM:
			    if ((xp->e_xtype & XTYPE) != XABS) {
				yyerror("Absolute expression required for immediate operand");
			    } else {
				ap->a_atype = AIMM;
				switch ( instr_opnd & TYPMASK ) {
				case TYPN:
				case TYPB:
				case TYPY:
					if (xp->e_xvalue < 0) {
						yyerror("Immediate value is negative, operand %d", i+1+idelta);
						xp->e_xvalue &= 0;
						break;
					}
					break;
				}
				switch ( instr_opnd & (ACCTMASK|TYPMASK) ){
				case ACCN|TYPN:
					if (xp->e_xvalue >> ROFFSET) {
						yyerror("Immediate operand greater than 15, operand %d",i+1+idelta);
					}
					xp->e_xvalue &= 0xf;
					nib[i] = xp->e_xvalue;
					break;
				case ACCN|TYPB:
					if (xp->e_xvalue >> JIOFFSET) {
						yyerror("Immediate operand greater than 7, operand %d",i+1+idelta);
					}
					xp->e_xvalue &= 0x7;
					nib[i] = xp->e_xvalue;
					break;
				case ACCN|TYPY:
					if (xp->e_xvalue > 1) {
						yyerror("Immediate operand greater than 1, operand %d",i+1+idelta);
					}
					xp->e_xvalue &= 0x1;
					nib[i] = xp->e_xvalue;
					break;
				case ACCN|TYPS:
				case ACCR|TYPS:
					break;
				}
			    }
			    break;
			default:
				yyerror("Invalid format for immediate operand, operand %d",i+idelta+1);
				break;
			} /* end of argtype switch for TI */
			break;
		case ARGTG >> ACCTLN:
			if (argtype != AREG) {
				yyerror("Invalid format for register operand, operand %d",i+idelta+1);
				nib[i] = 0;
			} else {
				nib[i] = ap->a_areg1;
			}
			break;
		case ARGTX >> ACCTLN:
			if (ap->a_xp->e_xloc != dotp - usedot)
			    yyerror("Destination not in the same segment");
			break;
		case ARGTA >> ACCTLN:
			switch(argtype) {
			   case ADISP:
			   case ALIT:
			   case AEXP:
				break;
			   default:
				yyerror("Invalid format for address operand, operand %d",i+idelta+1);
				break;
			}
			break;
		} /* end of switch on instr_opnd */
	} /* end of for loop */
	ap = apsave;

	switch(opcode.Op_eopcode){	/* look at the escape op code */

	case ESCX:			/* 4 bit op code, X format instruction */
					/* there are three register operands */
		/* ESDS comes here as well */
emit2bytes:				/* emit 2 byte instructions */
		Outb(opcode.Op_popcode | nib[0]);  /* emit the first byte */
		/* ESRD branches in here */
emit2ndbyte:
		Outb(nib[1] << 4 | nib[2]);  /* emit the second byte */
		if (blxflg) {
			blxflg = 0;
			/* emit a nop */
			Outb(0x08); Outb(0);
		}
		break;

	case ESDS:			/* 4 bit op code, D Short format */

					/* there are two operands */
					/* first operand is a register */
			nib[1] = nib [0];
			ap++;
			xp = ap->a_xp;	/* address of the exp structure */
			argtype = ap->a_atype;  /* get argument type */

			switch(argtype) {

			case ADISP:	/* second operand can be a register
					   and a displacement or a relocatable
					   expression */
				if ((opcode.Op_popcode == LHAS_OP) ||
				   (opcode.Op_popcode == STHS_OP)) {
					if (((xp->e_xvalue >> 1) << 1) 
					   != xp->e_xvalue) {
						yywarning("Second operand rounded down to multiple of 2");
					}
					/* if the op code is a lhas or a sths,
					   the displacement needs to be shifted
					   once to the right because the hardware
					   adds a 0 to the end of it */
					xp->e_xvalue = (xp->e_xvalue >> 1);
				} else if ((opcode.Op_popcode == LS_OP) ||
				          (opcode.Op_popcode == STS_OP)) {
					if (((xp->e_xvalue >> 2) << 2) 
					   != xp->e_xvalue) {
						yywarning("Second operand rounded down to multiple of 4");
					}
					/* if the op code is a ls or a sts,
					   the displacement needs to be shifted
					   twice to the right because the 
					   hardware adds 00 to the end of it */
					xp->e_xvalue = (xp->e_xvalue >> 2);
				}
					
				if ( (xp->e_xtype&XTYPE) != XABS) 
					yyerror("Displacement must be an absolute value, operand %d", i+1+idelta);
				if (xp->e_xvalue < 0) {
					yyerror("Displacement is negative, operand %d", i+1+idelta);
					xp->e_xvalue &= 0xf;
				} else {
					if (xp->e_xvalue >> ROFFSET) {
						yyerror("Displacement greater than 15, operand %d", i+1+idelta);
						xp->e_xvalue &= 0xf;
					}
				}
				nib[2] = ap->a_areg1;
				nib[0] = xp->e_xvalue;
					/* the 4 bit displacement will
					   be OR'd with the op code */
				goto emit2bytes;
			
			case ALIT:	/* $.pseudo */
			case AEXP:	/* expression */
			     	if (argtype & AINDX) {
					yyerror("Operand %d cannot be indexed",
					i+1+idelta);
				}

				reg_nbr = find_basereg(xp,i,idelta,W_MSG);  /* go find a .using */

				if ((opcode.Op_popcode == LHAS_OP) ||
				   (opcode.Op_popcode == STHS_OP)) {
					/* if the op code is a lhas or a sths,
					   the displacement needs to be shifted
					   once to the right because the hardware
					   adds a 0 to the end of it */
					xp->e_xvalue = (xp->e_xvalue >> 1);
				} else if ((opcode.Op_popcode == LS_OP) ||
				          (opcode.Op_popcode == STS_OP)) {
					/* if the op code is a ls or a sts,
					   the displacement needs to be shifted
					   twice to the right because the 
					   hardware adds 00 to the end of it */
					xp->e_xvalue = (xp->e_xvalue >> 2);
				}
					
				if (xp->e_xvalue < 0) {
					yyerror("Adjusted displacement is negative, operand %d", i+1+idelta);
				} else 
				if (xp->e_xvalue >> ROFFSET) {
					yyerror("Adjusted displacement greater than 15, operand %d", i+1+idelta);
					xp->e_xvalue &= 0xf;
				}
				nib[2] = reg_nbr;
				nib[0] = xp->e_xvalue;
				goto emit2bytes;


			}	/* end of switch */
		break;
				
	case ESJI:			/* 5 bit op code, 1 byte JI format */

		for (i = 0; i < n; i++, ap++) {  /* JI has two operands,
					   extended JI has only one operand */
			xp = ap->a_xp;	/* address of the exp struct */
			argtype = ap->a_atype;	/* get argument type */

	/*		instr_opnd = fetcharg(ITABFETCH(opcode),i); */

				switch (argtype) {

				case AIMM:
					/* the jb and jnb instructions have
					   dummy primary op codes in instrs
					   because no duplicate op codes are
					   allowed unless the operands are
					   identical and jb and jnb would be
					   the same as jnop and j respectively */
					if (opcode.Op_popcode == JB_FLAG)
						opcode.Op_popcode = JB_OP;
					else
					if (opcode.Op_popcode == JNB_FLAG)
						opcode.Op_popcode = JNB_OP;

					/* the first byte is the five bit
					   op code and the three bit 
					   condition status bit mask */
					opcode.Op_popcode |= nib[0];
					break;


			case AEXP:	/* first operand for extended JI format
					   and second operand for JI format is
					   a relocatable expression */
				if ((xp->e_xtype & XTYPE) == XUNDEF)
					yyerror("%s: destination label is undefined or external", 
					FETCHNAME(ITABFETCH(opcode)));
				if ((xp->e_xtype & XTYPE) == XABS)
					yyerror("Relocatable expression required for operand %d",i+1+idelta);
				else {
					rel_disp = ((xp->e_xvalue - dotp->e_xvalue) >> 1);
					/* the relative displacement in
					   a JI format instruction 
					   must be divided by two */
					if ((rel_disp < MAX_NEG_8BITS) || (rel_disp > MAX_POS_8BITS))
						yyerror("Expression value not in range %d to %d, operand %d",
						MAX_NEG_8BITS,MAX_POS_8BITS,i+1+idelta);
				}	/* end of else statement */
				break;

			}		/* end of switch */
		}			/* end of for loop */
		Outb(opcode.Op_popcode);
		Outb(rel_disp);
		break;

	case ESRD:			/* 8 bit op code, 2 byte RD
					   format instruction */
		Outb(opcode.Op_popcode);

				/* there are two operands */
				/* first operand is a register */
		nib[1] = nib[0];
		ap++;
		xp = ap->a_xp;	/* address of the exp struct */
		argtype = ap->a_atype;	/* get argument type */

		switch(argtype) {

		case ADISP:	/* second operand is always ADISP */
			if ( (xp->e_xtype&XTYPE) != XABS) {
				yyerror("Displacement must be an absolute value, operand %d", i+1+idelta);
			} else
			if (xp->e_xvalue != 0) {
				yywarning("Displacement set to zero");
				xp->e_xvalue = 0;
			}
			nib[2] = ap->a_areg1;
			break;

		default:
			yyerror("The second operand must consist of a displacement of 0 and a register");
			nib[2] = 0;
		}
		/* the second byte of the instruction
		   consists of the two registers */
		goto emit2ndbyte;

case ESBI:			/* 8 bit op code, 4 byte BI and BIB formats */

		if (opcode.Op_popcode == BALIX_OP) blxflg = 1;

				/* there are two operands */
				/* the first BIB operand is an
				   immediate operand */
				/* first BI operand is a register */
		ap++;
		xp = ap->a_xp;	/* address of the exp struct */
		argtype = ap->a_atype;	/* get argument type */

		switch(argtype) {

		case AEXP:	/* second operand for BI or BIB is always AEXP */
			if ((opcode.Op_popcode != BALI_OP) &&
			    (opcode.Op_popcode != BALIX_OP)) {
			if ((xp->e_xtype & XTYPE) == XUNDEF)
				yyerror("%s: destination label is undefined or external", 
				FETCHNAME(ITABFETCH(opcode)));
			} else {
			   if ( xp->e_xtype & XXTRN  &&  ((xp->e_xtype &
				XTEXT) == 0) ) {
				Outb(opcode.Op_popcode);
				xp->e_xvalue |= (nib[0] << 20);
				reloc_how = TYPZ + RELOC_PCREL;
				outrel(xp, reloc_how);
				break;
			   }
			}
			if ((xp->e_xtype & XTYPE) == XABS) {
				yyerror("Relocatable expression required for operand %d",i+1+idelta);
			} else {
			rel_disp = ((xp->e_xvalue - dotp->e_xvalue) >> 1);
				/* the relative displacement in a
				   BI or BIB format instruction 
				   must be divided by two */
			if ((rel_disp < MAX_NEG_20BITS) || (rel_disp > MAX_POS_20BITS)) {
				yyerror("Expression value not in range %d halfwords to %d halfwords, operand %d",
				MAX_NEG_20BITS, MAX_POS_20BITS, i+1+idelta);
			}
			nib[1] = ((rel_disp >> 16) & 0xf);
				/* the second byte of the instruction
				   consists of the register and the
				   leftmost four bits of the 20
				   bit relative branch displacment */
			}
			Outb(opcode.Op_popcode);
			Outb(nib[0] << 4| nib[1]);
			Outb(rel_disp >> 8);
			Outb(rel_disp);
			break;

		}		/* end of switch */
		break;

case ESBA:			/* 8 bit op code, 4 byte BA
					   format instruction */

		if (opcode.Op_popcode & WITH_X) blxflg = 1;

		xp = ap->a_xp;		/* address of the exp struct */
		argtype = ap->a_atype;	/* get argument type */

		if (argtype == AEXP) {  /* first operand is always AEXP */
					/* this if should be redundant */
			if ((xp->e_xtype&XTYPE) != XABS) {
			   if (xp->e_xvalue >> BAOFFSET) {
				yyerror("Absolute address greater than 16,777,215");
				xp->e_xvalue &= 0xffffff;
			   }
			   Outb(opcode.Op_popcode);
				reloc_how = TYPZ + RELOC_PCREL;
				outrel(xp, reloc_how);
				break;
			}
			if (xp->e_xvalue < 0)
				yyerror("Expression value is negative, operand %d", i+1+idelta);
			if (xp->e_xvalue >> BAOFFSET) {
				yyerror("Absolute address greater than 16,777,215");
				xp->e_xvalue &= 0xffffff;
			}
			Outb(opcode.Op_popcode);
			Outb(xp->e_xvalue >> 16);
			goto emit3rdbyte;

		}
		break;

	case ESCD:		/* 8 bit op code, D, DB, and D1 formats */
		laddr = MAX_NEG_16BITS;
		haddr = MAX_POS_16BITS;
		goto escd;
	case ESCDUS:
		laddr = 0;
		haddr = MAX_POS_16BITS*2+1;
		goto escd;
	case ESCDUP:
		laddr = MAX_NEG_16BITS;
		haddr = MAX_POS_16BITS*2+1;
escd:

		blxflg = 0;
		for (i = 0; i < n; i++, ap++) {
					/* there are two operands for D and DB,
					   only one operand for D1 */
			xp = ap->a_xp;	/* address of the exp structure */
			argtype = ap->a_atype;  /* get argument type */

			switch(argtype) {
			case AIMM:	/* the first DB operand is an
					   immediate operand */

			case AREG:	/* first D operand is a register */
				nib[1] = nib[0];
				break;

			case ADISP:	/* first operand for D1 or second
					   operand for D is a register and
					   a displacement or a relocatable
					   expression */

				if (nib[2] = ap->a_areg1 )
					op = CAL_OP;
				else
					op = CAL16_OP;
				if (opcode.Op_popcode == CAL_OP && get_flag){
				   get_flag = 0;	
				   if ( (xp->e_xtype&XTYPE) != XABS) {
				      if ( (xp->e_xtype&XTYPE) == XDATA &&
					   !(xp->e_xtype&XFORW) &&
					   ap->a_dispsize & 4) {
					 reg_nbr = find_basereg(xp,i,
							idelta,NO_MSG);
					 if (!reg_nbr) {
					    yyerror("Get $data and -d4 failed");
					    d4error++;
					 } else { /* cal with base will work */
					    nib[2] = reg_nbr;
					    break;
					 }
				      } else {
					reloc_how = TYPV;
					/* JSW - changed next two lines to use
					   op and nib[2] */
					Outb(op);
					Outb(nib[1]<<4|nib[2]);   /* RC = 0 */
					outrel(xp, reloc_how);  
					xp->e_xvalue >>= 16; 
			/* A negative displacement (say, -10) by itself or as
			 * the abs part of a relocatable disp, materializes as
			 * cal16 r,fff6;	oiu  r,0
			 *                  or
			 * cal   r,fff6(rx);	cau  r,0(r)
			 * and we rely on ld, when relocating, to give cau
			 * a displacement that takes cal's sign extension
			 * into consideration.
			 */
					goto emitoiuop;
				     }
				   } /* end of not-absolute */
				   else {
					if (xp->e_xtype&XFORW) 
					   goto emit8bytes;
				        if (xp->e_xvalue > MAX_POS_16BITS ||
					   xp->e_xvalue < MAX_NEG_16BITS) {
					     if ( !(xp->e_xvalue & 0xffff) ) {
						opcode.Op_popcode = CAU_OP;
						xp->e_xvalue >>= 16;
						break;
					     } else
					     if ( !(xp->e_xvalue&0xffff0000) ){
						opcode.Op_popcode = CAL16_OP;
						xp->e_xvalue &= 0xffff;
						break;
					     }
					     goto emit8bytes;
				        } /* end of need 8 bytes */
				   }
				} else /* end of CAL , now CAU */
				   if ( (xp->e_xtype&XTYPE) != XABS) { 
			 	      if (opcode.Op_popcode == CAU_OP &&
					   load_store_flag) {
					reloc_how = TYPV;
					Outb(CAU_OP)
					Outb(nib[1]<<4 | ap->a_areg1);
					outrel(xp, reloc_how);
					goto emitdone;
				      } else
				        yyerror("Displacement must be an absolute value, operand %d", i+1+idelta);
				   }
				if (checkbounds(xp->e_xvalue, laddr, haddr))
				    xp->e_xvalue &= 0xffff;
				nib[2] = ap->a_areg1;
				break;
			
			case ALIT:	/* $.pseudo */
			case AEXP:	/* expression */
				instr_opnd = fetcharg(ITABFETCH(opcode), i);
				if ( ((instr_opnd & ARGTMASK) != ARGTX) &&
			     	(argtype & AINDX) ) {
				    yyerror("Index on operand %d",i+1+idelta);
				}

				reg_nbr = find_basereg(xp,i,idelta,W_MSG);
				/* go find a .using */

				if (checkbounds(xp->e_xvalue, laddr, haddr))
				    xp->e_xvalue &= 0xffff;
				nib[2] = reg_nbr;
				break;

			}		/* end of switch */
		}			/* end of for loop */
	/*
	 * several places branch to here.. it seems like a slow fuse
	 * to pass the second 16 bits in xp->e_xvalue .
	 */	
emit4bytes:
		Outb(opcode.Op_popcode);
		Outb(nib[1] << 4 | nib[2]); /* emit the second byte */
emit3rdbyte:
		Outb(xp->e_xvalue >> 8); /* emit the third byte */
		Outb(xp->e_xvalue);	/* emit the fourth byte */
emitdone:
		break;
emit8bytes:
		/* changed next two lines to use op and nib[2] */
		Outb(op);
		Outb(nib[1]<<4|nib[2]);  /* RC = 0 */
		Outb(xp->e_xvalue >> 8);
		Outb(xp->e_xvalue);
			/* If op was cal (areg1!=0), next op is cau.
			 * Boost cau operand by 1 to compensate for 
			 * sign-extension of cal operand already output.
			 */
		if (ap->a_areg1) xp->e_xvalue += 0x8000;
		xp->e_xvalue >>= 16;

emitoiuop:
		nib[2] = nib[1];
		/* set opcode based on arg register existence */
		if (ap->a_areg1) {
			opcode.Op_popcode = CAU_OP;
		}
		else {
			opcode.Op_popcode = OIU_OP;
		}
		goto emit4bytes;
				
	case ESDI:	/*	 8 bit op code, DI, DIN, and D2 formats */
		haddr = MAX_POS_16BITS;
		goto esdi;
	case ESDIUS:
		haddr = MAX_POS_16BITS*2+1;
esdi:
		laddr = MAX_NEG_16BITS;

		blxflg = 0;
		if (n == 2) { 		 /* D2 has only two operands, */
					/* second operand is immediate */
			nib[1] = 0;
			nib[2] = nib[0];
			ap++;
			i = 1;
		} else {	/* DI and DIN have three operands */
				/* the first two operands are registers */
					/* the first DIN operand is an
					   immediate operand */
			nib[2] = nib[1];
			nib[1] = nib[0];
			ap += 2;	/* address the third arg */
			i = 2;
		}
		xp = ap->a_xp;	/* address of the exp struct */
		argtype = ap->a_atype;	/* get argument type */

		if (checkbounds(xp->e_xvalue, laddr, haddr))
		    xp->e_xvalue &= 0xffff;
		goto emit4bytes;

	case CORE:
		Outb(opcode.Op_popcode);

		switch(n) {

		case 0:			/* wait */ /* what happened to INST0 */
			Outb(0);	/* one byte op code, no operand */
			break;
		case 1:			/* should not happen */
			Outb(nib[0] << 4); 
			break;
		case 2:
			Outb(nib[0] << 4 | nib[1]);
			break;
		default:
			yyerror("as botch: too many nibs for ascode.c");
			break;
		}
		if (blxflg) {
			blxflg = 0;
			/* emit a nop */
			Outb(0x08); Outb(0);
		}
		if (opcode.Op_popcode == BALRX_OP) blxflg = 1;
		break;

	default:
		yyerror("as botch: invalid escape code in pass 2");
		break;
	}				/* end of switch statement */
}					/* end of putins */

/*
 *	find_basereg
 *	
 *	This routine finds an appropriate base register for the 
 *	expression in the exp struct addressed by xp.
 */

find_basereg(xp,i,idelta,opt)
	register struct exp *xp;
	int	i,idelta,opt;

{
	struct	basereg	*brplow;
	struct	basereg *brp;
	int	seg_nbr;
	int	reg_nbr;
	int	nbr_regs_reqd;

	if ((xp->e_xtype & XTYPE) != XABS) { /* find a .using */
		if ((xp->e_xtype&XTYPE)!=XTEXT && (xp->e_xtype&XTYPE)!=XDATA) {
		   /* expression must be text or data */
		   if (opt)
		      yyerror("Label expression must reference text or data");
		   return(0);
		}
		seg_nbr = xp->e_xloc;	/* find the segment number
					   where 0 - 3 is for .text
					   and 4 - 7 is for .data */
		brp = &usebreg[seg_nbr];  /* pick up the address of
					   the basereg structure for
					   this segment number */
#ifdef DEBUG
		if (debug) printf(" line: %d, segment: %d.\n", lineno, seg_nbr );
#endif
		if (!brp->b_rno) {	/* if there is no .using for
					   this segment number */
			brplow = seg_nbr>=NLOC ? &usebreg[NLOC] :
					   	 &usebreg[0] ;
					/* for .text brplow points to the
					   basereg structure for segment 0,
					   for .data brplow points to the
					   basereg structure for segment 4 */
			while (brp > brplow && !brp->b_rno) {
					/* since the current location doesn't
					   have a .using, see if a lower
					   segment has a .using */
				brp--;
				seg_nbr--;
			}
		}
		if (!brp->b_rno)
			goto no_basereg_error;
#ifdef DEBUG
		if (debug) printf(" xp->e_xvalue is %x, brp->b_rvalue is %x.\n",xp->e_xvalue,brp->b_rvalue);
#endif
		if (((xp->e_xvalue) - (brp->b_rvalue)) >= 0) {
					/* if the relocatable expression
					   is a positive displacement from
					   the expression in the .using */
			nbr_regs_reqd =(((xp->e_xvalue)-(brp->b_rvalue)) >> DOFFSET);
		     	   		/* see which base register can be
					   used (one base register can address
					   x10000 bytes, x8000 bytes positively
					   from the base register and x8000
					   bytes negatively from it) */
			if ( nbr_regs_reqd < brp->b_rno ) {
					/* if there are enough registers */
				reg_nbr = brp->b_rreg[nbr_regs_reqd];
				xp->e_xvalue -= (brp->b_rvalue + (nbr_regs_reqd<<DOFFSET) );
		      	
#ifdef DEBUG
				if (debug) printf(" OK: nbr_regs_reqd: %d, reg: %d.\n",  nbr_regs_reqd, brp->b_rreg[nbr_regs_reqd]);
#endif
			} else {
				goto no_basereg_error;
			}
		} else {		/* the relocatable expression is a
					   negative displacement from the
					   expression in the first .using */
			if (((brp->b_rvalue) - (xp->e_xvalue)) <= 0x8000) {
					/* if the expression can be expressed
					   as a negative displacement from the
					   first base register */
				reg_nbr = brp->b_rreg[0];
				xp->e_xvalue -= brp->b_rvalue;
#ifdef DEBUG
				if (debug) printf(" OK: base register for negative displacement: %d.\n", reg_nbr);
#endif
			} else {	
no_basereg_error:
			    if (opt)
				yyerror("No address base available for operand %d" , i+1+idelta);
#ifdef DEBUG
		 		if (debug) {  
					printf(" operand: %x, base: %x.\n", xp->e_xvalue, brp->b_rvalue );
		 		}
#endif
					/* Avoid a second error message */
				xp->e_xvalue &= 0xffff;
				reg_nbr = 0;
			}
		}

	} else {
		reg_nbr = 0;		/* arg is an absolute expression */
		if (opt)
		   yywarning("No base register assigned for operand %d",i+1+idelta);
	}
	return(reg_nbr);
}
