/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*	     Object code generator - September 2, 1987		    */
/*								    */
/*   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 (c) 1987 by Charlie Gibbs.    */
/*								    */
/*------------------------------------------------------------------*/

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

/* Functions */
extern int  LineParts(), GetField(), Instructions(), ObjDir();
extern int  GetSize(), GetInstModeSize(), GetMultReg();
extern int  ReadSymTab(), GetArgs(), GetAReg(),	OpenIncl();
extern long AddrBndW(),	AddrBndL(), GetValue(),	CalcValue();
extern char *malloc();
extern FILE *fopen();



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;

    if (Dir != None)
	return;				/* Directive - already done */

    if ((Label[0] != '\0') || (OpCode[0] != '\0'))
	PrntAddr = TRUE;		/* Print address at least */

    if (OpCode[0] == '\0')
	return;				/* No op code, exit now	*/

    if (!Instructions (OpLoc)) {	/* Get instruction parts */
	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 = ftell(InFile);	/*  remember where we are */
	tempop[0] = ' ';
	tempop[1] = '\0';
	strcat (tempop,	OpCode);	/* Prepend a blank to OpCode */
	if (ReadSymTab (tempop)) {	/* Search for user macro */
	    AddRef (LineCount);
	    InFNum++;
	    if (--InF <	LowInF)
		LowInF = InF;
	    MacCount++;
	    Heap2Space (0);		/* Check for space */
	    InF->UPtr =	Heap + 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 */
	    if (InF->UPtr == 0)	{
		InFile = fopen (InF->NPtr, "r");
		fseek (InFile, InF->Pos, 0);
	    }
	    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;
    }

    AddrCnt = AddrBndW (AddrCnt);	/* It'll be word-aligned */

    if ((AdrModeA != 0)	|| (AdrModeB !=	0)) {
	Src.Loc	= SrcLoc;
	Dest.Loc = DestLoc;
	GetOperand (SrcOp, &Src);
	GetOperand (DestOp, &Dest);
    }
    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	*/
	    && (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);
    }


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

    if ((AdrModeA != 0)	|| (AdrModeB !=	0))
	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 destination */

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

    if (DecBr IN AdrModeA) {
	if (Src.Mode !=	DReg)
	    Error (SrcLoc, ModeErr);

	ObjSrc = Dest.Value - AddrCnt -	2; /* Relative branch distance */

	if ((ObjSrc>32767) || (ObjSrc <	-32768)	|| (Dest.Hunk!=CurrHunk))
	    Error (DestLoc, BraErr);	/* Too far to branch */

	Dest.Hunk = ABSHUNK;
	AddrAdv	= 4;
	nO = nS	= 2;
	ObjOp =	Op | Src.Rn;
	return;
    }

    /* ------------------------	Branch (Bcc) ------------------------ */
    if (Brnch IN AdrModeA) {
	ObjSrc = Src.Value - AddrCnt - 2; /* Relative branch distance */

	if (DefLine2 <=	LineCount)
	    if ((ObjSrc	>= -128) && (ObjSrc <= 127))
		Size = Byte;		/* Short branch	if possible */

	if (Size != Byte) {
	    InstSize = 4;
	    nS = 2;
	    templong = 32767;
	} else {
	    InstSize = 2;
	    Op |= (ObjSrc & 0x00FF);
	    templong = 127;
	}

	if ((ObjSrc > templong)	|| (ObjSrc < -templong-1)
	|| (Src.Hunk !=	CurrHunk))
	    Error (SrcLoc, BraErr);	/* Too far to branch */

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

	Src.Hunk = ABSHUNK;
	AddrAdv	= InstSize;
	ObjOp =	Op;
	nO = 2;
	return;
    }

    if ((Op == JMP) || (Op == JSR))	/* Allows for 'JMP.S' */
	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 5 special cases first */

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

    if (Op == LINK) {
	Op |= Src.Rn;
	if ((Src.Mode != ARDir)	|| (Dest.Mode != Imm))
	    Error (SrcLoc, ModeErr);
    }

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

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

/* Now do generalized address modes */

    if ((Ry02 IN AdrModeA) && (Rx911 IN	AdrModeA)) { /*	Two 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 (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 (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 (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 */
	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) */
	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 */
	i = FALSE;				/* ExtL	flip indicator */
	if (Src.Mode ==	MultiM)	{
	    EffAdr (&Dest, (mea	| aea |	0x0008));
	    if ((ExtL =	Src.Value) == 0)
		ExtL = GetMultReg (SrcOp, (Dest.Mode ==	ARPre),	SrcLoc);
	    else
		i = (Dest.Mode == ARPre);	/* Already have	mask */
	} else if (Dest.Mode ==	MultiM)	{
	    Op |= 0x0400;			/* Set direction */
	    EffAdr (&Src, (mea | 0x0810));
	    if ((ExtL =	Dest.Value) == 0)
		ExtL = GetMultReg (DestOp, (Src.Mode ==	ARPre),	DestLoc);
	    else
		i = (Src.Mode == ARPre);
	} else
	    Error (SrcLoc, OperErr);
	if (i) {				/* Flip	ExtL */
	    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 (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 ((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;		/* 16-bit relocatable */
	    PutRel (Srec, templong, Src.Hunk, nS);
	}
	if ((Src.Mode==ARDisX) || (Src.Mode==PCDisX)) {
	    templong = AddrCnt + nO + 1;	/* 8-bit relocatable */
	    PutRel (Srec, 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;	/* 16-bit relocatable */
	    PutRel (Srec, templong, Dest.Hunk, nD);
	}
	if ((Dest.Mode==ARDisX)	|| (Dest.Mode==PCDisX))	{
	    templong = AddrCnt + nO + nS + 1;	/* 8-bit relocatable */
	    PutRel (Srec, templong, Dest.Hunk, 1);
	}
    }

    AddrAdv = InstSize;
}
