/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*	      Object code generator - January 6, 1989		    */
/*								    */
/*   This program may be copied	for personal, non-commercial use    */
/*   only, provided that the above copyright notice is included	    */
/*   on	all copies of the source code.	Copying	for any	other use   */
/*   without the consent of the	author is prohibited.		    */
/*								    */
/*------------------------------------------------------------------*/
/*								    */
/*		Originally published (in Modula-2) in		    */
/*	    Dr.	Dobb's Journal, April, May, and June 1986.          */
/*								    */
/*	 AmigaDOS conversion copyright 1989 by Charlie Gibbs.	    */
/*								    */
/*------------------------------------------------------------------*/

#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"

/* Functions */
extern int  LineParts(), Instructions(), ObjDir();
extern int  GetInstModeSize(), GetMultReg(), CountNest();
extern int  ReadSymTab(), GetArgs(), GetAReg(),	OpenIncl();
extern long AddrBndW(),	AddrBndL(), GetValue(),	CalcValue();
extern char *AddName(),	*GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();



GetObjectCode (dummy) int dummy;
/* Determines the object code for the operation	as well	as the operands	*/
/* Returns each	(up to 3 fields), along	with the length	of each.     */
{
    int	 quick;
    int	 ExtL;		/* Bit pattern for instruction extension word */
    long templong;
    char tempop[MAXLINE];
    register int i, j;

    i =	Instructions (OpLoc);		/* Analyze the opcode */

    if (Dir != None) {
	ObjDir (dummy);			/* Process directives */
	return;
    }
    if ((Label[0] != '\0') || (OpCode[0] != '\0'))
	PrntAddr = TRUE;		/* Print address at least */

    if (OpCode[0] == '\0') {
	MakeHunk |= PrntAddr;
	return;				/* No op code, exit now	*/
    }
    if (!i) {				/* Unrecognized	opcode */
	if ((Quiet < 0)	&& (InF->UPtr == 0))
	    ShowLine (InF->Line);	/* Show	where we are */
	if (OpCode[0] == '*') {
	    Error (OpLoc, NoCode);	/* Don't try to open the console! */
	    return;
	}
	if (Size == Byte)		/* Set up \0 parameter */
	    MacSize[0] = 'B';
	else if	(Size == Long)
	    MacSize[0] = 'L';
	else
	    MacSize[0] = 'W';

	AddrAdv	= InstSize = 0;
	PrntAddr = FALSE;
	Dir = MacCall;			/* Assume it's a macro call */
	if (InF->UPtr == 0) {		/* If we're reading from a file */
	    InF->Pos = lseek (In.fd, 0L,1); /*	remember where we are.	*/
	    InF->Pos -=	In.Lim - In.Ptr;
	}
	tempop[0] = ' ';
	tempop[1] = '\0';
	strcat (tempop,	OpCode);	/* Prepend a blank to OpCode */
	if (ReadSymTab (tempop)) {	/* Search for user macro */
	    AddRef (LineCount);
	    if(Sym->Defn < LineCount) {	/* Only	if previously defined! */
		InFNum++;
		if (--InF < LowInF)
		    LowInF = InF;
		MacCount++;
		Heap2Space (0);			/* Check for space */
		InF->UPtr = (char *) Hunk2;	/* MACRO statement */
		InF->UPtr += strlen(InF->UPtr) + 1; /* Skip over it */
		InF->NPtr = NextFNS;	/* New stack pointer */
		InF->Line = 0;		/* Line	number in macro	*/
		InF->NArg=GetArgs (""); /* Get arguments */
		InF->MCnt = MacCount;	/* Macro number	*/
		if (OuterMac ==	0)
		    OuterMac = InFNum;	/* Outer macro */
		return;
	    }
	}
	if (!OpenIncl (OpCode, InclList)) {
	    Error (OpLoc, NoCode);	/* Couldn't open file */
	    Dir	= BadMac;		/* Invalid macro */
	    if (InF->UPtr == 0)	{
		In.fd =	open (InF->NPtr, 0);
		lseek (In.fd, InF->Pos,	0);
		In.Ptr = In.Lim	= In.Buf;
	    }
	    return;			/* Return to outer file	*/
	}
	InFNum++;			/* Bump	nesting	level */
	if (--InF < LowInF)
	    LowInF = InF;
	MacCount++;
	Heap2Space (0);			/* Check for space */
	InF->UPtr = 0;			/* Not a user macro */
	InF->NPtr = NextFNS;		/* New stack pointer */
	InF->Line = 0;			/* Line	number in macro	*/
	InF->NArg = GetArgs (OpCode);	/* Get arguments */
	InF->MCnt = MacCount;		/* Macro number	*/
	if (OuterMac ==	0)
	    OuterMac = InFNum;		/* Outer macro */
	return;
    }

    MakeHunk = TRUE;			/* We have something for a hunk	*/
    AddrCnt = AddrBndW (AddrCnt);	/* It'll be word-aligned */

    if ((AdrModeA != 0)	|| (AdrModeB !=	0)) {
	Src.Loc	= SrcLoc;
	Dest.Loc = DestLoc;
	GetOperand (SrcOp, &Src, SrcPC IN AdrModeB ? 2 : 0);
	GetOperand (DestOp, &Dest, EA05c IN AdrModeB ? 4 : 0);
    }
    if (EA05z IN AdrModeB) {		/* MOVEM */
	if ((Src.Mode != MultiM) && (Dest.Mode != MultiM)) {
	    OpCode[4] =	'\0';           /* MOVEM of a single register */
	    Instructions (OpLoc);	/*  becomes a straight MOVE   */
	}
    }
    if ((Src.Mode == Imm)		/* Immediate instructions */
    && (Src.Hunk == ABSHUNK) &&	(Src.Defn < LineCount)
    &&	   (((EA611 IN AdrModeB) && (Dest.Mode == DReg)	/* MOVE	*/
	    && (Size ==	Long) && (Src.Value >= -128) &&	(Src.Value <= 127))
	|| ((EA05y IN AdrModeB)				/* ADD/SUB */
	    && (Src.Value > 0) && (Src.Value <=	8)))) {
		strcat (OpCode,	"Q");   /* Make it ADDQ/SUBQ/MOVEQ */
		Instructions (OpLoc);
    }
    else if ((Dest.Mode	== ARDir) && (Src.Mode <= 12)
    && (((EA05y	| EA611) IN AdrModeB)	/* ADD,	SUB, or	MOVE */
	|| (OpM68C IN AdrModeA))) {	/* CMP */
	    strcat (OpCode, "A");       /* ADD op,An becomes ADDA etc. */
	    Instructions (OpLoc);
    }
    else if ((Src.Mode == Imm)		/* Immediate instructions */
    && ((OpM68D	| OpM68C | OpM68X) IN AdrModeA)) {
	strcat (OpCode,	"I");           /* ADD/AND/OR/SUB, CMP, EOR */
	Instructions (OpLoc);		/* ADD #op,d becomes ADDI etc. */
    }
    else if ((Src.Mode == ARPost) && (Dest.Mode	== ARPost)
    && (OpM68C IN AdrModeA)) {		/* CMP */
	strcat (OpCode,	"M");           /* Generate CMPM if necessary */
	Instructions (OpLoc);
    }


/*=================== Operand validation routines ====================*/

    if (Pass2) {

    /* If an immediate operand isn't absolute, it must be a long word */

	if ((Src.Mode == Imm) && (Size != Long)	&& (Src.Hunk !=	ABSHUNK))
	    Error (SrcLoc, RelErr);

    /* ------- Check for instructions with too many operands. ------- */
    /* Some specialized	instruction routines contain their own tests. */

	if (AdrModeA ==	0) {		/* Should have only one	operand	*/
	    if ((AdrModeB == EA05e) || (AdrModeB == (Size67 | EA05e))) {
		if (Dest.Mode != Null)
		    Error (DestLoc, OperErr);
/*	    } else if (AdrModeB	== 0) {	*/  /* Should have no operands */
/*		if (Src.Mode !=	Null)
		    Error (SrcLoc, OperErr);
		if (Dest.Mode != Null)
		    Error (DestLoc, OperErr); De-activated for now */
	    }
	}
	if ((AdrModeA != 0) || (AdrModeB != 0))	{
	    if(Dest.Mode != NULL) { /* We should never find 3 operands */
		j = DestLoc + strlen (DestOp);
		if ((Line[j] !=	'\0')
		&& (Line[j] != ';')
		&& (!isspace (Line[j]))) {
		    Error (j, OperErr);
		}
	    }

    /* ----------------	Check for missing operands. ----------------- */

	    if (Src.Mode == Null) {
		Error (OpLoc+strlen(OpCode), OperErr);	/* No source */
	    } else if (Dest.Mode == Null) {
		if (((ImmMode &	AdrModeB) == ImmMode)
		|| (TwoOpsA IN AdrModeA)
		|| (TwoOpsB IN AdrModeB)) {
		    Error (SrcLoc+strlen(SrcOp), OperErr);  /* No dest.	*/
		}
	    }
	}
    }

/*====================================================================*/

    /* ----------------	Decrement and Branch (DBcc) ----------------- */

    if (DecBr IN AdrModeA) {
	if (Pass2) {
	    if (Src.Mode != DReg)
		Error (SrcLoc, ModeErr);
	    if (Dest.Value & 1)
		Error (DestLoc,	AlignErr);  /* Boundary	alignment error	*/

	    if (Dest.Hunk == CurrHunk) {
		ObjSrc = Dest.Value-AddrCnt-2;	/* Relative branch distance */
		Dest.Hunk = ABSHUNK;		/* Displacement	is absolute */
	    } else
		ObjSrc = 0;		/* Let the linker worry	about it */

	    if ((ObjSrc	> 32767) || (ObjSrc < -32768))
		Error (DestLoc,BraErr);	/* Too far to branch */

	    if (Dest.Hunk!=CurrHunk) {	/* DBcc	to another section */
		templong = AddrCnt + 2;	/* 16-bit relocatable */
		PutRel (templong, Dest.Hunk, 2);
	    }
	    ObjOp = Op | Src.Rn;
	}
	AddrAdv	= 4;
	nO = nS	= 2;
	return;
    }

    /* ------------ Branch (Bcc, including BRA and BSR)	------------- */

    if (Brnch IN AdrModeA) {
	if (Src.Value &	1)
	    Error (SrcLoc, AlignErr);	/* Boundary alignment error */

	if (Src.Hunk ==	CurrHunk) {
	    ObjSrc=Src.Value-AddrCnt-2;	/* Relative branch distance */
	    Src.Hunk = ABSHUNK;		/* Displacement	is absolute */
	    if (Size !=	Byte) {
		if ((ObjSrc >= -128) &&	(ObjSrc	<= 127)	&& (ObjSrc != 0))
		    if (DefLine2 < LineCount)
			Size = Byte;	/* Short branch	if possible */
		    else if (Pass2 && FwdProc && (Size != Byte))
			FwdShort=TRUE;	/* Fwd.	ref. could be made short */
	    }
	    if ((Size == Byte) && (ObjSrc == 0))
		Error (SrcLoc, BccSDsp0);	/* Can't do this! */
	} else {
	    ObjSrc = 0;			/* Let the linker worry	about it */
	    if (Size ==	Byte)
		Error (SrcLoc, BraErr);	/* No external short branches! */
	}

	if (Size != Byte) {
	    InstSize = 4;
	    nS = 2;
	    templong = 32767;
	} else {
	    InstSize = 2;
	    Op |= (ObjSrc & 0x00FF);
	    templong = 127;
	}
	if ((ObjSrc > templong)	|| (ObjSrc < -templong-1))
	    Error (SrcLoc, BraErr);	/* Too far to branch */

	if (Dest.Mode != Null)
	    Error (DestLoc, OperErr);	/* No Destination operand! */

	AddrAdv	= InstSize;
	ObjOp =	Op;
	nO = 2;
	if (Src.Hunk !=	CurrHunk) {	/* Bcc to another section */
	    templong = AddrCnt + 2;	/* 16-bit relocatable */
	    PutRel (templong, Src.Hunk,	2);
	}
	return;
    }

    /* ------------ Check for short (16-bit) JMP or JSR	------------- */

    if ((Op == JMP) || (Op == JSR))
	if ((Size == Byte) && (Src.Mode	== AbsL))
	    Src.Mode = AbsW;

/*  Uses information from Instructions & GetOperand (among others)  */
/*  to complete	calculation of Object Code.			    */
/*  Op,	AdrModeA, AdrModeB, Size, and Src & Dest records are all    */
/*  Global variables imported from the SyntaxAnalyzer MODULE.	    */

    ExtL = 0;
    quick = FALSE;

    /* ------------ Check for boundary alignment errors. ------------ */
    /*	BCHG, BCLR, BSET, BTST,	LEA, NBCD, PEA,	Scc, TAS are exempt.  */

    if (Pass2) {
	if ((Size != Byte)
	&& (Op != LEA)
	&& (Op != PEA)
	&& !((AdrModeA == 0) &&	(AdrModeB == 0))
	&& !(AdrModeB &	EA05c)	    /* BTST */
	&& !((AdrModeB&EA05e) && (AdrModeA==0) && !(AdrModeB&Size67))) {
	    if (Src.Value & 1)
		if ((Src.Mode >= ARDisp) && (Src.Mode <= PCDisX))
		    Error (SrcLoc, AlignErr);
	    if (Dest.Value & 1)
		if ((Dest.Mode >= ARDisp) && (Dest.Mode	<= PCDisX))
		    Error (DestLoc, AlignErr);
	}

/* Check for 5 special cases first */

	if (Op == STOP)	{
	    if (Src.Mode != Imm)
		Error (SrcLoc, OperErr);
	    if (Dest.Mode != Null)
		Error (DestLoc,	OperErr);
	}

	if (Op == LINK)	{
	    Op |= Src.Rn;
	    if (Src.Mode != ARDir)
		Error (SrcLoc, ModeErr);
	    if (Dest.Mode != Imm)
		Error (DestLoc,	ModeErr);
	    else if (Dest.Value	& 1)
		Error (DestLoc,	AlignErr);  /* Boundary	alignment error	*/
	}

	if (Op == SWAP)	{
	    if (!(EA05f	IN AdrModeB)) {	/* Ignore if PEA instruction */
		Op |= Src.Rn;
		if (Src.Mode !=	DReg)
		    Error (SrcLoc, OperErr);
		if (Dest.Mode != Null)
		    Error (DestLoc, OperErr);
	    }
	}

	if (Op == UNLK)	{
	    Op |= Src.Rn;
	    if (Src.Mode != ARDir)
		Error (SrcLoc, OperErr);
	    if (Dest.Mode != Null)
		Error (DestLoc,	OperErr);
	}

/* Now do generalized address modes */

	if ((Ry02 IN AdrModeA)&&(Rx911 IN AdrModeA)) {	/* 2 registers */
	    if (Op == CMPM) {		/* Special routine for CMPM */
		Op |= Src.Rn | (Dest.Rn	<< 9);
		if (Src.Mode !=	ARPost)
		    Error (SrcLoc, ModeErr);
		if (Dest.Mode != ARPost)
		    Error (DestLoc, ModeErr);
	    } else {		/* Other two-register instructions */
		Op |= Src.Rn | (Dest.Rn	<< 9);
		if (RegMem3 IN AdrModeA) {
		    if (Src.Mode == DReg) {
			if (Dest.Mode != DReg)
			    Error (DestLoc, ModeErr);
		    } else if (Src.Mode	== ARPre) {
			Op |= 0x0008;
			if (Dest.Mode != ARPre)
			    Error (DestLoc, ModeErr);
		    } else
			Error (SrcLoc, OperErr);
		} else {
		    if (Src.Mode == ARPost)
			if (Dest.Mode != ARPost)
			    Error (DestLoc, ModeErr);
			else
			    Error (SrcLoc, OperErr);
		}
	    }
	}
    }
    if (Data911	IN AdrModeA) {		/* Data	in 9-11	(ADDQ/SUBQ) */
	quick =	TRUE;
	if (Src.Mode ==	Imm)
	    if ((Src.Value > 0)	&& (Src.Value <= 8)) {
		if (Src.Value <	8)  /* Data of 8 is coded as 000 */
		    Op |= Src.Value << 9;
	    } else
		Error (SrcLoc, SizeErr);
	else
	    Error (SrcLoc, OperErr);
    }

    if (CntR911	IN AdrModeA) {		/* Only	Shift/Rotate use this */
	if (Dest.Mode == DReg) {
	    Op = (Op & 0xF9FF) | Dest.Rn;
	    if (Size ==	Word) Op |= 0x0040;
	    if (Size ==	Long) Op |= 0x0080;
	    if (Src.Mode == DReg)
		Op |= 0x0020 | (Src.Rn << 9);
	    else if (Src.Mode == Imm) {
		quick =	TRUE;
		/* Range Check */
		if ((Src.Value > 0) && (Src.Value <= 8)) {
		    if (Src.Value < 8) /* Data of 8 is coded as	000 */
			Op |= (Src.Value << 9);
		} else
		    Error (SrcLoc, SizeErr);
	    } else
		Error (SrcLoc, OperErr);
	} else if (Dest.Mode ==	Null) {
	    Op = (Op & 0xFFE7) | 0x00C0;
	    EffAdr (&Src, (mea | aea));
	} else
	    Error (SrcLoc, OperErr);
    }

    if (Data03 IN AdrModeA) {		/* TRAP	Vector in 0-3 */
	quick =	TRUE;
	if (Src.Mode ==	Imm)
	    if ((Src.Value >= 0) && (Src.Value < 16))
		Op |= Src.Value;
	    else
		Error (SrcLoc, SizeErr);
	else
	    Error (SrcLoc, OperErr);

	if (Dest.Mode != Null)
	    Error (DestLoc, OperErr);
    }

    if (Data07 IN AdrModeA) {		/* Data	in 0-7 (MOVEQ) */
	quick =	TRUE;
	Op |= (Src.Value & 0x00FFL) | (Dest.Rn << 9);
	if (Src.Mode !=	Imm)
	    Error (SrcLoc, ModeErr);
	else if	(Dest.Mode != DReg)
	    Error (DestLoc, ModeErr);
	else if	((Src.Value < -128) || (Src.Value > 127))
	    Error (SrcLoc, SizeErr);
    }

    if (Pass2) {
	if (OpM68D IN AdrModeA)	{   /* DReg in 6-8 (ADD/AND/OR/SUB) */
	    if (Dest.Mode == DReg) {
		Op |= (Dest.Rn << 9);
		if ((Src.Mode == ARDir)	&& (Size == Byte))
		    Error (SrcLoc, SizeErr);
	    } else /* Assume Src.Mode =	DReg --	Error trapped elsewhere	*/
		Op |= (Src.Rn << 9) | 0x0100;

	    if (Size ==	Word) Op |= 0x0040;
	    if (Size ==	Long) Op |= 0x0080;
	}

	if (OpM68A IN AdrModeA)	{   /* AReg in 6-8 (ADDA/CMPA/SUBA) */
	    if (Dest.Mode == ARDir)
		Op |= (Dest.Rn << 9);
	    else
		Error (DestLoc,	ModeErr);

	    if (Size ==	Byte) Error (OpLoc+5, SizeErr);
	    if (Size ==	Word) Op |= 0x00C0;
	    if (Size ==	Long) Op |= 0x01C0;
	}

	if (OpM68C IN AdrModeA)	{	/* CMP (Compare) */
	    if (Dest.Mode == DReg)
		Op |= (Dest.Rn << 9);
	    else
		Error (DestLoc,	ModeErr);

	    if (Size ==	Byte) {
		if (Src.Mode ==	ARDir)
		    Error (OpLoc+4, SizeErr);
	    }
	    if (Size ==	Word) Op |= 0x0040;
	    if (Size ==	Long) Op |= 0x0080;
	}

	if (OpM68X IN AdrModeA)	{	/* EOR (Exclusive or) */
	    if (Src.Mode == DReg)
		Op |= (Src.Rn << 9);
	    else
		Error (SrcLoc, ModeErr);

	    if (Size ==	Byte) Op |= 0x0100;
	    if (Size ==	Word) Op |= 0x0140;
	    if (Size ==	Long) Op |= 0x0180;
	}

	if (OpM68S IN AdrModeA)	{	/* EXT (Sign extension)	*/
	    if (Src.Mode == DReg)
		Op |= Src.Rn;
	    else
		Error (SrcLoc, ModeErr);

	    if (Dest.Mode != Null)
		Error (DestLoc,	OperErr);

	    if (Size ==	Byte) Error (OpLoc+4, SizeErr);
	    if (Size ==	Word) Op |= 0x0080;
	    if (Size ==	Long) Op |= 0x00C0;
	}

	if (OpM68R IN AdrModeA)	{	/* MOVEP (Register/memory) */
	    if ((Src.Mode == DReg) && (Dest.Mode == ARDisp)) {
		if (Size == Byte) Error	(OpLoc+6, SizeErr);
		if (Size == Word) Op |=	0x0180;
		if (Size == Long) Op |=	0x01C0;
		Op |= (Src.Rn << 9) | Dest.Rn;
	    } else if ((Src.Mode == ARDisp) && (Dest.Mode == DReg)) {
		if (Size == Byte) Error	(OpLoc+6, SizeErr);
		if (Size == Word) Op |=	0x0100;
		if (Size == Long) Op |=	0x0140;
		Op |= Src.Rn | (Dest.Rn	<< 9);
	    } else
		Error (SrcLoc, ModeErr);
	}

	if (OpM37 IN AdrModeA) {	/* EXG (Exchange registers) */
	    if ((Src.Mode == DReg) && (Dest.Mode == DReg))
		Op |= 0x0040 | (Src.Rn << 9) | Dest.Rn;
	    else if ((Src.Mode == ARDir) && (Dest.Mode == ARDir))
		Op |= 0x0048 | (Src.Rn << 9) | Dest.Rn;
	    else if ((Src.Mode == ARDir) && (Dest.Mode == DReg))
		Op |= 0x0088 | (Dest.Rn	<< 9) |	Src.Rn;
	    else if ((Src.Mode == DReg)	&& (Dest.Mode == ARDir))
		Op |= 0x0088 | (Src.Rn << 9) | Dest.Rn;
	    else
		Error (SrcLoc, ModeErr);
	}

	if (Bit811 IN AdrModeB)	{   /* Bit operations using bits 8-11 */
	    Size = Word;		/* Ignore size specification */
	    if (Src.Mode == DReg)
		Op |= 0x0100 | (Src.Rn << 9);
	    else if (Src.Mode == Imm)
		Op |= 0x0800;
	    else
		Error (SrcLoc, ModeErr);
	}

	if (Size67 IN AdrModeB)	{	/* Size	in bits	6-7 */
	 /* if (Size ==	Byte) ;	No action -- bits are already 0	*/
	    if (Size ==	Word) Op |= 0x0040;
	    if (Size ==	Long) Op |= 0x0080;
	}

	if (Size6 IN AdrModeB) {	/* Size	in bit 6 (MOVEM) */
	    if (Size ==	Byte) Error (OpLoc+6, SizeErr);
	 /* if (Size ==	Word) ;	No Action -- bit is already 0 */
	    if (Size ==	Long) Op |= 0x0040;
	}

	if (Sz1213A IN AdrModeB) {	/* Size	in 12-13 (MOVE)	*/
	    if (Size ==	Byte) Op |= 0x1000;
	    if (Size ==	Word) Op |= 0x3000;
	    if (Size ==	Long) Op |= 0x2000;
	}

	if (Sz1213 IN AdrModeB)	{	/* Size	in 12-13 (MOVEA) */
	    if (Dest.Mode == DReg)	/* Can't be to data register! */
		Error(DestLoc,ModeErr);	/* (Others are caught elsewhere) */
	    Op |= (Dest.Rn << 9);
	    if (Size ==	Byte) Error (OpLoc+6, SizeErr);
	    if (Size ==	Word) Op |= 0x3000;
	    if (Size ==	Long) Op |= 0x2000;
	}

	if (EA05a IN AdrModeB)		/* Effective address - all */
	    if ((Dest.Mode == DReg) || (Dest.Mode == ARDir))
		EffAdr (&Src, ea);
	    else
		Error (DestLoc,	ModeErr);

	if (EA05b IN AdrModeB)	/* Eff.	Addr. -	all except ARDir */
	    if (Dest.Mode == DReg) {
		EffAdr (&Src, dea);
		Op |= (Dest.Rn << 9);
	    } else
		Error (DestLoc,	ModeErr);

	if (EA05c IN AdrModeB)		/* BTST	*/
	    EffAdr (&Dest, 0x0802);	/* All but ARDir/Imm */

	if(EA05d IN AdrModeB) {	/* All but PC relative & immediate */
	    EffAdr (&Dest, aea);
	    if ((Dest.Mode == ARDir) &&	(Size == Byte))
		Error (OpLoc+5,	SizeErr);
	}

	if(EA05e IN AdrModeB) {	/* All but ARDir, PC relative, Imm */
	    if (Dest.Mode == Null)
		EffAdr (&Src, (dea | aea));
	    else if ((Src.Mode == Imm) || (Src.Mode == DReg))
		EffAdr (&Dest, (dea | aea));
	    else
		Error (SrcLoc, ModeErr);
	}

	if (EA05f IN AdrModeB) {	/* JMP,	JSR, LEA, and PEA */
	    EffAdr (&Src, cea);
	    if (Rx911 IN AdrModeA)
		if (Dest.Mode == ARDir)
		    Op |= (Dest.Rn << 9);   /* Address Reg. for	LEA */
		else
		    Error(DestLoc,ModeErr); /* Must load Address Reg. */
	    else
		if (Dest.Mode != Null)
		    Error (DestLoc, OperErr);	/* No Dest. unless LEA */
	}

	if (EA05x IN AdrModeB) {	/* AND and OR */
	    if (Dest.Mode == DReg)
		EffAdr (&Src, dea);
	    else if (Src.Mode == DReg)
		EffAdr (&Dest, mea | aea);
	    else
		Error (SrcLoc, OperErr);
	}

	if (EA05y IN AdrModeB) {	/* ADD and SUB */
	    if (Dest.Mode == DReg) {
		EffAdr (&Src, ea);
		if ((Src.Mode == ARDir)	&& (Size == Byte))
		    Error (OpLoc+4, SizeErr);
	    } else if (Src.Mode	== DReg)
		EffAdr (&Dest, (mea | aea));
	    else
		Error (SrcLoc, ModeErr);
	}
    }

    if (EA05z IN AdrModeB) {	    /* MOVEM */
	if (Pass2) {
	    if (Src.Mode == MultiM) {		/* Move	to memory */
		EffAdr (&Dest, (mea | aea | 0x0008));
		ExtL = Src.Value;
		i = (Dest.Mode == ARPre);	/* ExtL	flip indicator */
	    } else if (Dest.Mode == MultiM) {	/* Move	from memory */
		Op |= 0x0400;			/* Set direction */
		EffAdr (&Src, (mea | 0x0810));
		ExtL = Dest.Value;
		i = (Src.Mode == ARPre);
	    } else {
		Error (SrcLoc, OperErr);
		i = FALSE;
	    }
	    if (i) {				/* Flip	ExtL if	ARPre */
		j = 0;
		for (i = 0; i <	8; i++)
		    j |= (ExtL & (1<<i)) << (15-i*2);
		for (i = 8; i <	16; i++)
		    j |= (ExtL & (1<<i)) >> (i*2-15);
		ExtL = j;
	    }
	}
	nO += 2;	/* Extension is	part of	OpCode */
	InstSize += 2;
    }

    if (Pass2) {

	if (EA611 IN AdrModeB) {	/* Eff.	Addr. in 6-11 (MOVE) */
	    if (Dest.Mode == CCR) {		/* MOVE	to CCR */
		Op = 0x44C0;
		EffAdr (&Src, dea);
	    } else if (Dest.Mode == SR)	{	/* MOVE	to SR */
		Op = 0x46C0;
		EffAdr (&Src, dea);
	    } else if (Src.Mode	== SR) {	/* MOVE	from SR	*/
		Op = 0x40C0;
		EffAdr (&Dest, dea | aea);
	    } else if (Dest.Mode == USP) {	/* MOVE	to USP */
		Op = 0x4E60;
		if (Src.Mode ==	ARDir)
		    Op |= Src.Rn;
		else
		    Error (SrcLoc, ModeErr);
	    } else if (Src.Mode	== USP)	{	/* MOVE	from USP */
		Op = 0x4E68;
		if (Dest.Mode == ARDir)
		    Op |= Dest.Rn;
		else
		    Error (DestLoc, ModeErr);
	    } else {			/* General MOVE	instruction */
		EffAdr (&Src, (ea | xxx));
		if ((Size == Byte) && (Src.Mode	== ARDir))
		    Error (SrcLoc, SizeErr);
		if (Src.Mode > 12)
		    Error (SrcLoc, ModeErr);
		if (((1<<(Dest.Mode-1))	IN (dea|aea)) || (Dest.Mode>12))
		    Error (DestLoc, ModeErr);
		else if	(Dest.Mode < 8)	/* Register direct or indirect */
		    Op |= ((Dest.Mode -	1) << 6) | (Dest.Rn << 9);
		else		/* Absolute, PC	relative, or immediate */
		    Op |= 0x01C0 | ((Dest.Mode - 8) << 9);
		OperExt	(&Dest);	    /* Set up extension	word */
	    }
	}

	if ((Dest.Mode == CCR) && (Src.Mode == Imm)) {
	    if ((Size67	IN AdrModeB)
	    && (EA05e IN AdrModeB)
	    && (Exten IN AdrModeB))
		if (0x0400 IN Op)	/* not ANDI/EORI/ORI */
		    Error (DestLoc, ModeErr);
		else
		    Op = (Op & 0xFF00) | 0x003C;
	}

	if ((Dest.Mode == SR) && (Src.Mode == Imm)) {
	    if ((Size67	IN AdrModeB)
	    && (EA05e IN AdrModeB)
	    && (Exten IN AdrModeB))
		if (0x0400 IN Op)	/* not ANDI/EORI/ORI */
		    Error (DestLoc, ModeErr);
		else
		    Op = (Op & 0xFF00) | 0x007C;
	}
    }

    ObjOp = Op;
    InstSize +=	2;
    nO += 2;
    if (nO > 2)	{
	templong = ExtL;			/* Add extension word */
	ObjOp =	(ObjOp << 16) |	(templong & 0x0000FFFFL);
    }
    if ((AdrModeA != 0)	|| (AdrModeB !=	0)) {
	InstSize += (nS	= GetInstModeSize (Src.Mode));
	ObjSrc = Src.Value;
	InstSize += (nD	= GetInstModeSize (Dest.Mode));
	ObjDest	= Dest.Value;
    }
    if (quick) {
	InstSize -= nS;		/* Source operand is in	Op */
	nS = 0;
    }

    if (Pass2) {
	if ((nS!=0) && (Src.Hunk!=ABSHUNK)) {	/* SrcOp relocatable */
	    if ((Src.Mode == AbsL)
	    || (Src.Mode == AbsW)
	    || (Src.Mode == ARDisp)
	    || (Src.Mode == PCDisp)
	    || (Src.Mode == Imm)) {
		templong = AddrCnt+nO;	/* 32- or 16-bit relocatable */
		PutRel (templong, Src.Hunk, nS);
	    }
	    if ((Src.Mode==ARDisX) || (Src.Mode==PCDisX)) {
		templong = AddrCnt + nO	+ 1;	/* 8-bit relocatable */
		PutRel (templong, Src.Hunk, 1);
	    }
	}
	if ((nD!=0) && (Dest.Hunk!=ABSHUNK)) {	/* DestOp relocatable */
	    if ((Dest.Mode == AbsL)
	    || (Dest.Mode == AbsW)
	    || (Dest.Mode == ARDisp)
	    || (Dest.Mode == PCDisp)
	    || (Dest.Mode == Imm)) {
		templong = AddrCnt+nO+nS; /* 32- or 16-bit relocatable */
		PutRel (templong, Dest.Hunk, nD);
	    }
	    if ((Dest.Mode==ARDisX) || (Dest.Mode==PCDisX)) {
		templong = AddrCnt+nO+nS+1;	/* 8-bit relocatable */
		PutRel (templong, Dest.Hunk, 1);
	    }
	}
    }
    AddrAdv = InstSize;
}
