/* coderx.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator Renesas RX                                                  */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"
#include <ctype.h>
#include <string.h>

#include "nls.h"
#include "strutil.h"
#include "chunks.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "codevars.h"
#include "codepseudo.h"
#include "headids.h"
#include "errmsg.h"
#include "ieeefloat.h"
#include "onoff_common.h"
#include "intpseudo.h"
#include "be_le.h"

#include "coderx.h"

/*---------------------------------------------------------------------------*/

/* Define this to use Renesas Assembler like pseudo instructions */
#define COMPAT

/*---------------------------------------------------------------------------*/

typedef enum
{
	eRn,
	eDRn,
	eDRHn,
	eDRLn,
	eDCRn
} tRegType;

typedef enum
{
	eRXv1,
	eRXv2,
	eRXv3
} tInstSet;

typedef struct
{
	char Name[7];
	tInstSet InstSet;
	Boolean hasFloat;
	Boolean hasDouble;
	Word RegBank;
	Boolean hasMVTIPL;
} tCPUProps;

/*---------------------------------------------------------------------------*/

static const tCPUProps *pCurrCPUProps;

static tStrComp Temp1;
static tStrComp Temp2;

/*---------------------------------------------------------------------------*/

static Boolean ChkNoAttr(void)
{
	if (AttrPart.str.p_str[0])
	{
		WrError(ErrNum_UseLessAttr);
		return False;
	}

	return True;
}

static Boolean CheckSup(void)
{
	if (SupAllowed) return True;
	
	WrStrErrorPos(ErrNum_PrivOrder, &OpPart);
	return False;
}

static Boolean CheckV2(void)
{
	if (pCurrCPUProps->InstSet >= eRXv2) return True;

	WrError(ErrNum_InstructionNotSupported);
	return False;
}

static Boolean CheckV3(void)
{
	if (pCurrCPUProps->InstSet >= eRXv3) return True;

	WrError(ErrNum_InstructionNotSupported);
	return False;
}

static Boolean CheckFloat(void)
{
	if (pCurrCPUProps->hasFloat) return True;

	WrError(ErrNum_FPUNotEnabled);
	return False;
}

static Boolean CheckDouble(void)
{
	if (pCurrCPUProps->hasDouble) return True;

	WrError(ErrNum_FPUNotEnabled);
	return False;
}

static const char *DCReg[] = {
	"DPSW",
	"DCMR",
	"DECNT",
	"DEPC"
};

static Boolean DecodeReg(const tStrComp *pArg, Byte *pResult, tRegType type)
{
	const char *str = pArg->str.p_str;
	const int len = strlen(str);
	int i;
	int num = 16;

	switch (type)
	{
	case eRn:
		if (as_strncasecmp(str, "R", 1)) return False;
		i = 1;
		break;
	case eDRn:
		if (as_strncasecmp(str, "DR", 2)) return False;
		i = 2;
		break;
	case eDRHn:
		if (as_strncasecmp(str, "DRH", 3)) return False;
		i = 3;
		break;
	case eDRLn:
		if (as_strncasecmp(str, "DRL", 3)) return False;
		i = 3;
		break;
	case eDCRn:
		for (i = 0; i < 4; i++)
		{
			if (!as_strcasecmp(str, DCReg[i]))
			{
				*pResult = i;
				return True;
			}
		}
		if (as_strncasecmp(str, "DCR", 3)) return False;
		i = 3;
		num = 4;
		break;
	default:
		return False;
	}
	*pResult = 0;
	for (; i < len; i++)
	{
		if (!isdigit(str[i])) return False;
		*pResult = *pResult * 10 + (str[i] - '0');
	}

	return *pResult < num;
}

static Boolean DecodeImm(const tStrComp *pArg, LongInt *pResult, tSymbolFlags *pFlags)
{
	const char *str = pArg->str.p_str;
	tStrComp ImmArg;
	Boolean ValOK;
	tSymbolFlags flags;

	if (str[0] != '#') return False;

	StrCompRefRight(&ImmArg, pArg, 1);
	*pResult = EvalStrIntExpressionWithFlags(&ImmArg, Int32, &ValOK, &flags);
	if (pFlags) *pFlags = flags;

	return ValOK;
}

static Byte ImmSize32(LongInt value, tSymbolFlags flags)
{
	if (mFirstPassUnknown(flags)) return 0x00;	/* Temporarily return maximum size */

	if ((value & 0xFFFFFF80) == 0xFFFFFF80 ||
		(value & 0xFFFFFF80) == 0x00000000) return 0x01;	/* SIMM:8 */

	if ((value & 0xFFFF8000) == 0xFFFF8000 ||
		(value & 0xFFFF8000) == 0x00000000) return 0x02;	/* SIMM:16 */

	if ((value & 0xFF800000) == 0xFF800000 ||
		(value & 0xFF800000) == 0x00000000) return 0x03;	/* SIMM:24 */

	return 0x00;	/* IMM:32 */
}

static Byte ImmSize16(LongInt value, tSymbolFlags flags)
{
	if (mFirstPassUnknown(flags)) return 0x02;	/* Temporarily return maximum size */

	if ((value & 0xFFFFFF80) == 0xFFFFFF80 ||
		(value & 0xFFFFFF80) == 0x00000000) return 0x01;	/* SIMM:8 */

	return 0x02;	/* IMM:16 */
}

static int ImmOut(int pos, Byte size, LongInt imm)
{
	int i;

	if (size == 0x00) size = 4;
	for (i = 0; i < size; i++)
	{
		BAsmCode[pos+i] = imm & 0xFF;
		imm >>= 8;
	}
	return pos + size;
}

static Boolean DecodeIndirectADC(const tStrComp *pArg, Byte *reg, LongInt *disp, tSymbolFlags *flags)
{
	const char *str = pArg->str.p_str;
	const int len = strlen(str);
	int pos;
	Boolean ValOK;

	if (str[len-1] != ']') return False;
	for (pos = len - 2; pos >= 0; pos--)
	{
		if (str[pos] == '[') break;
	}
	if (pos < 0) return False;

	StrCompCopySub(&Temp1, pArg, pos + 1, len - pos - 2);
	if (!DecodeReg(&Temp1, reg, eRn)) return False;

	if (pos == 0)
	{
		*flags = eSymbolFlag_None;
		*disp = 0;
		return True;
	}

	StrCompCopySub(&Temp1, pArg, 0, pos);
	*disp = EvalStrIntExpressionWithFlags(&Temp1, UInt20, &ValOK, flags);

	return ValOK;
}

static Byte DispSize(LongInt disp, tSymbolFlags flags, Byte scale)
{
	Byte size = 0;
	Byte mask = scale - 1;

  UNUSED(flags);

	if (disp & mask)
	{
		WrStrErrorPos(ErrNum_NotAligned, &ArgStr[1]);
		return 0;
	}
	disp /= scale;

	if (disp == 0) size = 0x00;
	else if (disp < 0) size = 0xFF;
	else if (disp < 256) size = 0x01;
	else if (disp < 65536) size = 0x02;
	else size = 0xFF;

	return size;
}

static int DispOut(int pos, Byte size, LongInt disp, Byte scale)
{
	int i;

	disp /= scale;

	if (size > 0x02) size = 0x00;
	for (i = 0; i < size; i++ )
	{
		BAsmCode[pos+i] = disp & 0xFF;
		disp >>= 8;
	}
	return  pos + size;
}

static Boolean DecodeIndirectADD(const tStrComp *pArg, Byte *reg, LongInt *disp, tSymbolFlags *flags, Byte *memex, Byte *scale)
{
	const char *str = pArg->str.p_str;
	const int len = strlen(str);

	if (len > 2 && str[len-2] == '.')
	{
		switch (as_toupper(str[len-1]))
		{
		case 'B':
			*memex = 0x00;
			*scale = 1;
			break;
		case 'W':
			*memex = 0x01;
			*scale = 2;
			break;
		case 'L':
			*memex = 0x02;
			*scale = 4;
			break;
		default:
			return False;
		}
		StrCompCopySub(&Temp2, pArg, 0, len - 2);
		pArg = &Temp2;
	}
	else if (len > 3 && str[len-3] == '.' && as_toupper(str[len-2]) == 'U')
	{
		switch (as_toupper(str[len-1]))
		{
		case 'B':
			*memex = 0x80;
			*scale = 1;
			break;
		case 'W':
			*memex = 0x03;
			*scale = 2;
			break;
		default:
			return False;
		}
		StrCompCopySub(&Temp2, pArg, 0, len - 3);
		pArg = &Temp2;
	}

	return DecodeIndirectADC(pArg, reg, disp, flags);
}

static Boolean DecodeFloat(const tStrComp *pArg, LongInt *pResult)
{
	const char *str = pArg->str.p_str;
	tStrComp ImmArg;
	TempResult temp;
  Boolean Result = True;

	if (str[0] != '#') return False;

	StrCompRefRight(&ImmArg, pArg, 1);
  as_tempres_ini(&temp);
	EvalStrExpression(&ImmArg, &temp);
	switch (temp.Typ)
	{
	case TempInt:
		*pResult = temp.Contents.Int;
		break;
	case TempFloat:
		as_float_2_ieee4(temp.Contents.Float, (unsigned char *)pResult, False);
    /* TODO: rework this - we should better pass in a byte array as pResult */
    if (HostBigEndian)
      DSwap(pResult, 4);
		break;
	default:
		Result = False;
	}
  as_tempres_free(&temp);

	return Result;
}

static Boolean DecodeIndirectL(const tStrComp *pArg, Byte *reg, LongInt *disp, tSymbolFlags *flags)
{
	Boolean result;
	Byte memex = 0x02;	/* L */
	Byte scale;

	result = DecodeIndirectADD(pArg, reg, disp, flags, &memex, &scale);

	if (result && memex != 0x02) result = False;

	return result;
}

static tSymbolSize DecodeAttrSize(void)
{
	switch (strlen(AttrPart.str.p_str))
	{
		case 0:
			WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
			return eSymbolSizeUnknown;
		case 1:
			switch (AttrPart.str.p_str[0])
			{
				case 'B':
					return eSymbolSize8Bit;
				case 'W':
					return eSymbolSize16Bit;
				case 'L':
					return eSymbolSize32Bit;
				default:
					WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
					return eSymbolSizeUnknown;
			}
		default:
			WrStrErrorPos(ErrNum_TooLongAttr, &AttrPart);
			return eSymbolSizeUnknown;
		}
}

static Boolean DecodeRelative(const tStrComp *pArg, Byte *reg, LongInt *disp, tSymbolFlags *flags)
{	/* dsp:5[Rn] (R0-R7) */
	const char *str = pArg->str.p_str;
	const int len = strlen(str);
	int pos;
	Boolean ValOK;

	if (str[len-1] != ']') return False;
	for (pos = len - 2; pos > 0; pos--)
	{
		if (str[pos] == '[') break;
	}
	if (pos < 1) return False;

	StrCompCopySub(&Temp1, pArg, pos + 1, len - pos - 2);
	if (!DecodeReg(&Temp1, reg, eRn)) return False;
	if (*reg > 7) return False;

	StrCompCopySub(&Temp1, pArg, 0, pos);
	*disp = EvalStrIntExpressionWithFlags(&Temp1, UInt20, &ValOK, flags);

	return ValOK;
}

static int Size2Scale(Byte size)
{
	Byte scale;

	switch (size)
	{
	case 0x00:	/* B */
		scale = 1;
		break;
	case 0x01:	/* W */
		scale = 2;
		break;
	case 0x02:	/* L */
		scale = 4;
		break;
	default:
		return -1;
	}

	return scale;
}

static Boolean ChkDisp5(Byte size, LongInt disp, tSymbolFlags flags)
{
	const int scale = Size2Scale(size);

	if (scale < 0) return False;
	
	if (!mFirstPassUnknown(flags))
	{
		if (disp & (scale - 1))
		{
			WrError(ErrNum_AddrMustBeAligned);
			return False;
		}

		if (disp / scale > 31 || disp < 0) return False;
	}

	return True;
}

static Byte DispSize5(Byte size, LongInt disp)
{
	const Byte scale = Size2Scale(size);

	return disp / scale;
}

static Boolean DecodeIndexed(tStrComp *pArg, Byte *regi, Byte *regb)
{	/* [Ri,Rb] */
	const char *str = pArg->str.p_str;
	const int len = strlen(str);
	int pos;

	if (str[0] != '[' || str[len-1] != ']') return False;

	for (pos = 2; pos < len - 2; pos++)
	{
		if (str[pos] == ',') break;
	}

	StrCompCopySub(&Temp1, pArg, 1, pos - 1);
	if (!DecodeReg(&Temp1, regi, eRn)) return False;

	StrCompCopySub(&Temp1, pArg, pos + 1, len - pos - 2);
	if (!DecodeReg(&Temp1, regb, eRn)) return False;

	return True;
}

static Boolean DecodeIncDec(tStrComp *pArg, Byte *reg, Byte *id)
{	/* [Rn+] / [-Rn]] */
	const char *str = pArg->str.p_str;
	const int len = strlen(str);

	if (len < 5) return False;
	if (str[0] != '[' || str[len-1] != ']') return False;

	if (str[len-2] == '+')
	{
		*id = 0x00;
		StrCompCopySub(&Temp1, pArg, 1, len - 3);
	}
	else if (str[1] == '-')
	{
		*id = 0x01;
		StrCompCopySub(&Temp1, pArg, 2, len - 3);
	}
	else return False;

	return DecodeReg(&Temp1, reg, eRn);
}

static Boolean DecodeRegRange(tStrComp *pArg, Byte *range)
{
	const char *str = pArg->str.p_str;
	const int len = strlen(str);
	Byte reg1;
	Byte reg2;
	int pos;

	if (len < 5) return False;
	for (pos = 2; pos < len - 2; pos++)
	{
		if (str[pos] == '-') break;
	}
	if (pos >= len - 2) return False;

	StrCompCopySub(&Temp1, pArg, 0, pos);
	if (!DecodeReg(&Temp1, &reg1, eRn)) return False;

	StrCompCopySub(&Temp1, pArg, pos + 1, len - pos - 1);
	if (!DecodeReg(&Temp1, &reg2, eRn)) return False;

	if (reg1 == 0 || reg1 >= reg2) return False;

	*range = (reg1 << 4) | reg2;
	return True;
}

static Boolean DecodeIndirect(tStrComp *pArg, Byte *reg)
{
	const char *str = pArg->str.p_str;
	const int len = strlen(str);

	if (str[0] != '[') return False;
	if (str[len-1] != ']') return False;

	StrCompCopySub(&Temp1, pArg, 1, len - 2);
	if (!DecodeReg(&Temp1, reg, eRn)) return False;

	return True;
}

static Boolean DecodeAcc(tStrComp *pArg, Byte *acc)
{
	const char *str = pArg->str.p_str;
	const int len = strlen(str);

	if (len != 2) return False;
	if (as_toupper(str[0]) != 'A') return False;
	if (str[1] != '0' && str[1] != '1') return False;

	*acc = str[1] - '0';
	return True;
}

static Boolean DecodeAttrDouble(Byte *size)
{
	if (strlen(AttrPart.str.p_str) != 1)
	{
		WrStrErrorPos(ErrNum_TooLongAttr, &AttrPart);
		return False;
	}
	switch (as_toupper(AttrPart.str.p_str[0]))
	{
	case 'L':
		*size = 0;
		break;
	case 'D':
		*size = 1;
		break;
	default:
		WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
		return False;
	}

	return True;
}

/*---------------------------------------------------------------------------*/

static void DecodeABS(Word Index)
{
	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,2)) return;

	if (ArgCnt == 1)
	{
		Byte reg;

		if (!DecodeReg(&ArgStr[1], &reg, eRn))
		{
			WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
			return;
		}
		
		BAsmCode[0] = 0x7E;
		BAsmCode[1] = (Index >> 8) | reg;
		CodeLen = 2;
	}
	else
	{
		Byte regs;
		Byte regd;

		if (!DecodeReg(&ArgStr[1], &regs, eRn))
		{
			WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
			return;
		}
		if (!DecodeReg(&ArgStr[2], &regd, eRn))
		{
			WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
			return;
		}

		BAsmCode[0] = 0xFC;
		BAsmCode[1] = Index & 0xFF;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
	}
}

static void DecodeADC(Word Index)
{
	Byte regs;
	Byte regd;
	Byte size;
	LongInt imm;
	tSymbolFlags flags;
	LongInt disp;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	if ((Index & 0x0800) && DecodeImm(&ArgStr[1], &imm, &flags))	/* ADC only */
	{
		size = ImmSize32(imm, flags);

		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x70 | (size << 2);
		BAsmCode[2] = 0x20 | regd;
		CodeLen = ImmOut(3, size, imm);

		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		BAsmCode[0] = 0xFC;
		BAsmCode[1] = 0x03 | (Index >> 8);
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;

		return;
	}

	if (DecodeIndirectL(&ArgStr[1], &regs, &disp, &flags))
	{
		if (mFirstPassUnknown(flags)) size = 0x02;
		else size = DispSize(disp, flags, 4);

		BAsmCode[0] = 0x06;
		BAsmCode[1] = 0xA0 | size;
		BAsmCode[2] = Index & 0xFF;
		BAsmCode[3] = (regs << 4) | regd;
		CodeLen = DispOut(4, size, disp, 4);
	}
}

static const struct {
	Byte OpcImm4;	/* #IMM:4,Rd */
	Byte OpcImm1;	/* #IMM:*(,Rs),Rd 1st byte */
	Byte OpcImm2;	/* 2nd byte */
	Byte Opc2;	/* Rs,Rd / [Rs].UB,Rd */
	Byte Opc3;	/* Rs,Rs2,Rd */
	Byte Opc4;	/* [Rs],Rd */
	Byte flags;	/* 1<<0:, 1<<1:, 1<<2:#UIMM8 1<<3:Rs,Rs,Rd */
} OpTabADD[] = {
	{ 0x62, 0x70, 0x00, 0x48, 0x20, 0x08, 0x0B },	/* ADD */
	{ 0x64, 0x74, 0x20, 0x50, 0x40, 0x10, 0x09 },	/* AND */
	{ 0x61, 0x74, 0x00, 0x44, 0,    0x04, 0x05 },	/* CMP */
	{ 0x63, 0x74, 0x10, 0x4C, 0x30, 0x0C, 0x09 },	/* MUL */
	{ 0x65, 0x74, 0x30, 0x54, 0x50, 0x14, 0x09 },	/* OR */
	{ 0x60, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08 },	/* SUB */
};

static void DecodeADD(Word Index)
{
	Byte regs1;
	Byte regs2;
	Byte regd;
	Byte size;
	LongInt imm;
	tSymbolFlags flags;
	LongInt disp;
	Byte memex;
	Byte scale;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,3)) return;

	if (!DecodeReg(&ArgStr[2], &regs2, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}
	if (ArgCnt == 2)
		regd = regs2;
	else
	{
		if (!DecodeReg(&ArgStr[3], &regd, eRn))
		{
			WrStrErrorPos(ErrNum_InvRegName, &ArgStr[3]);
			return;
		}
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (ArgCnt == 2 && !mFirstPassUnknown(flags) && imm >= 0 && imm < 16 )
		{	/* #UIMM:4 */
			BAsmCode[0] = OpTabADD[Index].OpcImm4;
			BAsmCode[1] = (imm << 4) | regd;
			CodeLen = 2;
			return;
		}

		if ((OpTabADD[Index].flags & 0x04) && ArgCnt == 2 &&
			!mFirstPassUnknown(flags) && imm >= 0 && imm < 256)
		{	/* #UIMM:8 */
			BAsmCode[0] = 0x75;
			BAsmCode[1] = 0x50 | regd;
			BAsmCode[2] = imm;
			CodeLen = 3;
			return;
		}

		if (((OpTabADD[Index].flags & 0x01) && ArgCnt == 2) || (OpTabADD[Index].flags & 0x02))
		{	/* #SIMM:* */
			size = ImmSize32(imm, flags);

			BAsmCode[0] = OpTabADD[Index].OpcImm1 | size;
			if (OpTabADD[Index].flags & 0x02)
				if (ArgCnt == 2)
					BAsmCode[1] = (regd << 4) | regd;	/* #Imm,Rd */
				else
					BAsmCode[1] = (regs2 << 4) | regd;	/* #imm,Rs,Rd */
			else
				BAsmCode[1] = OpTabADD[Index].OpcImm2 | regd;
			CodeLen = ImmOut(2, size, imm);
			return;
		}
	}

	if (DecodeReg(&ArgStr[1], &regs1, eRn))
	{	/* Rs */
		if (ArgCnt == 2)
		{
			BAsmCode[0] = OpTabADD[Index].Opc2 | 0x03;
			BAsmCode[1] = (regs1 << 4) | regd;
			CodeLen = 2;
		}
		else if (OpTabADD[Index].flags & 0x08)
		{
			BAsmCode[0] = 0xFF;
			BAsmCode[1] = OpTabADD[Index].Opc3 | regd;
			BAsmCode[2] = (regs1 << 4) | regs2;
			CodeLen = 3;
		}
		else WrStrErrorPos(ErrNum_TooManyArgs, &ArgStr[3]);
		return;
	}

	if (ArgCnt == 2 && DecodeIndirectADD(&ArgStr[1], &regs1, &disp, &flags, &memex, &scale))
	{
		if (memex == 0x80)
		{
			size = DispSize(disp, flags, 1);

			BAsmCode[0] = OpTabADD[Index].Opc2 | size;
			BAsmCode[1] = (regs1 << 4) | regd;
			CodeLen = DispOut(2, size, disp, 1);
			return;
		}

		size = DispSize(disp, flags, scale);

		BAsmCode[0] = 0x06;
		BAsmCode[1] = OpTabADD[Index].Opc4 | (memex << 6) | size;
		BAsmCode[2] = (regs1 << 4) | regd;
		CodeLen = DispOut(3, size, disp, scale);
		return;
	}

	WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);
}

static const struct {
	Byte OpcIM1;	/* Imm3,[Rd] */
	Byte OpcIM2;
	Byte OpcRM;		/* Rs,[Rd] / Rs,Rd */
	Byte OpcIR;	/* #Imm5,Rd */
	Byte flags;
} OpTabBCLR[] = {
	{ 0xF0, 0x08, 0x64, 0x7A, 0x00 },	/* BCLR */
	{ 0xF0, 0x00, 0x6C, 0,    0x01 },	/* BNOT */
	{ 0xF0, 0x00, 0x60, 0x78, 0x00 },	/* BSET */
	{ 0xF4, 0x00, 0x68, 0x7C, 0x00 },	/* BTST */
};

static void DecodeBCLR(Word Index)
{
	Byte regs;
	Byte regd;
	Byte size;
	Byte memex;
	Byte scale;
	LongInt imm;
	LongInt disp;
	tSymbolFlags flags;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	memex = 0;
	if (DecodeIndirectADD(&ArgStr[2], &regd, &disp, &flags, &memex, &scale))
	{
		if (memex)
		{
			WrStrErrorPos(ErrNum_InvOpSize, &ArgStr[2]);
			return;
		}
		size = DispSize(disp, flags, 1);
		if (size > 0x02){
			WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
			return;
		}

		if (DecodeImm(&ArgStr[1], &imm, &flags))
		{
			if (!mSymbolQuestionable(flags) && (imm < 0 || imm > 7))
			{
				WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
				return;
			}

			if (OpTabBCLR[Index].flags & 0x01)
			{	/* BNOT */
				BAsmCode[0] = 0xFC;
				BAsmCode[1] = 0xE0 | (imm << 2) | size;
				BAsmCode[2] = 0x0F | (regd << 4);
				CodeLen = DispOut(3, size, disp, 1);
			}
			else
			{	/* BCLR, BSET, BTST */
				BAsmCode[0] = OpTabBCLR[Index].OpcIM1 | size;
				BAsmCode[1] = OpTabBCLR[Index].OpcIM2 | (regd << 4) | imm;
				CodeLen = DispOut(2, size, disp, 1);
			}
			return;
		}
		if (DecodeReg(&ArgStr[1], &regs, eRn))
		{
			BAsmCode[0] = 0xFC;
			BAsmCode[1] = OpTabBCLR[Index].OpcRM | size;
			BAsmCode[2] = regs | (regd << 4);
			CodeLen = DispOut(3, size, disp, 1);
			return;
		}

		WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);		
	}
	else if (DecodeReg(&ArgStr[2], &regd, eRn))
	{
		if (DecodeImm(&ArgStr[1], &imm, &flags))
		{
			if (!mSymbolQuestionable(flags) && (imm < 0 || imm > 31))
			{
				WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
				return;
			}

			if (OpTabBCLR[Index].flags & 0x01)
			{
				BAsmCode[0] = 0xFD;
				BAsmCode[1] = 0xE0 | imm;
				BAsmCode[2] = 0xF0 | regd;
				CodeLen = 3;
			}
			else
			{
				BAsmCode[0] = OpTabBCLR[Index].OpcIR | (imm >> 4);
				BAsmCode[1] = ((imm & 0x0F) << 4) | regd;
				CodeLen = 2;
			}
			return;
		}
		if (DecodeReg(&ArgStr[1], &regs, eRn))
		{
			BAsmCode[0] = 0xFC;
			BAsmCode[1] = OpTabBCLR[Index].OpcRM | 0x03;
			BAsmCode[2] = regs | (regd << 4);
			CodeLen = 3;
			return;
		}

		WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
}

static void DecodeBCnd(Word Index)
{
	const char *str = AttrPart.str.p_str;
	const int len = strlen(str);
	Byte attr = 0;
	Byte reg;
	LongInt addr;
	tSymbolFlags flags;
	Boolean ValOK;
	LongInt disp;

	if (len > 1)
	{
		WrStrErrorPos(ErrNum_TooLongAttr, &AttrPart);
		return;
	}
	if (len == 1)
	{
		attr = as_toupper(str[0]);
		switch (attr)
		{
		case 'S':
			break;
		case 'B':
			break;
		case 'W':
			break;
		case 'A':
		case 'L':
			if (Index != 14)
			{
				WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
				return;
			}
			break;
		default:
			WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
			return;
		}
	}

	if (!ChkArgCnt(1,1)) return;

	if ((attr == 0 || attr == 'L') && DecodeReg(&ArgStr[1], &reg, eRn))
	{
		BAsmCode[0] = 0x7F;
		BAsmCode[1] = 0x40 | reg;
		CodeLen = 2;
		return;
	}

	addr = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &ValOK, &flags);
	if (ValOK)
	{
		if (attr == 'L')
		{
			WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
			return;
		}

		disp = addr - EProgCounter();

		/* Try 3 bit */
		if ((attr == 0 || attr == 'S') && disp >= 3 && disp <= 10)
		{
			if (disp > 7) disp -= 8;

			if (Index == 0 || Index == 1)
			{

				BAsmCode[0] = 0x10 | (Index << 3) | disp;
				CodeLen = 1;
				return;
			}

			if (Index == 14)
			{
				BAsmCode[0] = 0x08 | disp;
				CodeLen = 1;
				return;
			}

			WrError(ErrNum_InternalError);
		}

		if (attr == 'S' && !mFirstPassUnknownOrQuestionable(flags))
		{
			WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
			return;
		}

		/* Try 8 bit */
		if ((attr == 0 || attr == 'B') &&
			((disp & 0xFFFFFF80) == 0xFFFFFF80 ||
			 (disp & 0xFFFFFF80) == 0x00000000))
		{
			BAsmCode[0] = 0x20 | Index;
			BAsmCode[1] = disp & 0xFF;
			CodeLen = 2;
			return;
		}

		if (attr == 'B' && !mFirstPassUnknownOrQuestionable(flags))
		{
			WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
			return;
		}

		/* Try 16 bit */
		if ((attr == 0 || attr == 'W') &&
			((disp & 0xFFFF8000) == 0xFFFF8000 ||
			 (disp & 0xFFFF8000) == 0x00000000))
		{
			if (Index == 0 || Index == 1)
			{
				BAsmCode[0] = 0x3A | Index;
				BAsmCode[1] = disp & 0xFF;
				BAsmCode[2] = (disp >> 8) & 0xFF;
				CodeLen = 3;
				return;
			}

			if (Index == 14)
			{
				BAsmCode[0] = 0x38;
				BAsmCode[1] = disp & 0xFF;
				BAsmCode[2] = (disp >> 8) & 0xFF;
				CodeLen = 3;
				return;
			}

			WrError(ErrNum_JmpDistTooBig);
			return;
		}
		
		if (attr == 'W' && !mFirstPassUnknownOrQuestionable(flags))
		{
			WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
			return;
		}
		
		/* Try 24 bit */
		if ((disp & 0xFF800000) == 0xFF800000 ||
			(disp & 0xFF800000) == 0x00000000)
		{
			if (Index == 14)
			{
				BAsmCode[0] = 0x04;
				BAsmCode[1] = disp & 0xFF;
				BAsmCode[2] = (disp >> 8) & 0xFF;
				BAsmCode[3] = (disp >> 16) & 0xFF;
				CodeLen = 4;
				return;
			}
		}

		WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
	}
}

static void DecodeBMCnd(Word Index)
{
	Byte regd;
	Byte size;
	Byte memex;
	Byte scale;
	LongInt imm;
	LongInt disp;
	tSymbolFlags flags;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	memex = 0;
	if (DecodeIndirectADD(&ArgStr[2], &regd, &disp, &flags, &memex, &scale))
	{
		if (memex)
		{
			WrStrErrorPos(ErrNum_InvOpSize, &ArgStr[2]);
			return;
		}
		size = DispSize(disp, flags, 1);
		if (size > 0x02){
			WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
			return;
		}
	}
	else if (DecodeReg(&ArgStr[2], &regd, eRn))
	{
		size = 0x03;
	}
	else
	{
		WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (size < 0x03)
		{
			/* #imm,disp[Rd] */
			if (!mSymbolQuestionable(flags) && (imm < 0 || imm > 7))
			{
				WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
				return;
			}

			BAsmCode[0] = 0xFC;
			BAsmCode[1] = 0xE0 | (imm << 2) | size;
			BAsmCode[2] = (regd << 4) | Index;
			CodeLen = DispOut(3, size, disp, 1);
			return;
		}
		else
		{
			/* #imm,Rd */
			if (!mSymbolQuestionable(flags) && (imm < 0 || imm > 31))
			{
				WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
				return;
			}
			
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0xE0 | imm;
			BAsmCode[2] = (Index << 4) | regd;
			CodeLen = 3;
			return;
		}
	}

	WrError(ErrNum_OverRange);
}

static void DecodeBRK(Word Index)
{
	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(0,0)) return;

	BAsmCode[0] = Index;
	CodeLen = 1;
}

static void DecodeBSR(Word Index)
{
	const char *str = AttrPart.str.p_str;
	const int len = strlen(str);
	Byte attr = 0;
	Byte reg;
	LongInt addr;
	tSymbolFlags flags;
	Boolean ValOK;
	LongInt disp;

  UNUSED(Index);

	if (len > 1)
	{
		WrStrErrorPos(ErrNum_TooLongAttr, &AttrPart);
		return;
	}
	if (len == 1)
	{
		attr = as_toupper(str[0]);
		switch (attr)
		{
		case 'W':
		case 'A':
		case 'L':
			break;
		default:
			WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
			return;
		}
	}

	if (!ChkArgCnt(1,1)) return;

	if ((attr == 0 || attr == 'L') && DecodeReg(&ArgStr[1], &reg, eRn))
	{
		BAsmCode[0] = 0x7F;
		BAsmCode[1] = 0x50 | reg;
		CodeLen = 2;
		return;
	}

	addr = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &ValOK, &flags);
	if (ValOK)
	{
		if (attr == 'L')
		{
			WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
			return;
		}

		disp = addr - EProgCounter();

		/* Try 16 bit */
		if ((attr == 0 || attr == 'W') &&
			((disp & 0xFFFF8000) == 0xFFFF8000 ||
			 (disp & 0xFFFF8000) == 0x00000000))
		{
			BAsmCode[0] = 0x39;
			BAsmCode[1] = disp & 0xFF;
			BAsmCode[2] = (disp >> 8) & 0xFF;
			CodeLen = 3;
			return;
		}

		if (attr == 'W' && !mFirstPassUnknownOrQuestionable(flags))
		{
			WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
			return;
		}
		
		/* Try 24 bit */
		if ((disp & 0xFF800000) == 0xFF800000 ||
			(disp & 0xFF800000) == 0x00000000)
		{
			BAsmCode[0] = 0x05;
			BAsmCode[1] = disp & 0xFF;
			BAsmCode[2] = (disp >> 8) & 0xFF;
			BAsmCode[3] = (disp >> 16) & 0xFF;
			CodeLen = 4;
			return;
		}

		WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
	}		
}

static const char *BitPSW[] = {
	"C",  "Z",  "S",  "O",  NULL, NULL, NULL, NULL,
	"I",  "U",  NULL, NULL, NULL, NULL, NULL, NULL };

static void DecodeCLRPSW(Word Index)
{
	int i;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	for (i = 0; i < 16; i++)
	{
		if (BitPSW[i] && !as_strcasecmp(ArgStr[1].str.p_str, BitPSW[i])) break;
	}

	if (i < 16)
	{
		BAsmCode[0] = 0x7F;
		BAsmCode[1] = Index | i;
		CodeLen = 2;
	}
	else WrStrErrorPos(ErrNum_UnknownFlag, &ArgStr[1]);
}

static const struct {
	Byte OpcI;
	Byte Opc2;
	Byte OpcM;
} OpTabDIV[] = {
	{ 0x80, 0x20, 0x08 },	/* DIV */
	{ 0x90, 0x24, 0x09 },	/* DIVU */
	{ 0x60, 0x18, 0x06 },	/* EMUL */
	{ 0x70, 0x1C, 0x07 },	/* EMULU */
	{ 0x40, 0x10, 0x04 },	/* MAX */
	{ 0x50, 0x14, 0x05 },	/* MIN */
};

static void DecodeDIV(Word Index)
{
	Byte regs;
	Byte regd;
	Byte size;
	LongInt imm;
	tSymbolFlags flags;
	LongInt disp;
	Byte memex;
	Byte scale;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		size = ImmSize32(imm, flags);

		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x70 | (size << 2);
		BAsmCode[2] = OpTabDIV[Index].OpcI | regd;
		CodeLen = ImmOut(3, size, imm);
		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		BAsmCode[0] = 0xFC;
		BAsmCode[1] = OpTabDIV[Index].Opc2 | 0x03;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
		return;
	}

	if (DecodeIndirectADD(&ArgStr[1], &regs, &disp, &flags, &memex, &scale))
	{
		if (memex == 0x80)
		{
			size = DispSize(disp, flags, 1);

			BAsmCode[0] = 0xFC;
			BAsmCode[1] = OpTabDIV[Index].Opc2 | size;
			BAsmCode[2] = (regs << 4) | regd;
			CodeLen = DispOut(3, size, disp, 1);
			return;
		}

		size = DispSize(disp, flags, scale);

		BAsmCode[0] = 0x06;
		BAsmCode[1] = 0x20 | (memex << 6) | size;
		BAsmCode[2] = OpTabDIV[Index].OpcM;
		BAsmCode[3] = (regs << 4) | regd;
		CodeLen = DispOut(4, size, disp, scale);
		return;
	}

	WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);	
}

static const struct {
	Byte OpcI;
	Byte OpcM;
	Byte Opc3;
	Byte flags;
} OpTabFADD[] = {
	{ 0x20, 0x88, 0xA0, 0x03 },	/* FADD */
	{ 0x10, 0x84, 0,    0x01 },	/* FCMP */
	{ 0x40, 0x90, 0,    0x01 },	/* FDIV */
	{ 0x30, 0x8C, 0xB0, 0x03 },	/* FMUL */
	{ 0x00, 0x80, 0x80, 0x03 },	/* FSUB */
	{ 0,    0x94, 0,    0x00 },	/* FTOI */
	{ 0,    0x98, 0,    0x00 },	/* ROUND */
	{ 0,    0xA0, 0,    0x10 },	/* FSQRT */
	{ 0,    0xA4, 0,    0x10 },	/* FTOU */
};

static void DecodeFADD(Word Index)
{
	Byte regs;
	Byte regd;
	Byte size;
	LongInt imm;
	LongInt disp;
	tSymbolFlags flags;

	if (!ChkNoAttr()) return;
	if (!CheckFloat()) return;

	if ((OpTabFADD[Index].flags & 0x02) && ArgCnt == 3)
	{
		Byte regs2;

		if (!DecodeReg(&ArgStr[1], &regs, eRn))
		{
			WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
			return;
		}
		if (!DecodeReg(&ArgStr[2], &regs2, eRn))
		{
			WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[2]);
			return;
		}
		if (!DecodeReg(&ArgStr[3], &regd, eRn))
		{
			WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[3]);
			return;
		}

		BAsmCode[0] = 0xFF;
		BAsmCode[1] = OpTabFADD[Index].Opc3 | regd;
		BAsmCode[2] = (regs << 4) | regs2;
		CodeLen = 3;
		return;
	}

	if (!ChkArgCnt(2,2)) return;

	if (OpTabFADD[Index].flags & 0x10)
	{
		if (!CheckV2()) return;
	}

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	if ((OpTabFADD[Index].flags & 0x01) &&
		DecodeFloat(&ArgStr[1], &imm))
	{
		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x72;
		BAsmCode[2] = OpTabFADD[Index].OpcI | regd;
		CodeLen = ImmOut(3, 0, imm);	/* size==0 means 4 byte */
		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		size = 0x03;
		disp = 0;
	}
	else if (DecodeIndirectL(&ArgStr[1], &regs, &disp, &flags))
	{
		if (mFirstPassUnknown(flags)) size = 0x02;
		else size = DispSize(disp, flags, 4);
	}
	else
	{
		WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);	
		return;
	}

	BAsmCode[0] = 0xFC;
	BAsmCode[1] = OpTabFADD[Index].OpcM | size;
	BAsmCode[2] = (regs << 4) | regd;
	CodeLen = DispOut(3, size, disp, 4);
}

static void DecodeINT(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (!mFirstPassUnknown(flags) && (imm < -128 || imm > 255))
		{
			WrStrErrorPos(ErrNum_ArgOutOfRange, &ArgStr[1]);
			return;
		}

		BAsmCode[0] = 0x75;
		BAsmCode[1] = 0x60;
		BAsmCode[2] = imm & 0xFF;
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);	
}

static const struct {
	Byte Opc1;
	Byte Opc2;
	Byte flags;
} OpTabITOF[] = {
	{ 0x44, 0x11, 0x00 },	/* ITOF */
	{ 0x54, 0x15, 0x10 },	/* UTOF */
};

static void DecodeITOF(Word Index)
{
	Byte regs;
	Byte regd;
	Byte size;
	Byte memex;
	Byte scale;
	LongInt disp;
	tSymbolFlags flags;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;
	if (!CheckFloat()) return;

	if ((OpTabITOF[Index].flags & 0x10) && !CheckV2()) return;

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		size = 0x03;
		disp = 0;
		memex = 0;
    scale = 0;
	}
	else if (DecodeIndirectADD(&ArgStr[1], &regs, &disp, &flags, &memex, &scale))
	{
		if (mFirstPassUnknown(flags)) size = 0x02;
		else size = DispSize(disp, flags, scale);
	}
	else
	{
		WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);	
		return;
	}

	if (memex == 0x80 || size == 0x03)
	{
		BAsmCode[0] = 0xFC;
		BAsmCode[1] = OpTabITOF[Index].Opc1 | size;
		BAsmCode[2] = (regs << 4) | regd;
		if (size < 0x03) CodeLen = DispOut(3, size, disp, scale);
		else CodeLen = 3;
		return;
	}

	BAsmCode[0] = 0x06;
	BAsmCode[1] = 0x20 | (memex << 6) | size;
	BAsmCode[2] = OpTabITOF[Index].Opc2;
	BAsmCode[3] = (regs << 4) | regd;
	CodeLen = DispOut(4, size, disp, scale);
}

static const struct {
	Byte Opc1;
	Byte Opc2;
} OpTabJMP[] = {
	{ 0x7F, 0x00 },	/* JMP */
	{ 0x7F, 0x10 },	/* JSR */
	{ 0x7E, 0xB0 },	/* POP */
	{ 0x7E, 0x50 },	/* ROLC */
	{ 0x7E, 0x40 },	/* RORC */
	{ 0x7E, 0x30 },	/* SAT */
};

static void DecodeJMP(Word Index)
{
	Byte reg;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	if (DecodeReg(&ArgStr[1], &reg, eRn))
	{
		BAsmCode[0] = OpTabJMP[Index].Opc1;
		BAsmCode[1] = OpTabJMP[Index].Opc2 | reg;
		CodeLen = 2;
		return;
	}
	
	WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);	
}

static const struct {
	Byte Opc;
	Byte flags;
} OpTabMACHI[] = {
	{ 0x04, 0x01 },	/* MACHI */
	{ 0x05, 0x01 },	/* MACLO */
	{ 0x00, 0x01 },	/* MULHI */
	{ 0x01, 0x01 },	/* MULLO */
	{ 0x67, 0x00 },	/* REVL */
	
	{ 0x65, 0x00 },	/* REVW */
	{ 0x07, 0x11 },	/* EMACA */
	{ 0x47, 0x11 },	/* EMSBA */
	{ 0x03, 0x11 },	/* EMULA */
	{ 0x06, 0x11 },	/* MACLH */

	{ 0x44, 0x11 },	/* MSBHI */
	{ 0x46, 0x11 },	/* MSBLH */
	{ 0x45, 0x11 },	/* MSBLO */
	{ 0x02, 0x11 },	/* MULLH */
};

static void DecodeMACHI(Word Index)
{
	Byte reg1;
	Byte reg2;
	Byte acc = 0;

	if ((OpTabMACHI[Index].flags & 0x10) && !CheckV2()) return;
	if (!ChkNoAttr()) return;
	if (pCurrCPUProps->InstSet == eRXv1)
	{
		if (!ChkArgCnt(2,2)) return;
	}
	else
	{
		if (OpTabMACHI[Index].flags & 0x01)
		{
			if (!ChkArgCnt(3,3)) return;
			if (!DecodeAcc(&ArgStr[3], &acc))
			{
				WrStrErrorPos(ErrNum_InvArg, &ArgStr[3]);
				return;
			}
		}
		else
		{
			if (!ChkArgCnt(2,2)) return;
		}
	}

	if (!DecodeReg(&ArgStr[1], &reg1, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
		return;
	}

	if (!DecodeReg(&ArgStr[2], &reg2, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = OpTabMACHI[Index].Opc | (acc << 3);
	BAsmCode[2] = (reg1 << 4) | reg2;
	CodeLen = 3;
}

static void DecodeMOV(Word Index)
{
	tSymbolSize size;
	Byte regs;
	Byte regd;
	LongInt imm;
	LongInt disp;
	tSymbolFlags flags;
	tSymbolFlags flags2;
	Byte disp2;
	Byte isize;
	Byte dsize;
	Byte scale;
	Byte regi;

	UNUSED(Index);

	size = DecodeAttrSize();
	if (size == eSymbolSizeUnknown) return;
	scale = Size2Scale(size);
	
	if (DecodeReg(&ArgStr[1], &regs, eRn) && regs < 8 &&
		DecodeRelative(&ArgStr[2], &regd, &disp, &flags))
	{	/* (1) */
		if (ChkDisp5(size, disp, flags))
		{
			disp2 = DispSize5(size, disp);
			
			BAsmCode[0] = 0x80 | (size << 4) | ((disp2 >> 2) & 0x07);
			BAsmCode[1] = ((disp2 << 6) & 0x80) | (regd << 4) | ((disp2 << 3) & 0x08) | regs;
			CodeLen = 2;
			return;
		}
	}

	if (DecodeRelative(&ArgStr[1], &regs, &disp, &flags) &&
		DecodeReg(&ArgStr[2], &regd, eRn) && regd < 8)
	{	/* (2) */
		if (ChkDisp5(size, disp, flags))
		{
			disp2 = DispSize5(size, disp);
			
			BAsmCode[0] = 0x88 | (size << 4) | ((disp2 >> 2) & 0x07);
			BAsmCode[1] = ((disp2 << 6) & 0x80) | (regs << 4) | ((disp2 << 3) & 0x08) | regd;
			CodeLen = 2;
			return;
		}
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (size == 0x02 && DecodeReg(&ArgStr[2], &regd, eRn) &&
			!mFirstPassUnknown(flags) && imm >= 0 && imm < 16)
		{	/* (3) */
			BAsmCode[0] = 0x66;
			BAsmCode[1] = (imm << 4) | regd;
			CodeLen = 2;
			return;
		}

		if (DecodeRelative(&ArgStr[2], &regd, &disp, &flags))
		{	/* (4) */
			if ((size == 0x00 && imm >= -128 && imm < 256) ||
				(size != 0x00 && imm >= 0 && imm < 256))
			{
				disp2 = DispSize5(size, disp);

				BAsmCode[0] = 0x3C | size;
				BAsmCode[1] = ((disp2 << 3) & 0x80) | (regd << 4) | (disp2 & 0x0F);
				BAsmCode[2] = imm;
				CodeLen = 3;
				return;
			}
		}

		if (DecodeReg(&ArgStr[2], &regd, eRn))
		{
			if (size == 0x02 && !mFirstPassUnknown(flags) &&
				imm >= 0 && imm < 256)
			{	/* (5) */
				BAsmCode[0] = 0x75;
				BAsmCode[1] = 0x40 | regd;
				BAsmCode[2] = imm;
				CodeLen = 3;
				return;
			}

			/* (6) */
			isize = ImmSize32(imm, flags);

			BAsmCode[0] = 0xFB;
			BAsmCode[1] = (regd << 4) | (isize << 2) | 0x02;

			CodeLen = ImmOut(2, isize, imm);
			return;
		}

		if (DecodeIndirectADC(&ArgStr[2], &regd, &disp, &flags2))
		{	/* (8) */
			switch (size)
			{
				case 0x00:	/* B */
					if (imm < -128 || imm > 255)
					{
						WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
						return;
					}
					isize = 0x01;
					break;
				case 0x01:	/* W */
					if (imm < -32768 || imm > 65535)
					{
						WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
						return;
					}
					isize = ImmSize16(imm, flags);
					break;
				case 0x02:	/* L */
					isize = ImmSize32(imm, flags);
					break;
				default:
					WrError(ErrNum_InternalError);
					return;
			}

			dsize = DispSize(disp, flags2, scale);

			BAsmCode[0] = 0xF8 | dsize;
			BAsmCode[1] = (regd << 4) | (isize << 2) | size;
			CodeLen = DispOut(2, dsize, disp, scale);
			CodeLen = ImmOut(CodeLen, isize, imm);
			return;
		}

		WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);			
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		if (DecodeReg(&ArgStr[2], &regd, eRn))
		{	/* (7) */
			BAsmCode[0] = 0xCF | (size << 4);
			BAsmCode[1] = (regs << 4) | regd;
			CodeLen = 2;
			return;
		}

		if (DecodeIndirectADC(&ArgStr[2], &regd, &disp, &flags))
		{	/* (11) */
			dsize = DispSize(disp, flags, scale);

			BAsmCode[0] = 0xC3 | (size << 4) | (dsize << 2);
			BAsmCode[1] = (regd << 4) | regs;
			CodeLen = DispOut(2, dsize, disp, scale);
			return;
		}

		if (DecodeIndexed(&ArgStr[2], &regi, &regd))
		{	/* (12) */
			BAsmCode[0] = 0xFE;
			BAsmCode[1] = (size << 4) | regi;
			BAsmCode[2] = (regd << 4) | regs;
			CodeLen = 3;
			return;
		}

		if (DecodeIncDec(&ArgStr[2], &regd, &regi))
		{	/* (14) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x20 | (regi << 2) | size;
			BAsmCode[2] = (regd << 4) | regs;
			CodeLen = 3;
			return;
		}
	}

	if (DecodeIndirectADC(&ArgStr[1], &regs, &disp, &flags))
	{
		if (DecodeReg(&ArgStr[2], &regd, eRn))
		{	/* (9) */
			dsize = DispSize(disp, flags, scale);

			BAsmCode[0] = 0xCC | (size << 4) | dsize;
			BAsmCode[1] = (regs << 4) | regd;
			CodeLen = DispOut(2, dsize, disp, scale);
			return;
		}

		if (DecodeIndirectADC(&ArgStr[2], &regd, &imm, &flags2))
		{	/* (13) */
			dsize = DispSize(disp, flags, scale);	/* src */
			isize = DispSize(imm, flags2, scale);	/* dst */

			BAsmCode[0] = 0xC0 | (size << 4) | (isize << 2) | dsize;
			BAsmCode[1] = (regs << 4) | regd;
			CodeLen = DispOut(2, dsize, disp, scale);
			CodeLen = DispOut(CodeLen, isize, imm, scale);
			return;
		}
	}

	if (DecodeIndexed(&ArgStr[1], &regi, &regs) &&
		DecodeReg(&ArgStr[2], &regd, eRn))
	{	/* (10) */
		BAsmCode[0] = 0xFE;
		BAsmCode[1] = 0x40 | (size << 4) | regi;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
		return;
	}

	if (DecodeIncDec(&ArgStr[1], &regs, &regi) &&
		DecodeReg(&ArgStr[2], &regd, eRn))
	{
		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x28 | (regi << 2) | size;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);	
}

static void DecodeMOVU(Word Index)
{
	tSymbolSize size;
	Byte regs;
	Byte regd;
	Byte scale;
	LongInt disp;
	tSymbolFlags flags;
	Byte disp2;
	Byte dsize;
	Byte regi;

	UNUSED(Index);

	size = DecodeAttrSize();
	if (size == eSymbolSizeUnknown || size == eSymbolSize32Bit) return;
	scale = Size2Scale(size);

	if (DecodeReg(&ArgStr[2], &regd, eRn))
	{
		if (DecodeRelative(&ArgStr[1], &regs, &disp, &flags) &&
			ChkDisp5(size, disp, flags) && regd < 8)
		{	/* (1) */
			disp2 = DispSize5(size, disp);

			BAsmCode[0] = 0xB0 | (size << 3) | ((disp2 >> 2) & 0x07);
			BAsmCode[1] = ((disp2 << 6) & 0x80) | (regs << 4) | ((disp2 << 3) & 0x08) | regd;
			CodeLen = 2;
			return;
		}

		if (DecodeReg(&ArgStr[1], &regs, eRn))
		{	/* (2)-1 */
			BAsmCode[0] = 0x5B | (size << 2);
			BAsmCode[1] = (regs << 4) | regd;
			CodeLen = 2;
			return;
		}

		if (DecodeIndirectADC(&ArgStr[1], &regs, &disp, &flags))
		{	/* (2)-2 */
			dsize = DispSize(disp, flags, scale);

			BAsmCode[0] = 0x58 | (size << 2) | dsize;
			BAsmCode[1] = (regs << 4) | regd;
			CodeLen = DispOut(2, dsize, disp, scale);
			return;
		}

		if (DecodeIndexed(&ArgStr[1], &regi, &regs))
		{	/* (3) */
			BAsmCode[0] = 0xFE;
			BAsmCode[1] = 0xC0 | (size << 4) | regi;
			BAsmCode[2] = (regs << 4) | regd;
			CodeLen = 3;
			return;
		}

		if (DecodeIncDec(&ArgStr[1], &regs, &regi))
		{	/* (4) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x38 | (regi << 2) | size;
			BAsmCode[2] = (regs << 4) | regd;
			CodeLen = 3;
			return;
		}
	}

	WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);	
}

static const struct {
	Byte Opc2;
	Byte Opc3;
	Byte flags;
} OpTabMVFACHI[] = {
	{ 0x1E, 0x00, 0x00 },	/* MVFACHI */
	{ 0x1E, 0x20, 0x00 },	/* MVFACMI */
	{ 0x1E, 0x30, 0x10 },	/* MVFACGU */
	{ 0x1E, 0x10, 0x10 },	/* MVFACLO */
};

static void DecodeMVFACHI(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;
	Byte acc;
	Byte reg;
	
	if ((OpTabMVFACHI[Index].flags & 0x10) && !CheckV2()) return;
	if (!ChkNoAttr()) return;

	if (pCurrCPUProps->InstSet == eRXv1)
	{
		if (!ChkArgCnt(1,1)) return;
		imm = 0x02;
		acc = 0x00;
	}
	else
	{
		if (!ChkArgCnt(3,3)) return;
		if (!DecodeImm(&ArgStr[1], &imm, &flags))
		{
			WrStrErrorPos(ErrNum_OnlyImmAddr, &ArgStr[1]);	
			return;
		}
		switch (imm)
		{
		case 0:
			imm = 0x02;
			break;
		case 1:
			imm = 0x03;
			break;
		case 2:
			imm = 0x00;
			break;
		default:
			if (mSymbolQuestionable(flags)) break;
			WrStrErrorPos(ErrNum_ArgOutOfRange, &ArgStr[1]);
			return;
		}

		if (!DecodeAcc(&ArgStr[2], &acc))
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
			return;
		}
	}
	
	if (!DecodeReg(&ArgStr[ArgCnt], &reg, eRn))
	{
		WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[ArgCnt]);	
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = OpTabMVFACHI[Index].Opc2 | ((imm >> 1) & 0x01);
	BAsmCode[2] = OpTabMVFACHI[Index].Opc3 | (acc << 7) | ((imm << 6) & 0x40) | reg;
	CodeLen = 3;
}

static const char *SPReg[] = {
	"PSW",   "PC",    "USP",   "FPSW",   NULL,    NULL,    NULL,    NULL,
	"BPSW",  "BPC",   "ISP",   "FINTV",  "INTB",  "EXTB",  NULL,    NULL,
};

static void DecodeMVFC(Word Index)
{
	Byte reg;
	size_t i;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (DecodeReg(&ArgStr[2], &reg, eRn))
	{
		for (i = 0; i < as_array_size(SPReg); i++)
		{
			if (i == 13 && pCurrCPUProps->InstSet == eRXv1)
			{
				WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[2]);
			}

			if (SPReg[i] && !as_strcasecmp(SPReg[i], ArgStr[1].str.p_str))
			{
				BAsmCode[0] = 0xFD;
				BAsmCode[1] = 0x6A;
				BAsmCode[2] = (i << 4) | reg;
				CodeLen = 3;
				return;
			}
		}
		
		WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[1]);
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);			
}

static const struct {
	Byte Opc2;
	Byte Opc3;
	Byte flags;
} OpTabMVTACHI[] = {
	{ 0x17, 0x00, 0x00 },	/* MVTACHI */
	{ 0x17, 0x10, 0x00 },	/* MVTACLO */
	{ 0x17, 0x30, 0x10 },	/* MVTACGU */
};

static void DecodeMVTACHI(Word Index)
{
	Byte acc;
	Byte reg;
	
	if ((OpTabMVTACHI[Index].flags & 0x10) && !CheckV2()) return;
	if (!ChkNoAttr()) return;

	if (pCurrCPUProps->InstSet == eRXv1)
	{
		if (!ChkArgCnt(1,1)) return;
		acc = 0x00;
	}
	else
	{
		if (!ChkArgCnt(2,2)) return;

		if (!DecodeAcc(&ArgStr[2], &acc))
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
			return;
		}
	}
	
	if (!DecodeReg(&ArgStr[1], &reg, eRn))
	{
		WrStrErrorPos(ErrNum_AddrModeNotSupported, &ArgStr[1]);
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = OpTabMVTACHI[Index].Opc2;
	BAsmCode[2] = OpTabMVTACHI[Index].Opc3 | (acc << 7) | reg;
	CodeLen = 3;
}

static void DecodeMVTC(Word Index)
{
	Byte reg;
	LongInt imm;
	Byte size;
	tSymbolFlags flags;
	size_t i;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	for (i = 0; i < as_array_size(SPReg); i++)
	{
		if (SPReg[i] && !as_strcasecmp(SPReg[i], ArgStr[2].str.p_str))
		{
			if (i == 1)
			{
				WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[2]);
				return;
			}

			if (i == 13 && pCurrCPUProps->InstSet == eRXv1)
			{
				WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[2]);
			}

			if (DecodeImm(&ArgStr[1], &imm, &flags))
			{
				size = ImmSize32(imm, flags);

				BAsmCode[0] = 0xFD;
				BAsmCode[1] = 0x73 | (size << 2);
				BAsmCode[2] = i;
				CodeLen = ImmOut(3, size, imm);
				return;
			}

			if (DecodeReg(&ArgStr[1], &reg, eRn))
			{
				BAsmCode[0] = 0xFD;
				BAsmCode[1] = 0x68;
				BAsmCode[2] = (reg << 4) | i;
				CodeLen = 3;
				return;
			}
		
			WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[1]);
		}
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);			
}

static void DecodeMVTIPL(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;

	UNUSED(Index);

	if (!CheckSup()) return;
	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	if (!pCurrCPUProps->hasMVTIPL)
	{
		WrError(ErrNum_InstructionNotSupported);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (!mFirstPassUnknown(flags) && (imm < 0 || imm > 15))
		{
			WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
			return;
		}

		BAsmCode[0] = 0x75;
		BAsmCode[1] = 0x70;
		BAsmCode[2] = imm;
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);			
}

static const Byte OpTabPOPC[] = {
	0xE0,	/* POPC */
	0xC0,	/* PUSHC */
};

static void DecodePOPC(Word Index)
{
	size_t i;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	for (i = 0; i < as_array_size(SPReg); i++)
	{
		if (SPReg[i] && !as_strcasecmp(SPReg[i], ArgStr[1].str.p_str))
		{
			if (Index == 0 && i == 1)
			{
				WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[1]);
				return;
			}

			if (i == 13 && pCurrCPUProps->InstSet == eRXv1)
			{
				WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[2]);
			}

			BAsmCode[0] = 0x7E;
			BAsmCode[1] = OpTabPOPC[Index] | i;
			CodeLen = 2;
			return;
		}
	}

	WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[1]);
}

static const Byte OpTabPOPM[] = {
	0x6F,	/* POPM */
	0x6E,	/* PUSHM */
};

static void DecodePOPM(Word Index)
{
	Byte range;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	if (DecodeRegRange(&ArgStr[1], &range))
	{
		BAsmCode[0] = OpTabPOPM[Index];
		BAsmCode[1] = range;
		CodeLen = 2;
		return;
	}

	WrStrErrorPos(ErrNum_InvRegList, &ArgStr[1]);
}

static void DecodePUSH(Word Index)
{
	tSymbolSize size;
	Byte reg;
	LongInt disp;
	tSymbolFlags flags;
	Byte dsize;
	Byte scale;

	UNUSED(Index);

	size = DecodeAttrSize();
	if (size == eSymbolSizeUnknown) return;
	if (!ChkArgCnt(1,1)) return;

	scale = Size2Scale(size);

	if (DecodeReg(&ArgStr[1], &reg, eRn))
	{
		BAsmCode[0] = 0x7E;
		BAsmCode[1] = 0x80 | (size << 4) | reg;
		CodeLen = 2;
		return;
	}

	if (DecodeIndirectADC(&ArgStr[1], &reg, &disp, &flags))
	{
		dsize = DispSize(disp, flags, scale);

		BAsmCode[0] = 0xF4 | dsize;
		BAsmCode[1] = 0x08 | (reg << 4) | size;
		CodeLen = DispOut(2, dsize, disp, scale);
		return;
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}

static const struct {
	Byte Opc2;
	Byte Opc3;
	Byte flags;
} OpTabRACW[] = {
	{ 0x18, 0x00, 0x00 },	/* RACW */
	{ 0x19, 0x00, 0x10 },	/* RACL */
	{ 0x19, 0x40, 0x10 },	/* RDACL */
	{ 0x18, 0x40, 0x10 },	/* RDACW */
};

static void DecodeRACW(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;
	Byte acc = 0;

	if ((OpTabRACW[Index].flags & 0x10) && !CheckV2()) return;
	if (!ChkNoAttr()) return;

	if (pCurrCPUProps->InstSet == eRXv1)
	{
		if (!ChkArgCnt(1,1)) return;
	}
	else
	{
		if (!ChkArgCnt(2,2)) return;

		if (!DecodeAcc(&ArgStr[2], &acc))
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
			return;
		}
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (mFirstPassUnknown(flags) || imm == 1 || imm == 2)
		{
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = OpTabRACW[Index].Opc2;
			BAsmCode[2] = OpTabRACW[Index].Opc3 | (acc << 7) | ((imm - 1) << 4);
			CodeLen = 3;
			return;
		}
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}

static void DecodeRMPA(Word Index)
{
	tSymbolSize size;

	size = DecodeAttrSize();
	if (size == eSymbolSizeUnknown) return;
	if (!ChkArgCnt(0,0)) return;

	BAsmCode[0] = 0x7F;
	BAsmCode[1] = Index | size;
	CodeLen = 2;
}

static const struct {
	Byte Opc1;
	Byte Opc2;
} OpTabROTL[] = {
	{ 0x6E, 0x66 },	/* ROTL */
	{ 0x6C, 0x64 },	/* ROTR */
};

static void DecodeROTL(Word Index)
{
	Byte regs;
	Byte regd;
	LongInt imm;
	tSymbolFlags flags;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (!mFirstPassUnknown(flags) && (imm < 0 || imm > 31))
		{
			WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
			return;
		}

		BAsmCode[0] = 0xFD;
		BAsmCode[1] = OpTabROTL[Index].Opc1 | ((imm >> 4) & 0x01);
		BAsmCode[2] = ((imm << 4) & 0xF0) | regd;
		CodeLen = 3;
		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		BAsmCode[0] = 0xFD;
		BAsmCode[1] = OpTabROTL[Index].Opc2;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
}

static void DecodeRTE(Word Index)
{
	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(0,0)) return;

	switch (Index)
	{
	case 0x7F95:	/* RTE */
	case 0x7F94:	/* RTFI */
	case 0x7F96:	/* WAIT */
		if (!CheckSup()) return;
	}

	BAsmCode[0] = Index >> 8;
	BAsmCode[1] = Index;
	CodeLen = 2;
}

static void DecodeRTSD(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;
	Byte range;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,2)) return;

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (mSymbolQuestionable(flags) && (imm < 0 || imm > 255))
		{
			WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
			return;
		}

		if (ArgCnt == 2 && DecodeRegRange(&ArgStr[2], &range))
		{
			BAsmCode[0] = 0x3F;
			BAsmCode[1] = range;
			BAsmCode[2] = imm;
			CodeLen = 3;
			return;
		}

		if (ArgCnt > 1)
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
			return;
		}

		BAsmCode[0] = 0x67;
		BAsmCode[1] = imm;
		CodeLen = 2;
		return;
	}

	WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
}

static void DecodeSCCnd(Word Index)
{
	tSymbolSize size;
	Byte reg;
	LongInt disp;
	tSymbolFlags flags;
	Byte dsize;
	Byte scale;

	size = DecodeAttrSize();
	if (size == eSymbolSizeUnknown) return;
	if (!ChkArgCnt(1,1)) return;

	scale = Size2Scale(size);

	if (DecodeReg(&ArgStr[1], &reg, eRn))
	{
		if (size != 0x02)
		{
			WrStrErrorPos(ErrNum_InvOpSize, &ArgStr[1]);
			return;
		}

		BAsmCode[0] = 0xFC;
		BAsmCode[1] = 0xD3 | (size << 2);
		BAsmCode[2] = (reg << 4) | Index;
		CodeLen = 3;
		return;
	}

	if (DecodeIndirectADC(&ArgStr[1], &reg, &disp, &flags))
	{
		dsize = DispSize(disp, flags, scale);

		BAsmCode[0] = 0xFC;
		BAsmCode[1] = 0xD0 | (size << 2) | dsize;
		BAsmCode[2] = (reg << 4) | Index;
		CodeLen = DispOut(3, dsize, disp, scale);
		return;
	}

	WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
}

static const struct {
	Byte Opc1;
	Byte Opc2;
	Byte Opc3;
} OpTabSHAR[] = {
	{ 0x6A, 0x61, 0xA0 },	/* SHAR */
	{ 0x6C, 0x62, 0xC0 },	/* SHLL */
	{ 0x68, 0x60, 0x80 },	/* SHLR */
};

static void DecodeSHAR(Word Index)
{
	Byte regs;
	Byte regd;
	LongInt imm;
	tSymbolFlags flags;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,3)) return;

	if (!DecodeReg(&ArgStr[ArgCnt], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (!mFirstPassUnknown(flags) && (imm < 0 || imm > 31))
		{
			WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
			return;
		}

		if (ArgCnt == 3)
		{
			if (DecodeReg(&ArgStr[2], &regs, eRn))
			{	/* (3) */
				BAsmCode[0] = 0xFD;
				BAsmCode[1] = OpTabSHAR[Index].Opc3 | imm;
				BAsmCode[2] = (regs << 4) | regd;
				CodeLen = 3;
				return;
			}

			WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
			return;
		}

		/* (1) */
		BAsmCode[0] = OpTabSHAR[Index].Opc1 | (imm >> 4);
		BAsmCode[1] = ((imm << 4) & 0xF0) | regd;
		CodeLen = 2;
		return;
	}

	if (ArgCnt > 2)
	{
		WrStrErrorPos(ErrNum_TooManyArgs, &ArgStr[2]);
		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{	/* (2) */
		BAsmCode[0] = 0xFD;
		BAsmCode[1] = OpTabSHAR[Index].Opc2;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
}

static const struct {
	Byte OpcIR;
	Byte OpcRR;
} OpTabSTNZ[] = {
	{ 0xF0, 0x4F },	/* STNZ */
	{ 0xE0, 0x4B },	/* STZ */
};

static void DecodeSTNZ(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;
	Byte regd;
	Byte regs;
	Byte size;
	
	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		size = ImmSize32(imm, flags);

		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x70 | (size << 2);
		BAsmCode[2] = OpTabSTNZ[Index].OpcIR | regd;
		CodeLen = ImmOut(3, size, imm);
		return;
	}

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		if (!CheckV2()) return;

		BAsmCode[0] = 0xFC;
		BAsmCode[1] = OpTabSTNZ[Index].OpcRR;
		BAsmCode[2] = (regs << 4) | regd;
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
}

static const struct {
	Byte Opc1;
	Byte Opc2;
	Byte Opc3;
	Byte flags;
} OpTabTST[] = {
	{ 0xC0, 0x30, 0x0C, 0x01 },	/* TST */
	{ 0,    0x40, 0x10, 0x00 },	/* XCHG */
	{ 0xD0, 0x34, 0x0D, 0x03 },	/* XOR */
};

static void DecodeTST(Word Index)
{
	Byte reg1;
	Byte reg2;
	LongInt imm;
	LongInt disp;
	tSymbolFlags flags;
	Byte size;
	Byte memex;
	Byte scale;

	if (!ChkNoAttr()) return;
	if ((OpTabTST[Index].flags & 0x02) && ArgCnt == 3)
	{
		Byte reg3;

		if (!CheckV3()) return;

		if (!DecodeReg(&ArgStr[1], &reg1, eRn))
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
			return;		
		}

		if (!DecodeReg(&ArgStr[2], &reg2, eRn))
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
			return;		
		}

		if (!DecodeReg(&ArgStr[3], &reg3, eRn))
		{
			WrStrErrorPos(ErrNum_InvArg, &ArgStr[3]);
			return;		
		}

		BAsmCode[0] = 0xFF;
		BAsmCode[1] = 0x60 | reg3;
		BAsmCode[2] = (reg1 << 4) | reg2;
		CodeLen = 3;
		return;
	}
		
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeReg(&ArgStr[2], &reg2, eRn))
	{
		WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
		return;		
	}

	if ((OpTabTST[Index].flags & 0x01) &&
		DecodeImm(&ArgStr[1], &imm, &flags))
	{
		size = ImmSize32(imm, flags);

		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x70 | (size << 2);
		BAsmCode[2] = OpTabTST[Index].Opc1 | reg2;
		CodeLen = ImmOut(3, size, imm);
		return;
	}

	if (DecodeReg(&ArgStr[1], &reg1, eRn))
	{
		BAsmCode[0] = 0xFC;
		BAsmCode[1] = OpTabTST[Index].Opc2 | 0x03;
		BAsmCode[2] = (reg1 << 4) | reg2;
		CodeLen = 3;
		return;
	}

	if (DecodeIndirectADD(&ArgStr[1], &reg1, &disp, &flags, &memex, &scale))
	{
		if (memex == 0x80)
		{
			size = DispSize(disp, flags, 1);
			
			BAsmCode[0] = 0xFC;
			BAsmCode[1] = OpTabTST[Index].Opc2 | size;
			BAsmCode[2] = (reg1 << 4) | reg2;
			CodeLen = DispOut(3, size, disp, 1);
			return;
		}

		size = DispSize(disp, flags, scale);

		BAsmCode[0] = 0x06;
		BAsmCode[1] = 0x20 | (memex << 6) | size;
		BAsmCode[2] = OpTabTST[Index].Opc3;
		BAsmCode[3] = (reg1 << 4) | reg2;
		CodeLen = DispOut(4, size, disp, scale);
		return;
	}
			
}

static void DecodeMOVCO(Word Index)
{
	Byte regs;
	Byte regd;

	UNUSED(Index);

	if (!CheckV2()) return;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeReg(&ArgStr[1], &regs, eRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
		return;
	}

	if (!DecodeIndirect(&ArgStr[2], &regd))
	{
		WrStrErrorPos(ErrNum_InvArg, &ArgStr[2]);
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = 0x27;
	BAsmCode[2] = (regd << 4) | regs;
	CodeLen = 3;
}

static void DecodeMOVLI(Word Index)
{
	Byte regs;
	Byte regd;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;

	if (!DecodeIndirect(&ArgStr[1], &regs))
	{
		WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
		return;
	}

	if (!DecodeReg(&ArgStr[2], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[2]);
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = 0x2F;
	BAsmCode[2] = (regs << 4) | regd;
	CodeLen = 3;
}

static const Byte OpTabBFMOV[] = {
	0x5E,	/* BFMOV */
	0x5A,	/* BFMOVZ */
};

static void DecodeBFMOV(Word Index)
{
	LongInt slsb;
	LongInt dlsb;
	LongInt width;
	tSymbolFlags flags;
	Byte regs;
	Byte regd;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(5,5)) return;
	if (!CheckV3()) return;

	if (!DecodeImm(&ArgStr[1], &slsb, &flags))
	{
		WrStrErrorPos(ErrNum_ExpectInt, &ArgStr[1]);
		return;
	}
	if (!mFirstPassUnknownOrQuestionable(flags) && !ChkRange(slsb, 0, 31)) return;

	if (!DecodeImm(&ArgStr[2], &dlsb, &flags))
	{
		WrStrErrorPos(ErrNum_ExpectInt, &ArgStr[2]);
		return;
	}
	if (!mFirstPassUnknownOrQuestionable(flags) && !ChkRange(dlsb, 0, 31)) return;

	if (!DecodeImm(&ArgStr[3], &width, &flags))
	{
		WrStrErrorPos(ErrNum_ExpectInt, &ArgStr[3]);
		return;
	}
	if (!mFirstPassUnknownOrQuestionable(flags) && !ChkRange(width, 1, 31)) return;

	if (!DecodeReg(&ArgStr[4], &regs, eRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[4]);
		return;
	}

	if (!DecodeReg(&ArgStr[5], &regd, eRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[5]);
		return;
	}

	if (slsb + width > 32 || dlsb + width > 32)
	{
		WrError(ErrNum_OverRange);
		return;
	}

	BAsmCode[0] = 0xFC;
	BAsmCode[1] = OpTabBFMOV[Index];
	BAsmCode[2] = (regs << 4) | regd;
	BAsmCode[3] = ((dlsb - slsb) & 0x1f) | ((dlsb << 5) & 0xE0);
	BAsmCode[4] = ((dlsb >> 3) & 0x03) | (((dlsb + width) << 2) & 0x7C);
	CodeLen = 5;
}

static const struct {
	Byte OpcI;
	Byte OpcR;
} OpTabRSTR[] = {
	{ 0xF0, 0xD0 },	/* RSTR */
	{ 0xE0, 0xC0 },	/* SAVE */
};

static void DecodeRSTR(Word Index)
{
	LongInt imm;
	tSymbolFlags flags;
	Byte reg;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;
	if (!CheckV3()) return;

	if (!pCurrCPUProps->RegBank)
	{
		WrError(ErrNum_InstructionNotSupported);
		return;
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (!ChkRange(imm, 0, pCurrCPUProps->RegBank - 1)) return;

		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x76;
		BAsmCode[2] = OpTabRSTR[Index].OpcI;
		BAsmCode[3] = imm;
		CodeLen = 4;
		return;
	}

	if (DecodeReg(&ArgStr[1], &reg, eRn))
	{
		BAsmCode[0] = 0xFD;
		BAsmCode[1] = 0x76;
		BAsmCode[2] = OpTabRSTR[Index].OpcR | reg;
		BAsmCode[3] = 0x00;
		CodeLen = 4;
		return;
	}

	WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
}

static const struct {
	Byte Opc1;
	Byte Opc2;
} OpTabDABS[] = {
	{ 0x0C, 0x01 },	/* DABS */
	{ 0x0C, 0x02 },	/* DNEG */
	{ 0x0D, 0x0D },	/* DROUND */
	{ 0x0D, 0x00 },	/* DSQRT */
	{ 0x0D, 0x0C },	/* DTOF */
	{ 0x0D, 0x08 },	/* DTOI */
	{ 0x0D, 0x09 },	/* DTOU */
};

static void DecodeDABS(Word Index)
{
	Byte regs;
	Byte regd;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	if (!DecodeReg(&ArgStr[1], &regs, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
		return;
	}

	if (!DecodeReg(&ArgStr[2], &regd, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[2]);
		return;
	}

	BAsmCode[0] = 0x76;
	BAsmCode[1] = 0x90;
	BAsmCode[2] = OpTabDABS[Index].Opc1 | (regs << 4);
	BAsmCode[3] = OpTabDABS[Index].Opc2 | (regd << 4);
	CodeLen = 4;
}

static const struct {
	Byte Opc;
} OpTabDADD[] = {
	{ 0x00 },	/* DADD */
	{ 0x05 },	/* DDIV */
	{ 0x02 },	/* DMUL */
	{ 0x01 },	/* DSUB */
};

static void DecodeDADD(Word Index)
{
	Byte regs1;
	Byte regs2;
	Byte regd;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(3,3)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	if (!DecodeReg(&ArgStr[1], &regs1, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
		return;
	}

	if (!DecodeReg(&ArgStr[2], &regs2, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[2]);
		return;
	}

	if (!DecodeReg(&ArgStr[3], &regd, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[3]);
		return;
	}

	BAsmCode[0] = 0x76;
	BAsmCode[1] = 0x90;
	BAsmCode[2] = OpTabDADD[Index].Opc | (regs2 << 4);
	BAsmCode[3] = (regd << 4) | regs1;
	CodeLen = 4;
}

static void DecodeDCMPcm(Word Index)
{
	Byte regs1;
	Byte regs2;

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	if (!DecodeReg(&ArgStr[1], &regs1, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
		return;
	}

	if (!DecodeReg(&ArgStr[2], &regs2, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[2]);
		return;
	}

	BAsmCode[0] = 0x76;
	BAsmCode[1] = 0x90;
	BAsmCode[2] = 0x08 | (regs2 << 4);
	BAsmCode[3] = ((Index << 4) & 0xF0) | regs1;
	CodeLen = 4;
}

static void DecodeDMOV(Word Index)
{
	Byte size;
	Byte regs;
	Byte regd;
	LongInt disp;
	LongInt imm;
	tSymbolFlags flags;
	Byte dsize;

	UNUSED(Index);

	if (!ChkArgCnt(2,2)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	if (!DecodeAttrDouble(&size)) return;

	if (DecodeReg(&ArgStr[1], &regs, eRn))
	{
		if (DecodeReg(&ArgStr[2], &regd, eDRHn))
		{	/* (1) / (2) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x77;
			BAsmCode[2] = 0x80 | regs;
			BAsmCode[3] = 0x02 | (regd << 4) | size;
			CodeLen = 4;
			return;
		}

		if (DecodeReg(&ArgStr[2], &regd, eDRLn) && !size)
		{	/* (3) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x77;
			BAsmCode[2] = 0x80 | regs;
			BAsmCode[3] = 0x00 | (regd << 4);
			CodeLen = 4;
			return;
		}
	}

	if (DecodeReg(&ArgStr[2], &regd, eRn))
	{
		if (DecodeReg(&ArgStr[1], &regs, eDRHn) && !size)
		{	/* (4) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x75;
			BAsmCode[2] = 0x80 | regd;
			BAsmCode[3] = 0x02 | (regs << 4);
			CodeLen = 4;
			return;
		}

		if (DecodeReg(&ArgStr[1], &regs, eDRLn) && !size)
		{	/* (5) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x75;
			BAsmCode[2] = 0x80 | regd;
			BAsmCode[3] = 0x00 | (regs << 4);
			CodeLen = 4;
			return;
		}
	}

	if (DecodeReg(&ArgStr[1], &regs, eDRn) && size)
	{
		if (DecodeReg(&ArgStr[2], &regd, eDRn))
		{	/* (6) */
			BAsmCode[0] = 0xFD;
			BAsmCode[1] = 0x90;
			BAsmCode[2] = 0x0C | (regs << 4);
			BAsmCode[3] = 0x00 | (regd << 4);
			CodeLen = 4;
			return;
		}

		if (DecodeIndirectADC(&ArgStr[2], &regd, &disp, &flags) && size)
		{	/* (7) */
			dsize = DispSize(disp, flags, 8);

			BAsmCode[0] = 0xFC;
			BAsmCode[1] = 0x78 | dsize;
			BAsmCode[2] = 0x08 | (regd << 4);
			CodeLen = DispOut(3, dsize, disp, 8);
			BAsmCode[CodeLen++] = 0x00 | (regs << 4);
			return;
		}
	}

	if (DecodeIndirectADC(&ArgStr[1], &regs, &disp, &flags) && size)
	{
		if (DecodeReg(&ArgStr[2], &regd, eDRn))
		{	/* (8) */
			dsize = DispSize(disp, flags, 8);

			BAsmCode[0] = 0xFC;
			BAsmCode[1] = 0xC8 | dsize;
			BAsmCode[2] = 0x08 | (regs << 4);
			CodeLen = DispOut(3, dsize, disp, 8);
			BAsmCode[CodeLen++] = 0x00 | (regd << 4);
			return;
		}
	}

	if (DecodeImm(&ArgStr[1], &imm, &flags))
	{
		if (DecodeReg(&ArgStr[2], &regd, eDRHn))
		{	/* (9) / (10) */
			BAsmCode[0] = 0xF9;
			BAsmCode[1] = 0x03;
			BAsmCode[2] = 0x02 | (regd << 4) | size;
			CodeLen = ImmOut(3, 0, imm);
			return;
		}

		if (DecodeReg(&ArgStr[2], &regd, eDRLn) && !size)
		{	/* (11) */
			BAsmCode[0] = 0xF9;
			BAsmCode[1] = 0x03;
			BAsmCode[2] = 0x00 | (regd << 4);
			CodeLen = ImmOut(3, 0, imm);
			return;
		}
	}

	WrError(ErrNum_InvArg);
}

static const Byte OpTabDPOPM[] = {
	0xA8,	/* DPOPM */
	0xA0	/* DPUSHM */
};

static void DecodeDPOPM(Word Index)
{
	const int len = strlen(ArgStr[1].str.p_str);
	Byte size;
	Byte reg1;
	Byte reg2;
	int i;

	if (!DecodeAttrDouble(&size)) return;
	if (!ChkArgCnt(1,1)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	for (i = 0; i < len; i++)
	{
		if (ArgStr[1].str.p_str[i] == '-') break;
	}
	if (i >= len)
	{
		WrStrErrorPos(ErrNum_InvRegList, &ArgStr[1]);
		return;
	}

	StrCompCopySub(&Temp1, &ArgStr[1], 0, i);
	if (!DecodeReg(&Temp1, &reg1, size ? eDRn : eDCRn))
	{
		WrStrErrorPos(ErrNum_InvRegList, &ArgStr[1]);
		return;
	}
		
	StrCompCopySub(&Temp1, &ArgStr[1], i + 1, len - i - 1);
	if (!DecodeReg(&Temp1, &reg2, size ? eDRn : eDCRn))
	{
		WrStrErrorPos(ErrNum_InvRegList, &ArgStr[1]);
		return;
	}

	if (reg2 >= reg1)
	{
		BAsmCode[0] = 0x75;
		BAsmCode[1] = OpTabDPOPM[Index] | (size << 4);
		BAsmCode[2] = (reg1 << 4) | (reg2 - reg1);
		CodeLen = 3;
		return;
	}

	WrStrErrorPos(ErrNum_InvRegList, &ArgStr[1]);
}

static const struct {
	Byte Opc1;
	Byte Opc2;
} OpTabFTOD[] = {
	{ 0x80, 0x0A },	/* FTOD */
	{ 0x80, 0x09 },	/* ITOD */
	{ 0x80, 0x0D },	/* UTOD */
};

static void DecodeFTOD(Word Index)
{
	Byte regs;
	Byte regd;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	if (!DecodeReg(&ArgStr[1], &regs, eRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[1]);
		return;
	}

	if (!DecodeReg(&ArgStr[2], &regd, eDRn))
	{
		WrStrErrorPos(ErrNum_ExpectReg, &ArgStr[2]);
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = 0x77;
	BAsmCode[2] = OpTabFTOD[Index].Opc1 | regs;
	BAsmCode[3] = OpTabFTOD[Index].Opc2 | (regd << 4);
	CodeLen = 4;
}

static void DecodeMVFDC(Word Index)
{
	Byte regc;
	Byte reg;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(2,2)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	if (!DecodeReg(&ArgStr[Index + 1], &regc, eDCRn))
	{
		WrStrErrorPos(ErrNum_InvCtrlReg, &ArgStr[Index + 1]);
		return;
	}
	
	if (!DecodeReg(&ArgStr[2 - Index], &reg, eRn))
	{
		WrStrErrorPos(ErrNum_InvReg, &ArgStr[2 - Index]);
		return;
	}

	BAsmCode[0] = 0xFD;
	BAsmCode[1] = 0x75 | (Index << 1);
	BAsmCode[2] = 0x80 | reg;
	BAsmCode[3] = 0x04 | (regc << 4);
	CodeLen = 4;
}

static void DecodeMVFDR(Word Index)
{
	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(0,0)) return;
	if (!CheckV3()) return;
	if (!CheckDouble()) return;

	BAsmCode[0] = 0x75;
	BAsmCode[1] = 0x90;
	BAsmCode[2] = 0x1B;
	CodeLen = 3;
}

#ifdef COMPAT

#define BigEndianSymName "BIGENDIAN" /* T.B.D. */
static void DecodeENDIAN(Word Index)
{
	const char *str;

	UNUSED(Index);

	if (!ChkNoAttr()) return;
	if (!ChkArgCnt(1,1)) return;

	str = ArgStr[1].str.p_str;
	if (!as_strcasecmp(str, "BIG"))
		SetFlag(&TargetBigEndian, BigEndianSymName, True);
	else if (!as_strcasecmp(str, "LITTLE"))
		SetFlag(&TargetBigEndian, BigEndianSymName, False);
	else
		WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
}

#endif /* COMPAT */

/*---------------------------------------------------------------------------*/

static void AddABS(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeABS);
}

static void AddADC(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeADC);
}

static void AddADD(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeADD);
}

static void AddBCLR(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeBCLR);
}

static void AddBCnd(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeBCnd);
}

static void AddBMCnd(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeBMCnd);
}

static void AddBRK(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeBRK);
}

static void AddBSR(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeBSR);
}

static void AddCLRPSW(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeCLRPSW);
}

static void AddDIV(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeDIV);
}

static void AddFADD(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeFADD);
}

static void AddINT(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeINT);
}

static void AddITOF(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeITOF);
}

static void AddJMP(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeJMP);
}

static void AddMACHI(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMACHI);
}

static void AddMOV(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMOV);
}

static void AddMOVU(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMOVU);
}

static void AddMVFACHI(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVFACHI);
}

static void AddMVFC(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVFC);
}

static void AddMVTACHI(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVTACHI);
}

static void AddMVTC(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVTC);
}

static void AddMVTIPL(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVTIPL);
}

static void AddPOPC(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodePOPC);
}

static void AddPOPM(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodePOPM);
}

static void AddPUSH(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodePUSH);
}

static void AddRACW(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeRACW);
}

static void AddRMPA(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeRMPA);
}

static void AddROTL(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeROTL);
}

static void AddRTE(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeRTE);
}

static void AddRTSD(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeRTSD);
}

static void AddSCCnd(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeSCCnd);
}

static void AddSHAR(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeSHAR);
}

static void AddSTNZ(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeSTNZ);
}

static void AddTST(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeTST);
}

static void AddMOVCO(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMOVCO);
}

static void AddMOVLI(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMOVLI);
}

static void AddBFMOV(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeBFMOV);
}

static void AddRSTR(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeRSTR);
}

static void AddDABS(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeDABS);
}

static void AddDADD(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeDADD);
}

static void AddDCMPcm(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeDCMPcm);
}

static void AddDMOV(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeDMOV);
}

static void AddDPOPM(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeDPOPM);
}

static void AddFTOD(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeFTOD);
}

static void AddMVFDC(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVFDC);
}

static void AddMVFDR(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeMVFDR);
}

#ifdef COMPAT

static void AddBLK(const char *NName, Word NCode)
{
	AddInstTable(InstTable, NName, NCode, DecodeIntelDS);
}

#endif /* COMPAT */

static Boolean TrueFnc(void)
{
  return True;
}

static void InitFields(void)
{
	InstTable = CreateInstTable(201);

  add_null_pseudo(InstTable);

	/* RXv1 */
	AddABS("ABS", 0x200F);
	AddADC("ADC", 0x0802);
	AddADD("ADD", 0);
	AddADD("AND", 1);
	AddBCLR("BCLR", 0);
	AddBCnd("BEQ",  0);
	AddBCnd("BZ",   0);
	AddBCnd("BNE",  1);
	AddBCnd("BNZ",  1);
	AddBCnd("BGEU", 2);
	AddBCnd("BC",   2);
	AddBCnd("BLTU", 3);
	AddBCnd("BNC",  3);
	AddBCnd("BGTU", 4);
	AddBCnd("BLEU", 5);
	AddBCnd("BPZ",  6);
	AddBCnd("BN",   7);
	AddBCnd("BGE",  8);
	AddBCnd("BLT",  9);
	AddBCnd("BGT",  10);
	AddBCnd("BLE",  11);
	AddBCnd("BO",   12);
	AddBCnd("BNO",  13);
	AddBMCnd("BMEQ",  0);
	AddBMCnd("BMZ", 0);
	AddBMCnd("BMNE", 1);
	AddBMCnd("BMNZ", 1);
	AddBMCnd("BMGEU", 2);
	AddBMCnd("BMC", 2);
	AddBMCnd("BMLTU", 3);
	AddBMCnd("BMNC", 3);
	AddBMCnd("BMGTU", 4);
	AddBMCnd("BMLEU", 5);
	AddBMCnd("BMPZ", 6);
	AddBMCnd("BMN", 7);
	AddBMCnd("BMGE", 8);
	AddBMCnd("BMLT", 9);
	AddBMCnd("BMGT", 10);
	AddBMCnd("BMLE", 11);
	AddBMCnd("BMO", 12);
	AddBMCnd("BMNO", 13);
	AddBCLR("BNOT", 1);
	AddBCnd("BRA", 14);
	AddBRK("BRK", 0x0000);
	AddBCLR("BSET", 2);
	AddBSR("BSR", 0);
	AddBCLR("BTST", 3);
	AddCLRPSW("CLRPSW", 0xB0);
	AddADD("CMP", 2);
	AddDIV("DIV", 0);
	AddDIV("DIVU", 1);
	AddDIV("EMUL", 2);
	AddDIV("EMULU", 3);
	AddFADD("FADD", 0);
	AddFADD("FCMP", 1);
	AddFADD("FDIV", 2);
	AddFADD("FMUL", 3);
	AddFADD("FSUB", 4);
	AddFADD("FTOI", 5);
	AddINT("INT", 0);
	AddITOF("ITOF", 0);
	AddJMP("JMP", 0);
	AddJMP("JSR", 1);
	AddMACHI("MACHI", 0);
	AddMACHI("MACLO", 1);
	AddDIV("MAX", 4);
	AddDIV("MIN", 5);
	AddMOV("MOV", 0);
	AddMOVU("MOVU", 0);
	AddADD("MUL", 3);
	AddMACHI("MULHI", 2);
	AddMACHI("MULLO", 3);
	AddMVFACHI("MVFACHI", 0);
	AddMVFACHI("MVFACMI", 1);
	AddMVFC("MVFC", 0);
	AddMVTACHI("MVTACHI", 0);
	AddMVTACHI("MVTACLO", 1);
	AddMVTC("MVTC", 0);
	AddMVTIPL("MVTIPL", 0);
	AddABS("NEG", 0x1007);
	AddBRK("NOP", 0x0003);
	AddABS("NOT", 0x003B);
	AddADD("OR", 4);
	AddJMP("POP", 2);
	AddPOPC("POPC", 0);
	AddPOPM("POPM", 0);
	AddPUSH("PUSH", 0);
	AddPOPC("PUSHC", 1);
	AddPOPM("PUSHM", 1);
	AddRACW("RACW", 0);
	AddMACHI("REVL", 4);
	AddMACHI("REVW", 5);
	AddRMPA("RMPA", 0x8C);
	AddJMP("ROLC", 3);
	AddJMP("RORC", 4);
	AddROTL("ROTL", 0);
	AddROTL("ROTR", 1);
	AddFADD("ROUND", 6);
	AddRTE("RTE", 0x7F95);
	AddRTE("RTFI", 0x7F94);
	AddBRK("RTS", 0x0002);
	AddRTSD("RTSD", 0);
	AddJMP("SAT", 5);
	AddRTE("SATR", 0x7F93);
	AddADC("SBB", 0x0000);
	AddSCCnd("SCEQ", 0);
	AddSCCnd("SCZ", 0);
	AddSCCnd("SCNE", 1);
	AddSCCnd("SCNZ", 1);
	AddSCCnd("SCGEU", 2);
	AddSCCnd("SCC", 2);
	AddSCCnd("SCLTU", 3);
	AddSCCnd("SCNC", 3);
	AddSCCnd("SCGTU", 4);
	AddSCCnd("SCLEU", 5);
	AddSCCnd("SCPZ", 6);
	AddSCCnd("SCN", 7);
	AddSCCnd("SCGE", 8);
	AddSCCnd("SCLT", 9);
	AddSCCnd("SCGT", 10);
	AddSCCnd("SCLE", 11);
	AddSCCnd("SCO", 12);
	AddSCCnd("SCNO", 13);
	AddRTE("SCMPU", 0x7F83);
	AddCLRPSW("SETPSW", 0xA0);
	AddSHAR("SHAR", 0);
	AddSHAR("SHLL", 1);
	AddSHAR("SHLR", 2);
	AddRTE("SMOVB", 0x7F8B);
	AddRTE("SMOVF", 0x7F8F);
	AddRTE("SMOVU", 0x7F87);
	AddRMPA("SSTR", 0x88);
	AddSTNZ("STNZ", 0);
	AddSTNZ("STZ", 1);
	AddADD("SUB", 5);
	AddRMPA("SUNTIL", 0x80);
	AddRMPA("SWHILE", 0x84);
	AddTST("TST", 0);
	AddRTE("WAIT", 0x7F96);
	AddTST("XCHG", 1);
	AddTST("XOR", 2);

	/* RXv2 */
	AddFADD("FSQRT", 7);
	AddFADD("FTOU", 8);
	AddITOF("UTOF", 1);
	AddMOVCO("MOVCO", 0);
	AddMOVLI("MOVLI", 0);
	AddMACHI("EMACA", 6);
	AddMACHI("EMSBA", 7);
	AddMACHI("EMULA", 8);
	AddMACHI("MACLH", 9);
	AddMACHI("MSBHI", 10);
	AddMACHI("MSBLH", 11);
	AddMACHI("MSBLO", 12);
	AddMACHI("MULLH", 13);
	AddMVFACHI("MVFACGU", 2);
	AddMVFACHI("MVFACLO", 3);
	AddMVTACHI("MVTACGU", 2);
	AddRACW("RACL", 1);
	AddRACW("RDACL", 2);
	AddRACW("RDACW", 3);

	/* RXv3 */
	AddBFMOV("BFMOV", 0);
	AddBFMOV("BFMOVZ", 1);
	AddRSTR("RSTR", 0);
	AddRSTR("SAVE", 1); SaveIsOccupiedFnc = TrueFnc;
	AddDABS("DABS", 0);
	AddDADD("DADD", 0);
	AddDCMPcm("DCMPUN", 0x01);
	AddDCMPcm("DCMPEQ", 0x02);
	AddDCMPcm("DCMPLT", 0x04);
	AddDCMPcm("DCMPLE", 0x06);
	AddDADD("DDIV", 1);
	AddDMOV("DMOV", 0);
	AddDADD("DMUL", 2);
	AddDABS("DNEG", 1);
	AddDPOPM("DPOPM", 0);
	AddDPOPM("DPUSHM", 1);
	AddDABS("DROUND", 2);
	AddDABS("DSQRT", 3);
	AddDADD("DSUB", 3);
	AddDABS("DTOF", 4);
	AddDABS("DTOI", 5);
	AddDABS("DTOU", 6);
	AddFTOD("FTOD", 0);
	AddFTOD("ITOD", 1);
	AddMVFDC("MVFDC", 0);
	AddMVFDR("MVFDR", 0);
	AddMVFDC("MVTDC", 1);
	AddFTOD("UTOD", 2);

	/* Pseudo Instructions */
#ifdef COMPAT
	AddInstTable(InstTable, "ENDIAN", 0, DecodeENDIAN);
	AddBLK("BLKB", 1);
	AddBLK("BLKW", 2);
	AddBLK("BLKL", 4);
	AddBLK("BLKD", 8);
	AddInstTable(InstTable, "BYTE", eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString, DecodeIntelDB);
	AddInstTable(InstTable, "WORD", eIntPseudoFlag_DynEndian | eIntPseudoFlag_AllowInt, DecodeIntelDW);
	AddInstTable(InstTable, "LWORD", eIntPseudoFlag_DynEndian | eIntPseudoFlag_AllowInt, DecodeIntelDD);
	AddInstTable(InstTable, "FLOAT", eIntPseudoFlag_DynEndian | eIntPseudoFlag_AllowFloat, DecodeIntelDD);
	AddInstTable(InstTable, "DOUBLE", eIntPseudoFlag_DynEndian | eIntPseudoFlag_AllowFloat, DecodeIntelDQ);
#endif

	StrCompAlloc(&Temp1, STRINGSIZE);
	StrCompAlloc(&Temp2, STRINGSIZE);
}

static void DeinitFields(void)
{
	StrCompFree(&Temp2);
	StrCompFree(&Temp1);

	DestroyInstTable(InstTable);
}

/*---------------------------------------------------------------------------*/

static void MakeCode_RX(void)
{
	if (!LookupInstTable(InstTable, OpPart.str.p_str))
		WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}

static Boolean IsDef_RX(void)
{
	return False;
}

static void SwitchFrom_RX(void)
{
	DeinitFields();
}

static void SwitchTo_RX(void *pUser)
{
	const TFamilyDescr *pDescr;

	TurnWords = False;
	SetIntConstMode(eIntConstModeIntel);

	pDescr = FindFamilyByName("RX");
	PCSymbol = "$";
	HeaderID = pDescr->Id;
	NOPCode = 0x03;
	DivideChars = ",";
	HasAttrs = True;
	AttrChars = ".";

	ValidSegs = (1 << SegCode);
	Grans[SegCode] = 1;
	ListGrans[SegCode] = 1;
	SegInits[SegCode] = 0x0000;
	SegLimits[SegCode] = (LargeWord)IntTypeDefs[UInt32].Max;

	MakeCode = MakeCode_RX;
	IsDef = IsDef_RX;
	SwitchFrom = SwitchFrom_RX;
	InitFields();
	onoff_supmode_add();
	onoff_bigendian_add();

	pCurrCPUProps = (const tCPUProps *)pUser;
}

static const tCPUProps CPUProps[] =
{
	/* Group   InsSet FLT    DBL    RegB MVTIPL */
	{ "RXV1",  eRXv1, True,  False, 0,   True  },	/* Generic RXv1 (Full option) */
	{ "RX110", eRXv1, False, False, 0,   True  },
	{ "RX111", eRXv1, False, False, 0,   True  },
	{ "RX113", eRXv1, False, False, 0,   True  },
	{ "RX130", eRXv1, False, False, 0,   True  },
	{ "RX210", eRXv1, False, False, 0,   True  },
	{ "RX21A", eRXv1, False, False, 0,   True  },
	{ "RX220", eRXv1, False, False, 0,   True  },
	{ "RX610", eRXv1, True,  False, 0,   False },
	{ "RX621", eRXv1, True,  False, 0,   True  },
	{ "RX62N", eRXv1, True,  False, 0,   True  },
	{ "RX630", eRXv1, True,  False, 0,   True  },
	{ "RX631", eRXv1, True,  False, 0,   True  },

	{ "RXV2",  eRXv2, True,  False, 0,   True  },	/* Generic RXv2 */
	{ "RX140", eRXv2, True,  False, 0,   True  },
	{ "RX230", eRXv2, True,  False, 0,   True  },
	{ "RX231", eRXv2, True,  False, 0,   True  },
	{ "RX64M", eRXv2, True,  False, 0,   True  },
	{ "RX651", eRXv2, True,  False, 0,   True  },
	
	{ "RXV3",  eRXv3, True,  True,  256, True  },	/* Generic RXv3 (Full option) */
	{ "RX660", eRXv3, True,  False, 16,  True  },
	{ "RX671", eRXv3, True,  True,  16,  True  },
	{ "RX72M", eRXv3, True,  True,  16,  True  },
	{ "RX72N", eRXv3, True,  True,  16,  True  },

	{ ""     ,    eRXv1, False, False, 0,   False }
};

void coderx_init(void)
{
	const tCPUProps *pProp;

	for (pProp = CPUProps; pProp->Name[0]; pProp++)
		(void)AddCPUUser(pProp->Name, SwitchTo_RX, (void *)pProp, NULL);

	AddCopyright("Renesas RX Generator (C) 2023 Haruo Asano");
}
