/* codens32k.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Code Generator National Semiconductor NS32000                             */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"
#include <string.h>
#include "bpemu.h"
#include "strutil.h"
#include "ieeefloat.h"

#include "headids.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "asmitree.h"
#include "codevars.h"
#include "codepseudo.h"
#include "intpseudo.h"

#include "codepseudo.h"
#include "intpseudo.h"
#include "codens32k.h"

typedef enum
{
  eCoreNone,
  eCoreGen1,
  eCoreGen1Ext,
  eCoreGenE,
  eCoreGen2,
  eCoreCount
} tCore;

typedef enum
{
  eFPUNone,
  eFPU16081,
  eFPU32081,
  eFPU32181,
  eFPU32381,
  eFPU32580,
  eFPUCount
} tFPU;

typedef enum
{
  ePMMUNone,
  ePMMU16082,
  ePMMU32082,
  ePMMU32382,
  ePMMU32532,
  ePMMUCount
} tPMMU;

typedef struct
{
  const char *pName;
  Byte CPUType, DefFPU, DefPMMU;
  IntType MemIntType;
} tCPUProps;

static char FPUNames[eFPUCount][8] = { "OFF", "NS16081", "NS32081", "NS32181", "NS32381", "NS32580" };

static char PMMUNames[ePMMUCount][8] = { "OFF", "NS16082", "NS32082", "NS32382", "NS32532" };

typedef struct
{
  const char *pName;
  Word Code, Mask;
  Boolean Privileged;
} tCtlReg;

#ifdef __cplusplus
#include "codens32k.hpp"
#endif

#define MAllowImm (1 << 0)
#define MAllowReg (1 << 1)
#define MAllowRegPair (1 << 2)

static tCtlReg *CtlRegs, *MMURegs;

static tSymbolSize OpSize;
static const tCPUProps *pCurrCPUProps;
static tFPU MomFPU;
static tPMMU MomPMMU;
static Boolean CustomAvail;

/*!------------------------------------------------------------------------
 * \fn     SetOpSize(tSymbolSize Size, const tStrComp *pArg)
 * \brief  set (new) operand size of instruction
 * \param  Size size to set
 * \param  pArg source argument size was deduced from
 * \return True if no conflict
 * ------------------------------------------------------------------------ */

static Boolean SetOpSize(tSymbolSize Size, const tStrComp *pArg)
{
  if (OpSize == eSymbolSizeUnknown)
    OpSize = Size;
  else if ((Size != eSymbolSizeUnknown) && (Size != OpSize))
  {
    WrStrErrorPos(ErrNum_ConfOpSizes, pArg);
    return False;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     ResetOpSize(void)
 * \brief  back to undefined op size
 * \return constat True
 * ------------------------------------------------------------------------ */

static Boolean ResetOpSize(void)
{
  OpSize = eSymbolSizeUnknown;
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     CheckCore(unsigned CoreMask)
 * \brief  check for CPU/Core requirement
 * \param  CoreMask bit mask of core type supported
 * \return True if fulfilled
 * ------------------------------------------------------------------------ */

static Boolean CheckCore(unsigned CoreMask)
{
  if ((CoreMask >> pCurrCPUProps->CPUType) & 1)
    return True;
  WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  return False;
}

/*!------------------------------------------------------------------------
 * \fn     CheckSup(Boolean Required, const tStrComp *pArg)
 * \brief  check whether supervisor mode requirement is violated
 * \param  Required is supervisor mode required?
 * \param  pArg source argument
 * \return False if violated
 * ------------------------------------------------------------------------ */

static Boolean CheckSup(Boolean Required, const tStrComp *pArg)
{
  if (!SupAllowed && Required)
  {
    WrStrErrorPos(ErrNum_PrivOrder, pArg);
    return False;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     SetMomFPU(tFPU NewFPU)
 * \brief  set new FPU type in use
 * \param  NewFPU new type
 * ------------------------------------------------------------------------ */

static void SetMomFPU(tFPU NewFPU)
{
  switch ((MomFPU = NewFPU))
  {
    case eFPU16081:
    case eFPU32081:
    case eFPU32181:
    case eFPU32381:
    case eFPU32580:
    {
      tStrComp TmpComp;
      String TmpCompStr;

      StrCompMkTemp(&TmpComp, TmpCompStr, sizeof(TmpCompStr));
      strmaxcpy(TmpCompStr, MomFPUIdentName, sizeof(TmpCompStr));
      strmaxcpy(MomFPUIdent, FPUNames[MomFPU], sizeof(MomFPUIdent));
      EnterStringSymbol(&TmpComp, FPUNames[MomFPU], True);
      break;
    }
    default:
      break;
  }
}

/*!------------------------------------------------------------------------
 * \fn     SetMomPMMU(tFPU NewPMMU)
 * \brief  set new PMMU type in use
 * \param  NewPMMU new type
 * ------------------------------------------------------------------------ */

static void SetMomPMMU(tPMMU NewPMMU)
{
  switch ((MomPMMU = NewPMMU))
  {
    case ePMMU16082:
    case ePMMU32082:
    case ePMMU32382:
    case ePMMU32532:
    {
      tStrComp TmpComp;
      String TmpCompStr;

      StrCompMkTemp(&TmpComp, TmpCompStr, sizeof(TmpCompStr));
      strmaxcpy(TmpCompStr, MomPMMUIdentName, sizeof(TmpCompStr));
      strmaxcpy(MomPMMUIdent, PMMUNames[MomPMMU], sizeof(MomPMMUIdent));
      EnterStringSymbol(&TmpComp, PMMUNames[MomPMMU], True);
      break;
    }
    default:
      break;
  }
}

/*!------------------------------------------------------------------------
 * \fn     CheckFPUAvail(void)
 * \brief  check whether FPU instructions are enabled
 * \return False if not
 * ------------------------------------------------------------------------ */

static Boolean CheckFPUAvail(tFPU MinFPU)
{
  if (!FPUAvail)
  {
    WrStrErrorPos(ErrNum_FPUNotEnabled, &OpPart);
    return False;
  }
  else if (MomFPU < MinFPU)
  {
    WrStrErrorPos(ErrNum_FPUInstructionNotSupported, &OpPart);
    return False;
  }

  return True;
}

/*!------------------------------------------------------------------------
 * \fn     CheckPMMUAvail(void)
 * \brief  check whether PMMU instructions are enabled
 * \return False if not
 * ------------------------------------------------------------------------ */

static Boolean CheckPMMUAvail(void)
{
  if (!PMMUAvail)
  {
    WrStrErrorPos(ErrNum_PMMUNotEnabled, &OpPart);
    return False;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     CheckCustomAvail(void)
 * \brief  check whether Custom instructions are enabled
 * \return False if not
 * ------------------------------------------------------------------------ */

static Boolean CheckCustomAvail(void)
{
  if (!CustomAvail)
  {
    WrStrErrorPos(ErrNum_CustomNotEnabled, &OpPart);
    return False;
  }
  return True;
}

/*--------------------------------------------------------------------------*/
/* Register Handling */

static const char MemRegNames[][3] = { "FP", "SP", "SB" };
#define MemRegCount (sizeof(MemRegNames) / sizeof(*MemRegNames))

/*!------------------------------------------------------------------------
 * \fn     DecodeRegCore(const char *pArg, Word *pValue, tSymbolSize *pSize)
 * \brief  check whether argument describes a register
 * \param  pArg source argument
 * \param  pValue register number if yes
 * \param  pSize register size if yes
 * \return True if it is
 * ------------------------------------------------------------------------ */

static Boolean DecodeRegCore(const char *pArg, Word *pRegNum, tSymbolSize *pRegSize)
{
  unsigned z;

  for (z = 0; z < MemRegCount; z++)
    if (!as_strcasecmp(pArg, MemRegNames[z]))
    {
      *pRegNum = z + 8;
      *pRegSize = eSymbolSize32Bit;
      return True;
    }

  if ((strlen(pArg) != 2) || (pArg[1] < '0') || (pArg[1] > '7'))
    return False;
  *pRegNum = pArg[1] - '0';

  switch (as_toupper(*pArg))
  {
    case 'F': *pRegSize = eSymbolSizeFloat32Bit; return True;
    case 'R': *pRegSize = eSymbolSize32Bit; return True;
    case 'L': *pRegSize = eSymbolSizeFloat64Bit; return True;
    default:
      return False;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DissectReg_NS32K(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
 * \brief  dissect register symbols - NS32000 variant
 * \param  pDest destination buffer
 * \param  DestSize destination buffer size
 * \param  Value numeric register value
 * \param  InpSize register size
 * ------------------------------------------------------------------------ */

static void DissectReg_NS32K(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
  switch (InpSize)
  {
    case eSymbolSize32Bit:
      if (Value < 8)
        as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
      else if (Value < 8 + MemRegCount)
        as_snprintf(pDest, DestSize, "%s", MemRegNames[Value - 8]);
      else
        goto unknown;
      break;
    case eSymbolSizeFloat32Bit:
      as_snprintf(pDest, DestSize, "F%u", (unsigned)Value);
      break;
    case eSymbolSizeFloat64Bit:
      as_snprintf(pDest, DestSize, "L%u", (unsigned)Value);
      break;
    default:
    unknown:
      as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, Word *pValue, tSymbolSize *pSize, tSymbolSize ChkRegSize, Boolean MustBeReg)
 * \brief  check whether argument is a CPU register or user-defined register alias
 * \param  pArg argument
 * \param  pValue resulting register # if yes
 * \param  pSize resulting register size if yes
 * \param  ChkReqSize explicitly request certain register size
 * \param  MustBeReg expecting register or maybe not?
 * \return reg eval result
 * ------------------------------------------------------------------------ */

static Boolean MatchRegSize(tSymbolSize IsSize, tSymbolSize ReqSize)
{
  return (ReqSize == eSymbolSizeUnknown)
      || (IsSize == ReqSize)
      || ((ReqSize == eSymbolSizeFloat64Bit) && (IsSize == eSymbolSizeFloat32Bit));
}

static tRegEvalResult DecodeReg(const tStrComp *pArg, Word *pValue, tSymbolSize *pSize, tSymbolSize ChkRegSize, Boolean MustBeReg)
{
  tEvalResult EvalResult;
  tRegEvalResult RegEvalResult;

  if (DecodeRegCore(pArg->str.p_str, pValue, &EvalResult.DataSize))
    RegEvalResult = eIsReg;
  else
  {
    tRegDescr RegDescr;

    RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSizeUnknown, MustBeReg);
    if (eIsReg == RegEvalResult)
      *pValue = RegDescr.Reg;
  }

  if ((RegEvalResult == eIsReg) && !MatchRegSize(EvalResult.DataSize, ChkRegSize))
  {
    WrStrErrorPos(ErrNum_InvOpSize, pArg);
    RegEvalResult = MustBeReg ? eIsNoReg : eRegAbort;
  }

  if (pSize) *pSize = EvalResult.DataSize;
  return RegEvalResult;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCtlReg(const tStrComp *pArg, Word *pResult)
 * \brief  decode control processor register
 * \param  pArg source argument
 * \param  pResult result buffer
 * \return True if src expr is a register
 * ------------------------------------------------------------------------ */

static Boolean DecodeCtlReg(const tStrComp *pArg, Word *pResult)
{
  unsigned z;

  for (z = 0; CtlRegs[z].pName; z++)
    if (!as_strcasecmp(pArg->str.p_str, CtlRegs[z].pName))
    {
      *pResult = CtlRegs[z].Code;
      return CheckSup(CtlRegs[z].Privileged, pArg);
    }
  WrStrErrorPos(ErrNum_InvReg, pArg);
  return False;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMMUReg(const tStrComp *pArg, Word *pResult)
 * \brief  decode MMU register
 * \param  pArg source argument
 * \param  pResult result buffer
 * \return True if src expr is a register
 * ------------------------------------------------------------------------ */

static Boolean DecodeMMUReg(const tStrComp *pArg, Word *pResult)
{
  unsigned z;

  for (z = 0; MMURegs[z].pName; z++)
    if (!as_strcasecmp(pArg->str.p_str, MMURegs[z].pName))
    {
      if (!((MMURegs[z].Mask >> MomPMMU) & 1))
      {
        WrStrErrorPos(ErrNum_InvPMMUReg, pArg);
        return False;
      }
      *pResult = MMURegs[z].Code;
      return CheckSup(MMURegs[z].Privileged, pArg);
    }
  WrStrErrorPos(ErrNum_InvPMMUReg, pArg);
  return False;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRegList(const tStrComp *pArg, Boolean BitRev, Byte *pResult)
 * \brief  Decode Register List
 * \param  pArg Source Argument
 * \param  BitRev Reverse Bit Order, i.e. R0->Bit 7 ?
 * \param  pResult Result Buffer
 * \return True if successfully parsed
 * ------------------------------------------------------------------------ */

static Boolean DecodeRegList(const tStrComp *pArg, Boolean BitRev, Byte *pResult)
{
  tStrComp Part, Remainder;
  int l = strlen(pArg->str.p_str);
  Word Reg;
  char *pSep;

  if ((l < 2)
   || (pArg->str.p_str[0] != '[')
   || (pArg->str.p_str[l - 1] != ']'))
  {
    WrStrErrorPos(ErrNum_InvRegList, pArg);
    return False;
  }

  *pResult = 0;
  StrCompRefRight(&Part, pArg, 1);
  StrCompShorten(&Part, 1);
  while (True)
  {
    KillPrefBlanksStrCompRef(&Part);
    pSep = strchr(Part.str.p_str, ',');
    if (pSep)
      StrCompSplitRef(&Part, &Remainder, &Part, pSep);
    KillPostBlanksStrComp(&Part);
    if (DecodeReg(&Part, &Reg, NULL, eSymbolSize32Bit, True) != eIsReg)
      return False;
    if (Reg >= 8)
    {
      WrStrErrorPos(ErrNum_InvReg, &Part);
      return False;
    }
    *pResult |= 1 << (BitRev ? 7 - Reg : Reg);
    if (pSep)
      Part = Remainder;
    else
      break;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCfgList(const tStrComp *pArg, Byte *pResult)
 * \brief  Decode Config Option List
 * \param  pArg Source Argument
 * \param  pResult Result Buffer
 * \return True if successfully parsed
 * ------------------------------------------------------------------------ */

static Boolean DecodeCfgList(const tStrComp *pArg, Byte *pResult)
{
  tStrComp Part, Remainder;
  int l = strlen(pArg->str.p_str);
  char *pSep;
  const char Opts[] = "IFMC", *pOpt;

  if ((l < 2)
   || (pArg->str.p_str[0] != '[')
   || (pArg->str.p_str[l - 1] != ']'))
  {
    WrStrErrorPos(ErrNum_InvCfgList, pArg);
    return False;
  }

  *pResult = 0;
  StrCompRefRight(&Part, pArg, 1);
  StrCompShorten(&Part, 1);
  while (True)
  {
    KillPrefBlanksStrCompRef(&Part);
    pSep = strchr(Part.str.p_str, ',');
    if (pSep)
      StrCompSplitRef(&Part, &Remainder, &Part, pSep);
    KillPostBlanksStrComp(&Part);
    switch (strlen(Part.str.p_str))
    {
      case 0:
        break;
      case 1:
        pOpt = strchr(Opts, as_toupper(*Part.str.p_str));
        if (pOpt)
        {
          *pResult |= 1 << (pOpt - Opts);
          break;
        }
        /* else fall-through */
      default:
        WrStrErrorPos(ErrNum_InvCfgList, &Part);
        return False;
    }
    if (pSep)
      Part = Remainder;
    else
      break;
  }
  return True;
}

/*--------------------------------------------------------------------------*/
/* Address Decoder */

enum
{
  AddrCode_Reg = 0x00,
  AddrCode_Relative = 0x08,
  AddrCode_MemRelative = 0x10,
  AddrCode_Reserved = 0x13,
  AddrCode_Immediate = 0x14,
  AddrCode_Absolute = 0x15,
  AddrCode_External = 0x16,
  AddrCode_TOS = 0x17,
  AddrCode_MemSpace = 0x18,
  AddrCode_ScaledIndex = 0x1c
};

typedef struct
{
  Byte Code;
  Byte Index[1], Disp[8];
  unsigned IndexCnt, DispCnt;
} tAdrVals;

static void ClearAdrVals(tAdrVals *pVals)
{
  pVals->Code = AddrCode_Reserved;
  pVals->IndexCnt = pVals->DispCnt = 0;
}

/*!------------------------------------------------------------------------
 * \fn     EncodeDisplacement(LongInt Disp, tAdrVals *pDest, tErrorNum ErrorNum, const tStrComp *pArg)
 * \brief  encode signed displacement
 * \param  Disp displacement to encode
 * \param  pDest destination buffer
 * \param  ErrorNum error msg to print if out of range
 * \param  pArg source argument for error messages
 * \return True if successfully encoded
 * ------------------------------------------------------------------------ */

static Boolean EncodeDisplacement(LongInt Disp, tAdrVals *pDest, tErrorNum ErrorNum, const tStrComp *pArg)
{
  if ((Disp >= -64) && (Disp <= 63))
  {
    pDest->Disp[pDest->DispCnt++] = Disp & 0x7f;
    return True;
  }
  else if ((Disp >= -8192) && (Disp <= 8191))
  {
    pDest->Disp[pDest->DispCnt++] = 0x80 | ((Disp >> 8) & 0x3f);
    pDest->Disp[pDest->DispCnt++] = Disp & 0xff;
    return True;
  }
  else if ((Disp >= -520093696) && (Disp <= 536870911))
  {
    Byte HiByte = 0xc0 | ((Disp >> 24) & 0x3f);

    if (HiByte == 0xe0)
      goto error;

    pDest->Disp[pDest->DispCnt++] = HiByte;
    pDest->Disp[pDest->DispCnt++] = (Disp >> 16) & 0xff;
    pDest->Disp[pDest->DispCnt++] = (Disp >> 8) & 0xff;
    pDest->Disp[pDest->DispCnt++] = Disp & 0xff;
    return True;
  }
  else
  {
error:
    WrStrErrorPos(ErrorNum, pArg);
    return False;
  }
}

/*!------------------------------------------------------------------------
 * \fn     EncodePCRel(const tStrComp *pArg, tAdrVals *pDest)
 * \brief  PC-relative encoding of address
 * \param  pArg address in source
 * \param  pDest dest buffer
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean EncodePCRel(const tStrComp *pArg, tAdrVals *pDest)
{
  tEvalResult EvalResult;
  LongInt Dist = EvalStrIntExpressionWithResult(pArg, pCurrCPUProps->MemIntType, &EvalResult) - EProgCounter();

  ClearAdrVals(pDest);
  if (!EvalResult.OK
   || !EncodeDisplacement(Dist, pDest, mFirstPassUnknownOrQuestionable(EvalResult.Flags) ? ErrNum_None : ErrNum_JmpDistTooBig, pArg))
    return False;

  pDest->Code = AddrCode_MemSpace + 3;
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     DecodeAdr(tStrComp *pArg, tAdrVals *pDest, unsigned AddrModeMask)
 * \brief  decode address expression
 * \param  pArg source argument
 * \param  pDest dest buffer
 * \param  AddrModeMask allow immediate/register addressing?
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean DecodeAdr(const tStrComp *pArg, tAdrVals *pDest, Boolean AddrModeMask)
{
  Byte IndexCode = 0;
  Boolean OK, NeedEvenReg;
  const Boolean IsFloat = (OpSize == eSymbolSizeFloat32Bit) || (OpSize == eSymbolSizeFloat64Bit);
  Word RegValue, IndexReg = 0;
  int ArgLen, SplitPos;
  tStrComp BaseArg;
  const char IndexChars[] = "BWDQ";
  char *pSplit, *pSplit2, Scale;

  ClearAdrVals(pDest);

  /* split off scaled indexing, which is orthogonal to (almost) all other modes */

  pSplit = MatchCharsRev(pArg->str.p_str, " : ? ] ", IndexChars, &Scale);
  pSplit2 = (pSplit && (pSplit > pArg->str.p_str))
          ? FindOpeningParenthese(pArg->str.p_str, pSplit - 1, "[]")
          : NULL;
  if (pSplit && pSplit2)
  {
    tStrComp Mid, Right;
    const char *pScaleIndex;

    StrCompSplitRef(&BaseArg, &Right, pArg, pSplit);
    StrCompSplitRef(&BaseArg, &Mid, &BaseArg, pSplit2);
    KillPrefBlanksStrCompRef(&Mid);
    KillPostBlanksStrComp(&BaseArg);
    pArg = &BaseArg;

    pScaleIndex = strchr(IndexChars, as_toupper(Scale));
    if (!pScaleIndex)
    {
      WrStrErrorPos(ErrNum_InvScale, &Right);
      return False;
    }
    IndexCode = AddrCode_ScaledIndex + (pScaleIndex - IndexChars);
    if ((DecodeReg(&Mid, &IndexReg, NULL, eSymbolSize32Bit, True) == eIsReg)
     && (IndexReg >= 8))
    {
      WrStrErrorPos(ErrNum_InvReg, &Mid);
      return False;
    }

    /* Immediate cannot be combined with scaling, so disallow regardless of caller's
       preference: */

    AddrModeMask &= ~MAllowImm;
  }

  /* absolute: */

  if (*pArg->str.p_str == '@')
  {
    tStrComp Arg;
    LongWord Addr;

    StrCompRefRight(&Arg, pArg, 1);
    Addr = EvalStrIntExpression(&Arg, pCurrCPUProps->MemIntType, &OK);
    if (!OK)
      return False;

    /* On a CPU with non-32-bit address bus, addresses @ the upper end may be encoded
       as negative 'displacements': */

    if ((pCurrCPUProps->MemIntType == UInt24)
     && (Addr & 0x800000ul))
      Addr |= 0xff000000ul;
    if (EncodeDisplacement((LongInt)Addr, pDest, ErrNum_OverRange, &Arg))
    {
      pDest->Code = AddrCode_Absolute;
      goto chk;
    }
    else
      return False;
  }

  /* TOS? */

  if (!as_strcasecmp(pArg->str.p_str, "TOS"))
  {
    pDest->Code = AddrCode_TOS;
    goto chk;
  }

  /* register? */

  if (IsFloat)
    NeedEvenReg = (OpSize == eSymbolSizeFloat64Bit) && (MomFPU < eFPU32181);
  else
    NeedEvenReg = !!(AddrModeMask & MAllowRegPair);
  switch (DecodeReg(pArg, &RegValue, NULL, IsFloat ? OpSize : eSymbolSize32Bit, False))
  {
    case eIsReg:
      if (NeedEvenReg && (RegValue & 1))
      {
        WrStrErrorPos(ErrNum_InvRegPair, pArg);
        return False;
      }
      else if (!(AddrModeMask & (MAllowReg | MAllowRegPair)))
      {
        WrStrErrorPos(ErrNum_InvAddrMode, pArg);
        return False;
      }
      else
      {
        pDest->Code = AddrCode_Reg + RegValue;
        goto chk;
      }
    case eIsNoReg:
      break;
    default:
      return False;
  }

  /* EXT mode */

  pSplit = MatchChars(pArg->str.p_str, " EXT (");
  if (pSplit)
  {
    tStrComp Left, Mid, Right;
    LongInt Disp1, Disp2 = 0;
    Boolean OK;

    StrCompSplitRef(&Left, &Mid, pArg, pSplit - 1);
    pSplit = FindClosingParenthese(Mid.str.p_str);
    if (!pSplit)
    {
      WrStrErrorPos(ErrNum_BrackErr, pArg);
      return False;
    }
    StrCompSplitRef(&Mid, &Right, &Mid, pSplit);
    Disp1 = EvalStrIntExpression(&Mid, Int30, &OK);
    if (!OK)
      return False;
    *(--Right.str.p_str) = '0'; Right.Pos.Len++; Right.Pos.StartCol--;
    if (*Right.str.p_str)
      Disp2 = EvalStrIntExpression(&Right, Int30, &OK);
    if (!OK)
      return False;

    pDest->Code = AddrCode_External;
    if (!EncodeDisplacement(Disp1, pDest, ErrNum_OverRange, &Mid)
     || !EncodeDisplacement(Disp2, pDest, ErrNum_OverRange, &Right))
      return False;
    goto chk;
  }

  /* PC-relative */

  if (!strcmp(pArg->str.p_str, "*")
   || MatchChars(pArg->str.p_str, "* ?", "+-", NULL))
  {
    LongInt Disp;
    Boolean OK;

    *pArg->str.p_str = '0';
    Disp = EvalStrIntExpression(pArg, Int30, &OK);
    *pArg->str.p_str = '*';
    if (!OK
     || !EncodeDisplacement(Disp, pDest, ErrNum_OverRange, pArg))
      return False;
    pDest->Code = AddrCode_MemSpace + 3;
    goto chk;
  }

  /* disp(...)? */

  SplitPos = FindDispBaseSplit(pArg->str.p_str, &ArgLen);
  if (SplitPos >= 0)
  {
    tStrComp OutDisp, InnerArg;
    LongInt OutDispVal;
    tEvalResult OutEvalResult;

    memset(&OutEvalResult, 0, sizeof(OutEvalResult));
    StrCompSplitRef(&OutDisp, &InnerArg, pArg, &pArg->str.p_str[SplitPos]);
    if (OutDisp.Pos.Len)
    {
      OutDispVal = EvalStrIntExpressionWithResult(&OutDisp, Int30, &OutEvalResult);
      if (!OutEvalResult.OK)
        return False;
    }
    else
    {
      OutEvalResult.OK = True;
      OutDispVal = 0;
    }

    StrCompShorten(&InnerArg, 1);
    KillPrefBlanksStrCompRef(&InnerArg);
    KillPostBlanksStrComp(&InnerArg);
    switch (DecodeReg(&InnerArg, &RegValue, NULL, eSymbolSize32Bit, False))
    {
      case eIsReg: /* disp(Rn/FP/SP/SB) */
        pDest->Code = (RegValue < 8) ? AddrCode_Relative + RegValue : AddrCode_MemSpace + (RegValue - 8);
        if (!EncodeDisplacement(OutDispVal, pDest, ErrNum_OverRange, &OutDisp))
          return False;
        goto chk;
      IsPCRel:
        if (EncodeDisplacement(OutDispVal - EProgCounter(), pDest, mFirstPassUnknownOrQuestionable(OutEvalResult.Flags) ? ErrNum_None : ErrNum_JmpDistTooBig, &OutDisp))
          pDest->Code = AddrCode_MemSpace + 3;
        goto chk;
      case eIsNoReg:
      {
        tStrComp InDisp;
        LongInt InDispVal = 0;

        if (!as_strcasecmp(InnerArg.str.p_str, "PC"))
          goto IsPCRel;

        SplitPos = FindDispBaseSplit(InnerArg.str.p_str, &ArgLen);
        if (SplitPos < 0)
        {
          WrStrErrorPos(ErrNum_InvAddrMode, &InnerArg);
          return False;
        }
        StrCompSplitRef(&InDisp, &InnerArg, &InnerArg, &InnerArg.str.p_str[SplitPos]);
        if (InDisp.Pos.Len)
        {
          InDispVal = EvalStrIntExpression(&InDisp, Int30, &OK);
          if (!OK)
            return False;
        }

        StrCompShorten(&InnerArg, 1);
        KillPrefBlanksStrCompRef(&InnerArg);
        KillPostBlanksStrComp(&InnerArg);

        /* disp2(disp1(ext)) is an alias for EXT(disp1)+disp2 */

        if (!as_strcasecmp(InnerArg.str.p_str, "EXT"))
        {
          pDest->Code = AddrCode_External;
        }

        /* disp2(disp1(FP/SP/SB)) */

        else
        {
          if (DecodeReg(&InnerArg, &RegValue, NULL, eSymbolSize32Bit, True) != eIsReg)
            return False;
          if (RegValue < 8)
          {
            WrStrErrorPos(ErrNum_InvReg, &InnerArg);
            return False;
          }
          pDest->Code = AddrCode_MemRelative + (RegValue - 8);
        }
        if (!EncodeDisplacement(InDispVal, pDest, ErrNum_OverRange, &InDisp)
         || !EncodeDisplacement(OutDispVal, pDest, ErrNum_OverRange, &OutDisp))
          return False;
        goto chk;
      }
      default:
        return False;
    }
  }

  /* -> immediate or PC-relative */

  if (AddrModeMask & MAllowImm)
  {
    switch (OpSize)
    {
      case eSymbolSize8Bit:
        pDest->Disp[0] = EvalStrIntExpression(pArg, Int8, &OK);
        if (OK)
          pDest->DispCnt = 1;
        break;
      case eSymbolSize16Bit:
      {
        Word Val = EvalStrIntExpression(pArg, Int16, &OK);
        if (OK)
        {
          pDest->Disp[pDest->DispCnt++] = Hi(Val);
          pDest->Disp[pDest->DispCnt++] = Lo(Val);
        }
        break;
      }
      case eSymbolSize32Bit:
      {
        LongWord Val = EvalStrIntExpression(pArg, Int32, &OK);
        if (OK)
        {
          pDest->Disp[pDest->DispCnt++] = (Val >> 24) & 0xff;
          pDest->Disp[pDest->DispCnt++] = (Val >> 16) & 0xff;
          pDest->Disp[pDest->DispCnt++] = (Val >>  8) & 0xff;
          pDest->Disp[pDest->DispCnt++] = (Val >>  0) & 0xff;
        }
        break;
      }
      case eSymbolSize64Bit:
      {
        LargeWord Val = EvalStrIntExpression(pArg, LargeIntType, &OK);
        if (OK)
        {
          unsigned z;
          Byte highest_src = 0;

          for (z = 0; z < min(8, LARGEBITS / 8); z++, Val >>= 8)
            pDest->Disp[pDest->DispCnt + (7 - z)] = highest_src = Val & 0xff;
          for (; z < 8; z++)
            pDest->Disp[pDest->DispCnt + (7 - z)] = (highest_src & 0x80) ? 0xff : 0x00;
          pDest->DispCnt += 8;
        }
        break;
      }
      case eSymbolSizeFloat32Bit:
      {
        as_float_t Val = EvalStrFloatExpression(pArg, &OK);
        if (OK)
        {
          int ret;

          if ((ret = as_float_2_ieee4(Val, pDest->Disp, True)) < 0)
          {
            asmerr_check_fp_dispose_result(ret, pArg);
            OK = False;
          }
        }
        if (OK)
          pDest->DispCnt = 4;
        break;
      }
      case eSymbolSizeFloat64Bit:
      {
        as_float_t Val = EvalStrFloatExpression(pArg, &OK);
        if (OK)
        {
          int ret;

          if ((ret = as_float_2_ieee8(Val, pDest->Disp, True)) < 0)
          {
            asmerr_check_fp_dispose_result(ret, pArg);
            OK = False;
          }
        }
        if (OK)
          pDest->DispCnt = 8;
        break;
      }
      default:
        WrStrErrorPos(ErrNum_UndefOpSizes, pArg);
    }
    if (pDest->DispCnt)
      pDest->Code = AddrCode_Immediate;
    else
      return False;
  }
  else if (!EncodePCRel(pArg, pDest))
    return False;

chk:
  /* if we have an index code, check it's not immedate, otherwise relocate */

  if (IndexCode)
  {
    if (pDest->Code == AddrCode_Immediate)
    {
      WrStrErrorPos(ErrNum_InvAddrMode, pArg);
      return False;
    }
    pDest->Index[pDest->IndexCnt++] = (pDest->Code << 3) | IndexReg;
    pDest->Code = IndexCode;
  }
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     AppendIndex(const tAdrVals *pVals)
 * \brief  append optional index byte to code
 * \param  pVals encoded addressing mode
 * ------------------------------------------------------------------------ */

static void AppendIndex(const tAdrVals *pVals)
{
  if (pVals->IndexCnt)
  {
    memcpy(&BAsmCode[CodeLen], pVals->Index, pVals->IndexCnt);
    CodeLen += pVals->IndexCnt;
  }
}

/*!------------------------------------------------------------------------
 * \fn     AppendDisp(const tAdrVals *pVals)
 * \brief  append optional displacement to code
 * \param  pVals encoded addressing mode
 * ------------------------------------------------------------------------ */

static void AppendDisp(const tAdrVals *pVals)
{
  if (pVals->DispCnt)
  {
    memcpy(&BAsmCode[CodeLen], pVals->Disp, pVals->DispCnt);
    CodeLen += pVals->DispCnt;
  }
}

/*--------------------------------------------------------------------------*/
/* Helper Functions */

/*!------------------------------------------------------------------------
 * \fn     SizeCodeI(tSymbolSize Size)
 * \brief  transform (integer) operand size to i size in instruction
 * \param  Size Operand Size
 * \return Size Code
 * ------------------------------------------------------------------------ */

static LongWord SizeCodeI(tSymbolSize Size)
{
  switch (Size)
  {
    case eSymbolSize8Bit:
      return 0;
    case eSymbolSize16Bit:
      return 1;
    case eSymbolSize32Bit:
      return 3;
    default:
      return 2;
  }
}

/*!------------------------------------------------------------------------
 * \fn     SizeCodeF(tSymbolSize Size)
 * \brief  transform (float) operand size to f size in instruction
 * \param  Size Operand Size
 * \return Size Code
 * ------------------------------------------------------------------------ */

static LongWord SizeCodeF(tSymbolSize Size)
{
  switch (Size)
  {
    case eSymbolSizeFloat64Bit:
      return 0;
    case eSymbolSizeFloat32Bit:
      return 1;
    default:
      return 0xff;
  }
}

/*!------------------------------------------------------------------------
 * \fn     SizeCodeC(tSymbolSize Size)
 * \brief  transform (custom) operand size to c size in instruction
 * \param  Size Operand Size
 * \return Size Code
 * ------------------------------------------------------------------------ */

static LongWord SizeCodeC(tSymbolSize Size)
{
  switch (Size)
  {
    case eSymbolSize64Bit:
      return 0;
    case eSymbolSize32Bit:
      return 1;
    default:
      return 0xff;
  }
}

/*!------------------------------------------------------------------------
 * \fn     GetOpSizeFromCode(Word Code)
 * \brief  get operand size of instruction from insn name
 * \param  Code contains size in MSB
 * \return operand size
 * ------------------------------------------------------------------------ */

static tSymbolSize GetOpSizeFromCode(Word Code)
{
  Byte Size = Hi(Code) & 15;

  return (Size == 0xff) ? eSymbolSizeUnknown : (tSymbolSize)Size;
}

/*!------------------------------------------------------------------------
 * \fn     SetOpSizeFromCode(Word Code)
 * \brief  set operand size of instruction from insn code MSB
 * \param  Code contains size in MSB
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean SetOpSizeFromCode(Word Code)
{
  return SetOpSize(GetOpSizeFromCode(Code), &OpPart);
}

/*!------------------------------------------------------------------------
 * \fn     SetFOpSizeFromCode(Word Code)
 * \brief  set FP operand size of instruction from insn code
 * \param  Code contains size in LSB
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean SetFOpSizeFromCode(Word Code)
{
  return SetOpSize((Code & 1) ? eSymbolSizeFloat32Bit : eSymbolSizeFloat64Bit, &OpPart);
}

/*!------------------------------------------------------------------------
 * \fn     SetCOpSizeFromCode(Word Code)
 * \brief  set custom operand size of instruction from insn code
 * \param  Code contains size in LSB
 * \return True if success
 * ------------------------------------------------------------------------ */

static Boolean SetCOpSizeFromCode(Word Code)
{
  return SetOpSize((Code & 1) ? eSymbolSize32Bit : eSymbolSize64Bit, &OpPart);
}

/*!------------------------------------------------------------------------
 * \fn     PutCode(LongWord Code, unsigned Count)
 * \brief  write instruction opcode to output
 * \param  Code opcode to write
 * \param  Count # of bytes to write
 * ------------------------------------------------------------------------ */

static void PutCode(LongWord Code, unsigned Count)
{
  BAsmCode[CodeLen++] = Code & 0xff;
  while (Count > 1)
  {
    Code >>= 8;
    Count--;
    BAsmCode[CodeLen++] = Code & 0xff;
  }
}

/*!------------------------------------------------------------------------
 * \fn     ChkNoAttrPart(void)
 * \brief  check for no attribute part
 * \return True if no attribute
 * ------------------------------------------------------------------------ */

static Boolean ChkNoAttrPart(void)
{
  if (*AttrPart.str.p_str)
  {
    WrError(ErrNum_UseLessAttr);
    return False;
  }
  return True;
}

/*--------------------------------------------------------------------------*/
/* Instruction De/Encoders */

/*!------------------------------------------------------------------------
 * \fn     DecodeFixed(Word Code)
 * \brief  decode instructions without argument
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeFixed(Word Code)
{
  if (ChkArgCnt(0, 0))
    PutCode(Code, !!Hi(Code));
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat0(Word Code)
 * \brief  Decode Format 0 Instructions
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeFormat0(Word Code)
{
  tAdrVals AdrVals;

  ClearAdrVals(&AdrVals);
  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && EncodePCRel(&ArgStr[1], &AdrVals))
  {
    PutCode(Code, 1);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRET(Word Code)
 * \brief  Decode RET/RETT/RXP Instructions
 * \param  Code Machine Code
 * ------------------------------------------------------------------------ */

static void DecodeRET(Word Code)
{
  if (ChkArgCnt(0, 1)
   &&  ChkNoAttrPart())
  {
    tEvalResult EvalResult;
    LongInt Value;
    tAdrVals AdrVals;

    if (ArgCnt >= 1)
      Value = EvalStrIntExpressionWithResult(&ArgStr[1], SInt30, &EvalResult);
    else
    {
      Value = 0;
      EvalResult.OK = True;
      EvalResult.Flags = eSymbolFlag_None;
    }

    ClearAdrVals(&AdrVals);
    if (EncodeDisplacement(Value, &AdrVals, mFirstPassUnknownOrQuestionable(EvalResult.Flags) ? ErrNum_None : ErrNum_OverRange, &ArgStr[1]))
    {
      PutCode(Code, 1);
      AppendDisp(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCXP(Word Code)
 * \brief  Handle CXP Instruction
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeCXP(Word Code)
{
  if (ChkArgCnt(1, 1)
   &&  ChkNoAttrPart())
  {
    tEvalResult EvalResult;
    LongInt Value = EvalStrIntExpressionWithResult(&ArgStr[1], SInt30, &EvalResult);
    tAdrVals AdrVals;

    ClearAdrVals(&AdrVals);
    if (EncodeDisplacement(Value, &AdrVals, mFirstPassUnknownOrQuestionable(EvalResult.Flags) ? ErrNum_None : ErrNum_OverRange, &ArgStr[1]))
    {
      PutCode(Code, 1);
      AppendDisp(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeENTER(Word Code)
 * \brief  Handle ENTER Instruction (Format 1)
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeENTER(Word Code)
{
  Byte RegList;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && DecodeRegList(&ArgStr[1], False, &RegList))
  {
    tEvalResult EvalResult;
    LongInt Value = EvalStrIntExpressionWithResult(&ArgStr[2], SInt30, &EvalResult);
    tAdrVals AdrVals;

    ClearAdrVals(&AdrVals);
    if (EncodeDisplacement(Value, &AdrVals, mFirstPassUnknownOrQuestionable(EvalResult.Flags) ? ErrNum_None : ErrNum_OverRange, &ArgStr[1]))
    {
      PutCode(Code, 1);
      BAsmCode[CodeLen++] = RegList;
      AppendDisp(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeEXIT(Word Code)
 * \brief  Handle EXIT Instruction (Format 1)
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeEXIT(Word Code)
{
  Byte RegList;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && DecodeRegList(&ArgStr[1], True, &RegList))
  {
    PutCode(Code, 1);
    BAsmCode[CodeLen++] = RegList;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeSAVE_RESTORE(Word Code)
 * \brief  Decode SAVE/RESTORE Instructions
 * \param  Code Machine Code
 * ------------------------------------------------------------------------ */

static void DecodeSAVE_RESTORE(Word Code)
{
  Byte RegList;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && DecodeRegList(&ArgStr[1], !!(Code & 0x10), &RegList))
  {
    PutCode(Code, 1);
    PutCode(RegList, 1);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCINV(Word Code)
 * \brief  handle CINV instruction
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeCINV(Word Code)
{
  tAdrVals AdrVals;

  if (ChkArgCnt(2, 4)
   && ChkNoAttrPart()
   && CheckCore(1 << eCoreGen2)
   && CheckSup(True, &OpPart)
   && DecodeAdr(&ArgStr[ArgCnt], &AdrVals, MAllowReg))
  {
    LongWord ActCode = (((LongWord)AdrVals.Code) << 19)
                     | Code;
    int z;

    for (z = 1; z < ArgCnt; z++)
      if (!as_strcasecmp(ArgStr[z].str.p_str, "A"))
        ActCode |= 1ul << 17;
      else if (!as_strcasecmp(ArgStr[z].str.p_str, "I"))
        ActCode |= 1ul << 16;
      else if (!as_strcasecmp(ArgStr[z].str.p_str, "D"))
        ActCode |= 1ul << 15;
      else
      {
        WrStrErrorPos(ErrNum_InvCacheInvMode, &ArgStr[z]);
        return;
      }
    PutCode(ActCode, 3);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeLPR_SPR(Word Code)
 * \brief  Decode LPR/SPR Instructions (Format 2)
 * \param  Code Machine Code & Operand Size
 * ------------------------------------------------------------------------ */

static void DecodeLPR_SPR(Word Code)
{
  tAdrVals SrcAdrVals;
  Word Reg;
  Boolean IsSPR = (Lo(Code) == 2);

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &SrcAdrVals, MAllowReg | (IsSPR ? 0 : MAllowImm))
   && DecodeCtlReg(&ArgStr[1], &Reg))
  {
    PutCode((((Word)SrcAdrVals.Code) << 11)
          | (Reg << 7)
          | (Lo(Code) << 4)
          | (SizeCodeI(OpSize) << 0)
          | 0x0c, 2);
    AppendIndex(&SrcAdrVals);
    AppendDisp(&SrcAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeScond(Word Code)
 * \brief  Handloe Scond Instructions
 * \param  Code condition & operand size
 * ------------------------------------------------------------------------ */

static void DecodeScond(Word Code)
{
  tAdrVals AdrVals;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &AdrVals, MAllowReg))
  {
    PutCode((((Word)AdrVals.Code) << 11)
          | ((Code & 0xff) << 7)
          | (SizeCodeI(OpSize) << 0)
          | 0x3c, 2);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVQ(Word Code)
 * \brief  Handle MOVQ/ADDQ/CMPQ Instructions
 * \param  Code Machine Code & Operand Size
 * ------------------------------------------------------------------------ */

#define MOVQ_DESTMAYIMM 0x80

static void DecodeMOVQ(Word Code)
{
  tAdrVals DestAdrVals;
  Boolean DestMayImm = !!(Code & MOVQ_DESTMAYIMM);

  Code &= ~MOVQ_DESTMAYIMM;
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg | (DestMayImm ? MAllowImm : 0)))
  {
    Boolean OK;
    Integer Val = EvalStrIntExpression(&ArgStr[1], SInt4, &OK);

    if (OK)
    {
      PutCode((((Word)DestAdrVals.Code) << 11)
            | ((Val & 0x0f) << 7)
            | (Lo(Code) << 4)
            | (SizeCodeI(OpSize) << 0)
            | 0x0c, 2);
      AppendIndex(&DestAdrVals);
      AppendDisp(&DestAdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeACB(Word Code)
 * \brief  handle ACBi Instrucion
 * \param  Code machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeACB(Word Code)
{
  tAdrVals DestAdrVals;

  if (ChkArgCnt(3, 3)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    Boolean OK;
    tAdrVals DistAdrVals;
    Integer Val = EvalStrIntExpression(&ArgStr[1], SInt4, &OK);

    if (OK && EncodePCRel(&ArgStr[3], &DistAdrVals))
    {
      PutCode((((Word)DestAdrVals.Code) << 11)
            | ((Val & 0x0f) << 7)
            | (Lo(Code) << 4)
            | (SizeCodeI(OpSize) << 0)
            | 0x0c, 2);
      AppendIndex(&DestAdrVals);
      AppendDisp(&DestAdrVals);
      AppendDisp(&DistAdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat3(Word Code)
 * \brief  Decode Format 3 Instructions
 * \param  Code Machine Code
 * ------------------------------------------------------------------------ */

static void DecodeFormat3(Word Code)
{
  tAdrVals AdrVals;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &AdrVals, MAllowReg | MAllowImm))
  {
    PutCode((((Word)AdrVals.Code) << 11)
          | (Lo(Code) << 7)
          | (SizeCodeI(OpSize) << 0)
          | 0x7c, 2);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat4(Word Code)
 * \brief  decode Format 4 instructions
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

#define FMT4_SRCISADDR 0x80
#define FMT4_DESTMAYIMM 0x40

static void DecodeFormat4(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Boolean SrcIsAddr = !!(Code & FMT4_SRCISADDR),
          DestMayImm = !!(Code & FMT4_DESTMAYIMM);

  Code &= ~(FMT4_SRCISADDR | FMT4_DESTMAYIMM);
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | (SrcIsAddr ? 0 : MAllowImm))
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg | (DestMayImm ? MAllowImm : 0)))
  {
    PutCode((((Word)SrcAdrVals.Code) << 11)
          | (((Word)DestAdrVals.Code) << 6)
          | (Lo(Code) << 2)
          | (SizeCodeI(OpSize)), 2);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVS_CMPS_SKPS(Word Code)
 * \brief  Handle MOVSi/CMPSi/SKPSi Instructions (Format 5)
 * \param  Code machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeMOVS_CMPS_SKPS(Word Code)
{
  if (ChkArgCnt(0, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code))
  {
    Byte Options = 0;
    int z;

    for (z = 1; z <= ArgCnt; z++)
    {
      if (!as_strcasecmp(ArgStr[z].str.p_str, "B"))
        Options |= 1;
      else if (!as_strcasecmp(ArgStr[z].str.p_str, "U"))
      {
        if (Options & 6)
        {
          WrStrErrorPos(ErrNum_ConfStringOpt, &ArgStr[z]);
          return;
        }
        else
          Options |= 6;
      }
      else if (!as_strcasecmp(ArgStr[z].str.p_str, "W"))
      {
        if (Options & 6)
        {
          WrStrErrorPos(ErrNum_ConfStringOpt, &ArgStr[z]);
          return;
        }
        else
          Options |= 2;
      }
      else
      {
        WrStrErrorPos(ErrNum_UnknownStringOpt, &ArgStr[z]);
        return;
      }
    }
    PutCode((((LongWord)Options) << 16)
          | ((Code & 0xff) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x0e, 3);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeSETCFG(Word Code)
 * \brief  Handle SETCFG Instruction
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeSETCFG(Word Code)
{
  Byte CfgOpts;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && CheckSup(True, &OpPart)
   && DecodeCfgList(&ArgStr[1], &CfgOpts))
    PutCode((((LongWord)CfgOpts) << 15)
            | Code, 3);
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat6(Word Code)
 * \brief  Decode Format 6 Instructions
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

#define FMT6_SRC8BIT 0x80

static void DecodeFormat6(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Boolean SrcIs8Bit = !!(Code & FMT6_SRC8BIT);

  Code &= ~FMT6_SRC8BIT;
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(SrcIs8Bit ? 0x0000 : Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x4e, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat7(Word Code)
 * \brief  Decode Format 7 Instructions
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeFormat7(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0xce, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVM_CMPM(Word Code)
 * \brief  Decode MOVMi/CMPMi Instruction (Format 7)
 * \param  Code machine code & size
 * ------------------------------------------------------------------------ */

static void DecodeMOVM_CMPM(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(3, 3)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    tEvalResult EvalResult;
    LongWord Count = EvalStrIntExpressionWithResult(&ArgStr[3], UInt30, &EvalResult);

    if (EvalResult.OK)
    {
      tAdrVals CntAdrVals;

      Count = (Count - 1) << OpSize;
      ClearAdrVals(&CntAdrVals);
      if (EncodeDisplacement(Count, &CntAdrVals, mFirstPassUnknownOrQuestionable(EvalResult.Flags) ? ErrNum_None : ErrNum_OverRange, &ArgStr[3]))
      {
        PutCode((((LongWord)SrcAdrVals.Code) << 19)
            | (((LongWord)DestAdrVals.Code) << 14)
            | (Lo(Code) << 10)
            | (SizeCodeI(OpSize) << 8)
            | 0xce, 3);
        AppendIndex(&SrcAdrVals);
        AppendIndex(&DestAdrVals);
        AppendDisp(&SrcAdrVals);
        AppendDisp(&DestAdrVals);
        AppendDisp(&CntAdrVals);
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeINSS_EXTS(Word Code)
 * \brief  Handle INSS/EXTS Instructions (Format 7)
 * \param  Code machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeINSS_EXTS(Word Code)
{
  tAdrVals Arg1AdrVals, Arg2AdrVals;

  if (ChkArgCnt(4, 4)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &Arg1AdrVals, MAllowReg | ((Lo(Code) == 2) ? MAllowImm : 0))
   && DecodeAdr(&ArgStr[2], &Arg2AdrVals, MAllowReg))
  {
    tEvalResult EvalResult;
    Byte Offs, Length;

    Offs = EvalStrIntExpressionWithResult(&ArgStr[3], UInt3, &EvalResult);
    if (!EvalResult.OK)
      return;

    Length = EvalStrIntExpressionWithResult(&ArgStr[4], UInt5, &EvalResult);
    if (!EvalResult.OK)
      return;
    if (mFirstPassUnknownOrQuestionable(EvalResult.Flags))
      Length = (Length & 31) + 1;
    if (ChkRange(Length, 1, 32))
    {
      PutCode((((LongWord)Arg1AdrVals.Code) << 19)
            | (((LongWord)Arg2AdrVals.Code) << 14)
            | (SizeCodeI(OpSize) << 8)
            | (Lo(Code) << 10)
            | 0xce, 3);
      AppendIndex(&Arg1AdrVals);
      AppendIndex(&Arg2AdrVals);
      AppendDisp(&Arg1AdrVals);
      AppendDisp(&Arg2AdrVals);
      BAsmCode[CodeLen++] = ((Offs & 7) << 5) | ((Length - 1) & 31);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVExt(Word Code)
 * \brief  Decode MOV{X|Z}{BW|BD|WD} Instructions (Format 7)
 * \param  Code machine code & operand sizes
 * ------------------------------------------------------------------------ */

static void DecodeMOVExt(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Byte SrcOpSize = (Code >> 8) & 15,
       DestOpSize = (Code >> 12) & 15;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSize((tSymbolSize)SrcOpSize, &OpPart)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm))
  {
    OpSize = (tSymbolSize)DestOpSize;

    if (DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
    {
      Code = ((DestOpSize == eSymbolSize32Bit) ? 6 : 5) ^ (Code & 1);
      PutCode((((LongWord)SrcAdrVals.Code) << 19)
            | (((LongWord)DestAdrVals.Code) << 14)
            | (Code << 10)
            | (((LongWord)SrcOpSize) << 8)
            | 0xce, 3);
      AppendIndex(&SrcAdrVals);
      AppendIndex(&DestAdrVals);
      AppendDisp(&SrcAdrVals);
      AppendDisp(&DestAdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeDoubleDest(Word Code)
 * \brief  handle instruction with double-sized dest operand (Format 8)
 * \param  Code machine code
 * ------------------------------------------------------------------------ */

static void DecodeDoubleDest(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowRegPair))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0xce, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCHECK_INDEX(Word Code)
 * \brief  Handle CHECK/CVTP/INDEX Instructions (Format 8)
 * \param  Code machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeCHECK_INDEX(Word Code)
{
  tAdrVals BoundsAdrVals, SrcAdrVals;
  Word DestReg;
  Boolean IsINDEX = Lo(Code) == 0x42,
          IsCVTP = Lo(Code) == 0x06;


  if (ChkArgCnt(3, 3)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &BoundsAdrVals, IsINDEX ? (MAllowReg | MAllowImm) : 0)
   && DecodeAdr(&ArgStr[3], &SrcAdrVals, MAllowReg | (IsCVTP ? 0 : MAllowImm))
   && DecodeReg(&ArgStr[1], &DestReg, NULL, eSymbolSize32Bit, True))
  {
    PutCode((((LongWord)BoundsAdrVals.Code) << 19)
        | (((LongWord)SrcAdrVals.Code) << 14)
        | (DestReg << 11)
        | (SizeCodeI(OpSize) << 8)
        | (Lo(Code) << 4)
        | 0x0e, 3);
    AppendIndex(&BoundsAdrVals);
    AppendIndex(&SrcAdrVals);
    AppendDisp(&BoundsAdrVals);
    AppendDisp(&SrcAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeINS_EXT(Word Code)
 * \brief  Handle INS/EXT Instructions (Format 8)
 * \param  IsINS 1 for INS, 0 for EXT
 * ------------------------------------------------------------------------ */

static void DecodeINS_EXT(Word IsINS)
{
  tAdrVals Arg2AdrVals, Arg3AdrVals;
  Word OffsetReg;

  if (ChkArgCnt(4, 4)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(IsINS)
   && DecodeReg(&ArgStr[1], &OffsetReg, NULL, eSymbolSize32Bit, True)
   && DecodeAdr(&ArgStr[2], &Arg2AdrVals, MAllowReg | (Lo(IsINS) ? MAllowImm : 0))
   && DecodeAdr(&ArgStr[3], &Arg3AdrVals, MAllowReg))
  {
    tEvalResult EvalResult;
    LongInt Disp = EvalStrIntExpressionWithResult(&ArgStr[4], SInt30, &EvalResult);

    if (EvalResult.OK)
    {
      tAdrVals DispAdrVals;

      ClearAdrVals(&DispAdrVals);
      if (EncodeDisplacement(Disp, &DispAdrVals, ErrNum_OverRange, &ArgStr[4]))
      {
        PutCode((((LongWord)Arg2AdrVals.Code) << 19)
              | (((LongWord)Arg3AdrVals.Code) << 14)
              | (OffsetReg << 11)
              | (SizeCodeI(OpSize) << 8)
              | (Lo(IsINS) << 7)
              | 0x2e, 3);
        AppendIndex(&Arg2AdrVals);
        AppendIndex(&Arg3AdrVals);
        AppendDisp(&Arg2AdrVals);
        AppendDisp(&Arg3AdrVals);
        AppendDisp(&DispAdrVals);
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFFS(Word Code)
 * \brief  Handle FFS Instruction
 * \param  Code machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeFFS(Word Code)
{
  tAdrVals BaseAdrVals, OffsetAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &BaseAdrVals, MAllowReg | MAllowImm)
   && DecodeAdr(&ArgStr[2], &OffsetAdrVals, MAllowReg))
  {
    PutCode((((LongWord)BaseAdrVals.Code) << 19)
          | (((LongWord)OffsetAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x6e, 3);
    AppendIndex(&BaseAdrVals);
    AppendIndex(&OffsetAdrVals);
    AppendDisp(&BaseAdrVals);
    AppendDisp(&OffsetAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVSU(Word Code)
 * \brief  Handle MOVSU/MOVUS Instruction
 * \param  Code machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeMOVSU(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckSup(True, &OpPart)
   && CheckCore((1 << eCoreGen1) | (1 << eCoreGen2))
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, 0)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, 0))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | ((Code & 0xff) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0xae, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFLOOR_ROUND_TRUNC(Word Code)
 * \brief  Handle FLOOR.../ROUND.../TRUNC... instructions (Format 9)
 * \param  Code machine code & (integer) op size
 * ------------------------------------------------------------------------ */

static void DecodeFLOOR_ROUND_TRUNC(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckFPUAvail(eFPU16081)
   && SetFOpSizeFromCode(Code & 0x1)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x3e, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVif(Word Code)
 * \brief  Handle MOV i->f Instructions (Format 9)
 * \param  Code machine code & (integer) op size
 * ------------------------------------------------------------------------ */

static void DecodeMOVif(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckFPUAvail(eFPU16081)
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetFOpSizeFromCode(Code & 0x1)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | ((Code & 0xff) << 10)
          | (SizeCodeI(GetOpSizeFromCode(Code)) << 8)
          | 0x3e, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormatLFSR_SFSR(Word Code)
 * \brief  Handle LFSR/SFSR Instructions (Format 9)
 * \param  Code Machine Code & Flags
 * ------------------------------------------------------------------------ */

#define FMT9_MAYIMM (1 << 15)

static void DecodeLFSR_SFSR(Word Code)
{
  Boolean MayImm = !!(Code & FMT9_MAYIMM);
  tAdrVals AdrVals;

  Code &= ~FMT9_MAYIMM;
  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && CheckFPUAvail(eFPU16081)
   && SetOpSize(eSymbolSize32Bit, &OpPart)
   && DecodeAdr(&ArgStr[1], &AdrVals, MAllowReg | (MayImm ? MAllowImm : 0)))
  {
    PutCode((((LongWord)AdrVals.Code) << (MayImm ? 19 : 14))
          | (((LongWord)Code) << 8)
          | 0x3e, 3);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeMOVF(Word Code)
 * \brief  Handle MOVFL/MOVLF Instructions (Format 9)
 * \param  Code Machine Code & Flags
 * ------------------------------------------------------------------------ */

static void DecodeMOVF(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Byte OpSize = (Code >> 8) & 1;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckFPUAvail(eFPU16081)
   && SetFOpSizeFromCode(OpSize)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetFOpSizeFromCode(OpSize ^ 1)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | Code, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat11(Word Code)
 * \brief  Handle Format 11 Instructions
 * \param  Code Machine Code & Operand Size
 * ------------------------------------------------------------------------ */

#define FMT11_DESTMAYIMM 0x80

static void DecodeFormat11(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Boolean DestMayImm = !!(Code & FMT11_DESTMAYIMM);

  Code &= ~FMT11_DESTMAYIMM;
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckFPUAvail(eFPU16081)
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg | (DestMayImm ? MAllowImm : 0)))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | ((Code & 0xff) << 10)
          | (SizeCodeF(OpSize) << 8)
          | 0xbe, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat12(Word Code)
 * \brief  Handle Format 12 Instructions
 * \param  Code Machine Code & Operand Size
 * ------------------------------------------------------------------------ */

#define FMT12_DESTMAYIMM 0x40
#define FMT12_580 0x20

static void DecodeFormat12(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Boolean DestMayImm = !!(Code & FMT12_DESTMAYIMM),
          Req580 = !!(Code & FMT12_580);

  Code &= ~(FMT12_DESTMAYIMM | FMT12_580);
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckFPUAvail(Req580 ? eFPU32580 : eFPU32181)
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg | (DestMayImm ? MAllowImm : 0)))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | ((Code & 0xff) << 10)
          | (SizeCodeF(OpSize) << 8)
          | 0xfe, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeLMR_SMR(Word Code)
 * \brief  Decode LMR/SMR Instructions (Format 14)
 * \param  Code Machine Code & Operand Size
 * ------------------------------------------------------------------------ */

static void DecodeLMR_SMR(Word Code)
{
  tAdrVals AdrVals;
  Word Reg;
  Boolean IsStore = (Code == 3);

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckPMMUAvail()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &AdrVals, MAllowReg | (IsStore ? 0 : MAllowImm))
   && DecodeMMUReg(&ArgStr[1], &Reg))
  {
    if (!IsStore && (Reg >= 14))
      WrStrErrorPos(ErrNum_Unpredictable, &ArgStr[1]);
    PutCode((((LongWord)AdrVals.Code) << 19)
          | ((LongWord)Reg << 15)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x1e, 3);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRDVAL_WRVAL(Word Code)
 * \brief  Handle RDVAL/WRVAL Instructions
 * \param  Code Machine code & operand size
 * ------------------------------------------------------------------------ */

static void DecodeRDVAL_WRVAL(Word Code)
{
  tAdrVals AdrVals;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && CheckSup(True, &OpPart)
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &AdrVals, MAllowReg))
  {
    PutCode((((LongWord)AdrVals.Code) << 19)
        | (Lo(Code) << 10)
        | (SizeCodeI(OpSize) << 8)
        | 0x1e, 3);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCCVci(Word Code)
 * \brief  Handle CCVnci Instructions (Format 15.1)
 * \param  Code Machine code & (integer) operand size
 * ------------------------------------------------------------------------ */

static void DecodeCCVci(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckCustomAvail()
   && SetCOpSizeFromCode(Code & 0x01)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x36, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCCVic(Word Code)
 * \brief  Handle CCVnic Instructions (Format 15.1)
 * \param  Code Machine code & (integer) operand size
 * ------------------------------------------------------------------------ */

static void DecodeCCVic(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckCustomAvail()
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetCOpSizeFromCode(Code & 0x01)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeI(GetOpSizeFromCode(Code)) << 8)
          | 0x36, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCCVcc(Word Code)
 * \brief  Handle CCVncc Instructions (Format 15.1)
 * \param  Code Machine Code & Flags
 * ------------------------------------------------------------------------ */

static void DecodeCCVcc(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  Byte OpSize = Code & 1;

  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckCustomAvail()
   && SetCOpSizeFromCode(OpSize)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && ResetOpSize() && SetCOpSizeFromCode(OpSize ^ 1)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Code << 10)
          | 0x36, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCATST(Word Code)
 * \brief  Decode CATSTx Instructions (Format 15.0)
 * \param  Code Machine Code
 * ------------------------------------------------------------------------ */

static void DecodeCATST(Word Code)
{
  tAdrVals AdrVals;

  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && SetOpSize(eSymbolSize32Bit, &OpPart)
   && DecodeAdr(&ArgStr[1], &AdrVals, MAllowReg | MAllowImm))
  {
    PutCode((((LongWord)AdrVals.Code) << 19)
          | (Code << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x16, 3);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeLCR_SCR(Word Code)
 * \brief  Handle LCR/SCR Instructions (Format 15.0)
 * \param  Code Machine Code & Flags
 * ------------------------------------------------------------------------ */

#define FMT15_0_MAYIMM (1 << 7)

static void DecodeLCR_SCR(Word Code)
{
  Boolean MayImm = !!(Code & FMT15_0_MAYIMM);
  tAdrVals AdrVals;

  Code &= ~FMT15_0_MAYIMM;
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckCustomAvail()
   && CheckSup(True, &OpPart)
   && SetOpSize(eSymbolSize32Bit, &OpPart)
   && DecodeAdr(&ArgStr[2], &AdrVals, MAllowReg | (MayImm ? MAllowImm : 0)))
  {
    Boolean OK;
    LongWord Reg = EvalStrIntExpression(&ArgStr[1], UInt4, &OK);

    if (OK)
    {
      PutCode((((LongWord)AdrVals.Code) << 19)
           | (Reg << 15)
           | (Code << 10)
           |  (SizeCodeI(OpSize) << 8)
           | 0x16, 3);
      AppendIndex(&AdrVals);
      AppendDisp(&AdrVals);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormatLCSR_SCSR(Word Code)
 * \brief  Handle LCSR/SCSR Instructions (Format 15.1)
 * \param  Code Machine Code & Flags
 * ------------------------------------------------------------------------ */

#define FMT15_1_MAYIMM (1 << 7)

static void DecodeLCSR_SCSR(Word Code)
{
  Boolean MayImm = !!(Code & FMT15_1_MAYIMM);
  tAdrVals AdrVals;

  Code &= ~FMT15_1_MAYIMM;
  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && CheckCustomAvail()
   && SetOpSize(eSymbolSize32Bit, &OpPart)
   && DecodeAdr(&ArgStr[1], &AdrVals, MAllowReg | (MayImm ? MAllowImm : 0)))
  {
    PutCode((((LongWord)AdrVals.Code) << (MayImm ? 19 : 14))
          | (((LongWord)Code) << 10)
          | (SizeCodeI(OpSize) << 8)
          | 0x36, 3);
    AppendIndex(&AdrVals);
    AppendDisp(&AdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeFormat15_5_7(Word Code)
 * \brief  Handle Format 15.5/15.7 Instructions
 * \param  Code Machine code & operand size
 * ------------------------------------------------------------------------ */

#define FMT15_5_DESTMAYIMM 0x80
#define FMT15_7 0x40

static void DecodeFormat15_5_7(Word Code)
{
  tAdrVals SrcAdrVals, DestAdrVals;
  unsigned DestMayImm = (Code & FMT15_5_DESTMAYIMM) ? MAllowImm : 0,
           Is7 = !!(Code & FMT15_7);

  Code &= ~(FMT15_5_DESTMAYIMM | FMT15_7);
  if (ChkArgCnt(2, 2)
   && ChkNoAttrPart()
   && CheckCustomAvail()
   && (!Is7 || CheckCore((1 << eCoreGen1Ext) | (1 << eCoreGen2)))
   && SetOpSizeFromCode(Code)
   && DecodeAdr(&ArgStr[1], &SrcAdrVals, MAllowReg | MAllowImm)
   && DecodeAdr(&ArgStr[2], &DestAdrVals, MAllowReg| DestMayImm))
  {
    PutCode((((LongWord)SrcAdrVals.Code) << 19)
          | (((LongWord)DestAdrVals.Code) << 14)
          | (Lo(Code) << 10)
          | (SizeCodeC(OpSize) << 8)
          | (Is7 << 6)
          | 0xb6, 3);
    AppendIndex(&SrcAdrVals);
    AppendIndex(&DestAdrVals);
    AppendDisp(&SrcAdrVals);
    AppendDisp(&DestAdrVals);
  }
}

/*!------------------------------------------------------------------------
 * \fn     void CodeFPU(Word Code)
 * \brief  Handle FPU Instruction
 * ------------------------------------------------------------------------ */

static void CodeFPU(Word Code)
{
  UNUSED(Code);

  if (ChkArgCnt(1, 1))
  {
    if (!as_strcasecmp(ArgStr[1].str.p_str, "OFF"))
    {
      SetFlag(&FPUAvail, FPUAvailName, False);
      SetMomFPU(eFPUNone);
    }
    else if (!as_strcasecmp(ArgStr[1].str.p_str, "ON"))
    {
      SetFlag(&FPUAvail, FPUAvailName, True);
      if (!MomFPU)
        SetMomFPU((tFPU)pCurrCPUProps->DefFPU);
    }
    else
    {
      tFPU FPU;

      for (FPU = (tFPU)1; FPU < eFPUCount; FPU++)
        if (!as_strcasecmp(ArgStr[1].str.p_str, FPUNames[FPU]))
        {
          SetFlag(&FPUAvail, FPUAvailName, True);
          SetMomFPU(FPU);
          break;
        }
      if (FPU >= eFPUCount)
        WrStrErrorPos(ErrNum_InvFPUType, &ArgStr[1]);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     void CodePMMU(Word Code)
 * \brief  Handle PMMU Instruction
 * ------------------------------------------------------------------------ */

static void CodePMMU(Word Code)
{
  UNUSED(Code);

  if (ChkArgCnt(1, 1))
  {
    if (!as_strcasecmp(ArgStr[1].str.p_str, "OFF"))
    {
      SetFlag(&PMMUAvail, PMMUAvailName, False);
      SetMomPMMU(ePMMUNone);
    }
    else if (!as_strcasecmp(ArgStr[1].str.p_str, "ON"))
    {
      SetFlag(&PMMUAvail, PMMUAvailName, True);
      if (!MomPMMU)
        SetMomPMMU((tPMMU)pCurrCPUProps->DefPMMU);
    }
    else
    {
      tPMMU PMMU;

      for (PMMU = (tPMMU)1; PMMU < ePMMUCount; PMMU++)
        if (!as_strcasecmp(ArgStr[1].str.p_str, PMMUNames[PMMU]))
        {
          SetFlag(&PMMUAvail, PMMUAvailName, True);
          SetMomPMMU(PMMU);
          break;
        }
      if (PMMU >= ePMMUCount)
        WrStrErrorPos(ErrNum_InvPMMUType, &ArgStr[1]);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBB(Word Code)
 * \brief  Handle BitBLT Instructions
 * \param  Code Machine Code & Options
 * ------------------------------------------------------------------------ */

#define BB_NOOPT (1 << 15)

typedef struct
{
  char Name[3];
  Byte Pos, Value;
} tBitBltOpt;

static const tBitBltOpt BitBltOpts[] =
{
  { "DA" , 17, 1 },
  { "-S" , 15, 1 },
  { "IA" , 17, 0 },
  { "S"  , 15, 0 },
  { ""   , 0 , 0 }
};

static void DecodeBB(Word Code)
{
  if (ChkArgCnt(0, 2)
   && ChkNoAttrPart()
   && CheckCore(1 << eCoreGenE))
  {
    LongWord OpCode = 0x0e | ((LongWord)(Code & ~BB_NOOPT) << 8), OptMask = 0;
    tStrComp *pArg;
    const tBitBltOpt *pOpt;

    forallargs(pArg, True)
    {
      for (pOpt = BitBltOpts + ((Code & BB_NOOPT) ? 2 : 0); pOpt->Name[0]; pOpt++)
        if (!as_strcasecmp(pArg->str.p_str, pOpt->Name))
        {
          LongWord ThisMask = 1ul << pOpt->Pos;

          if (OptMask & ThisMask)
          {
            WrStrErrorPos(ErrNum_ConfBitBltOpt, pArg);
            return;
          }
          OptMask |= ThisMask;
          OpCode = pOpt->Value ? (OpCode | ThisMask) : (OpCode & ~ThisMask);
          break;
        }
      if (!pOpt->Name[0])
      {
        WrStrErrorPos(ErrNum_UnknownBitBltOpt, pArg);
        return;
      }
    }
    PutCode(OpCode, 3);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeBITxT(Word Code)
 * \brief  Handle BITBLT instructions without argument
 * \param  Code Machine Code
 * ------------------------------------------------------------------------ */

static void DecodeBITxT(Word Code)
{
  if (ChkArgCnt(0, 0)
   && ChkNoAttrPart()
   && CheckCore(1 << eCoreGenE))
    PutCode(((LongWord)Code) << 8 | 0x0e, 3);
}

/*!------------------------------------------------------------------------
 * \fn     DecodeTBITS(Word Code)
 * \brief  Handle TBITS Instruction
 * \param  Code Machine Code
 * ------------------------------------------------------------------------ */

static void DecodeTBITS(Word Code)
{
  if (ChkArgCnt(1, 1)
   && ChkNoAttrPart()
   && CheckCore(1 << eCoreGenE))
  {
    Boolean OK;
    LongWord Arg = EvalStrIntExpression(&ArgStr[1], UInt1, &OK);

    if (OK)
      PutCode((Arg << 15)
            | (((LongWord)Code) << 8)
            | 0x0e, 3);
  }
}

/*--------------------------------------------------------------------------*/
/* Instruction Lookup Table */

/*!------------------------------------------------------------------------
 * \fn     InitFields(void)
 * \brief  create lookup table
 * ------------------------------------------------------------------------ */

static void AddSizeInstTable(const char *pName, unsigned SizeMask, Word Code, InstProc Proc)
{
  char Name[20];
  tSymbolSize Size;

  for (Size = eSymbolSize8Bit; Size <= eSymbolSize32Bit; Size++)
    if (SizeMask & (1 << Size))
    {
      as_snprintf(Name, sizeof(Name), "%s%c", pName, "BWD"[Size - eSymbolSize8Bit]);
      AddInstTable(InstTable, Name, Code | (Size << 8), Proc);
    }
}

static void AddFSizeInstTable(const char *pName, unsigned SizeMask, Word Code, InstProc Proc)
{
  char Name[20];
  tSymbolSize Size;

  for (Size = eSymbolSizeFloat32Bit; Size <= eSymbolSizeFloat64Bit; Size++)
    if (SizeMask & (1 << Size))
    {
      as_snprintf(Name, sizeof(Name), "%s%c", pName, "FL"[Size - eSymbolSizeFloat32Bit]);
      AddInstTable(InstTable, Name, Code | (Size << 8), Proc);
    }
}

static void AddCSizeInstTable(const char *pName, unsigned SizeMask, Word Code, InstProc Proc)
{
  char Name[20];
  tSymbolSize Size;

  for (Size = eSymbolSize32Bit; Size <= eSymbolSize64Bit; Size++)
    if (SizeMask & (1 << Size))
    {
      as_snprintf(Name, sizeof(Name), "%s%c", pName, "DQ"[Size - eSymbolSize32Bit]);
      AddInstTable(InstTable, Name, Code | (Size << 8), Proc);
    }
}

static void AddCondition(const char *pCondition, Word Code)
{
  char Str[20];

  as_snprintf(Str, sizeof(Str), "B%s", pCondition);
  AddInstTable(InstTable, Str, (Code << 4) | 0x0a, DecodeFormat0);
  as_snprintf(Str, sizeof(Str), "S%s", pCondition);
  AddSizeInstTable(Str, (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), Code, DecodeScond);
}

static void AddCtl(const char *pName, Word Code, Boolean Privileged)
{
  order_array_rsv_end(CtlRegs, tCtlReg);
  CtlRegs[InstrZ  ].pName      = pName;
  CtlRegs[InstrZ  ].Code       = Code;
  CtlRegs[InstrZ++].Privileged = Privileged;
}

static void AddMMU(const char *pName, Word Code, Word Mask, Boolean Privileged)
{
  order_array_rsv_end(MMURegs, tCtlReg);
  MMURegs[InstrZ  ].pName      = pName;
  MMURegs[InstrZ  ].Code       = Code;
  MMURegs[InstrZ  ].Mask       = Mask;
  MMURegs[InstrZ++].Privileged = Privileged;
}

static void InitFields(void)
{
  InstTable = CreateInstTable(605);
  SetDynamicInstTable(InstTable);

  add_null_pseudo(InstTable);

  InstrZ = 0;
  AddCtl("UPSR"   , 0x00, True );
  AddCtl("DCR"    , 0x01, True );
  AddCtl("BPC"    , 0x02, True );
  AddCtl("DSR"    , 0x03, True );
  AddCtl("CAR"    , 0x04, True );
  AddCtl("FP"     , 0x08, False);
  AddCtl("SP"     , 0x09, False);
  AddCtl("SB"     , 0x0a, False);
  AddCtl("USP"    , 0x0b, True );
  AddCtl("CFG"    , 0x0c, True );
  AddCtl("PSR"    , 0x0d, False);
  AddCtl("INTBASE", 0x0e, True );
  AddCtl("MOD"    , 0x0f, False);
  AddCtl(NULL     , 0   , False);

  InstrZ = 0;
  AddMMU("BPR0"   , 0x00, (1 << ePMMU16082) | (1 << ePMMU32082)                                        , True );
  AddMMU("BPR1"   , 0x01, (1 << ePMMU16082) | (1 << ePMMU32082)                                        , True );
  AddMMU("MSR"    , 0x0a, (1 << ePMMU16082) | (1 << ePMMU32082)                     | (1 << ePMMU32532), True );
  AddMMU("BCNT"   , 0x0b, (1 << ePMMU16082) | (1 << ePMMU32082)                                        , True );
  AddMMU("PTB0"   , 0x0c, (1 << ePMMU16082) | (1 << ePMMU32082) | (1 << ePMMU32382) | (1 << ePMMU32532), True );
  AddMMU("PTB1"   , 0x0d, (1 << ePMMU16082) | (1 << ePMMU32082) | (1 << ePMMU32382) | (1 << ePMMU32532), True );
  AddMMU("EIA"    , 0x0f, (1 << ePMMU16082) | (1 << ePMMU32082)                                        , True );
  AddMMU("BAR"    , 0x00,                                         (1 << ePMMU32382)                    , True );
  AddMMU("BMR"    , 0x02,                                         (1 << ePMMU32382)                    , True );
  AddMMU("BDR"    , 0x03,                                         (1 << ePMMU32382)                    , True );
  AddMMU("BEAR"   , 0x06,                                         (1 << ePMMU32382)                    , True );
  AddMMU("FEW"    , 0x09,                                         (1 << ePMMU32382)                    , True );
  AddMMU("ASR"    , 0x0a,                                         (1 << ePMMU32382)                    , True );
  AddMMU("TEAR"   , 0x0b,                                         (1 << ePMMU32382) | (1 << ePMMU32532), True );
  /* TODO: 8 according to National docu, but 9 according to sample code */
  AddMMU("MCR"    , 0x09,                                                             (1 << ePMMU32532), True );
  AddMMU("IVAR0"  , 0x0e,                                         (1 << ePMMU32382) | (1 << ePMMU32532), True );/* w/o */
  AddMMU("IVAR1"  , 0x0f,                                         (1 << ePMMU32382) | (1 << ePMMU32532), True );/* w/o */
  AddMMU(NULL     , 0, 0, False);

  AddCondition("EQ",  0);
  AddCondition("NE",  1);
  AddCondition("CS",  2);
  AddCondition("CC",  3);
  AddCondition("HI",  4);
  AddCondition("LS",  5);
  AddCondition("GT",  6);
  AddCondition("LE",  7);
  AddCondition("FS",  8);
  AddCondition("FC",  9);
  AddCondition("LO", 10);
  AddCondition("HS", 11);
  AddCondition("LT", 12);
  AddCondition("GE", 13);

  /* Format 0 */

  AddInstTable(InstTable, "BR" , 0xea, DecodeFormat0);
  AddInstTable(InstTable, "BSR", 0x02, DecodeFormat0);

  /* Format 1 */

  AddInstTable(InstTable, "BPT" , 0xf2, DecodeFixed);
  AddInstTable(InstTable, "DIA" , 0xc2, DecodeFixed);
  AddInstTable(InstTable, "FLAG", 0xd2, DecodeFixed);
  AddInstTable(InstTable, "NOP" , NOPCode, DecodeFixed);
  AddInstTable(InstTable, "RETI", 0x52, DecodeFixed);
  AddInstTable(InstTable, "SVC" , 0xe2, DecodeFixed);
  AddInstTable(InstTable, "WAIT", 0xb2, DecodeFixed);
  AddInstTable(InstTable, "RET" , 0x12, DecodeRET);
  AddInstTable(InstTable, "RETT", 0x42, DecodeRET);
  AddInstTable(InstTable, "RXP" , 0x32, DecodeRET);
  AddInstTable(InstTable, "SAVE", 0x62, DecodeSAVE_RESTORE);
  AddInstTable(InstTable, "RESTORE", 0x72, DecodeSAVE_RESTORE);

  AddInstTable(InstTable, "CINV", 0x271e, DecodeCINV);
  AddInstTable(InstTable, "CXP" , 0x22, DecodeCXP);
  AddInstTable(InstTable, "ENTER", 0x82, DecodeENTER);
  AddInstTable(InstTable, "EXIT", 0x92, DecodeEXIT);

  /* Format 2 */

  AddSizeInstTable("ADDQ" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0, DecodeMOVQ);
  AddSizeInstTable("LPR"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 6, DecodeLPR_SPR);
  AddSizeInstTable("SPR"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 2, DecodeLPR_SPR);
  AddSizeInstTable("MOVQ" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 5, DecodeMOVQ);
  AddSizeInstTable("ACB"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 4, DecodeACB);
  AddSizeInstTable("CMPQ" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 1 | MOVQ_DESTMAYIMM, DecodeMOVQ);

  /* Format 3 */

  AddInstTable(InstTable, "JUMP"  , 0x04 | (eSymbolSize32Bit << 8), DecodeFormat3);
  AddInstTable(InstTable, "JSR"   , 0x0c | (eSymbolSize32Bit << 8), DecodeFormat3);
  AddSizeInstTable("ADJSP" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0a, DecodeFormat3);
  AddSizeInstTable("BICPSR", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit), 0x02, DecodeFormat3);
  AddSizeInstTable("BISPSR", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit), 0x06, DecodeFormat3);
  AddSizeInstTable("CASE"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeFormat3);
  AddInstTable(InstTable, "CXPD"  , 0x00 | (eSymbolSize32Bit << 8), DecodeFormat3);

  /* Format 4 */

  AddSizeInstTable("MOV" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x05, DecodeFormat4);
  AddSizeInstTable("ADD" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x00, DecodeFormat4);
  AddSizeInstTable("ADDC", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x04, DecodeFormat4);
  AddInstTable(InstTable, "ADDR", (eSymbolSize32Bit << 8) | FMT4_SRCISADDR | 0x09, DecodeFormat4);
  AddSizeInstTable("AND" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0a, DecodeFormat4);
  AddSizeInstTable("BIC" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x02, DecodeFormat4);
  AddSizeInstTable("CMP" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), FMT4_DESTMAYIMM | 0x01, DecodeFormat4);
  AddSizeInstTable("OR"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x06, DecodeFormat4);
  AddSizeInstTable("SUB" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x08, DecodeFormat4);
  AddSizeInstTable("SUBC", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0c, DecodeFormat4);
  AddSizeInstTable("TBIT", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0d, DecodeFormat4);
  AddSizeInstTable("XOR" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeFormat4);

  /* Format 5 */

  AddSizeInstTable("MOVS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x00, DecodeMOVS_CMPS_SKPS);
  AddSizeInstTable("CMPS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x01, DecodeMOVS_CMPS_SKPS);
  AddSizeInstTable("SKPS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x03, DecodeMOVS_CMPS_SKPS);
  AddInstTable(InstTable, "MOVST", (eSymbolSize8Bit << 8) | 0x20, DecodeMOVS_CMPS_SKPS);
  AddInstTable(InstTable, "CMPST", (eSymbolSize8Bit << 8) | 0x21, DecodeMOVS_CMPS_SKPS);
  AddInstTable(InstTable, "SKPST", (eSymbolSize8Bit << 8) | 0x23, DecodeMOVS_CMPS_SKPS);
  AddInstTable(InstTable, "SETCFG", 0xb0e, DecodeSETCFG);

  /* Format 6 */

  AddSizeInstTable("ABS"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0c, DecodeFormat6);
  AddSizeInstTable("ADDP"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0f, DecodeFormat6);
  AddSizeInstTable("ASH"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), FMT6_SRC8BIT | 0x01, DecodeFormat6);
  AddSizeInstTable("CBIT"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x02, DecodeFormat6);
  AddSizeInstTable("CBITI" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x03, DecodeFormat6);
  AddSizeInstTable("COM"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0d, DecodeFormat6);
  AddSizeInstTable("IBIT"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeFormat6);
  AddSizeInstTable("LSH"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), FMT6_SRC8BIT | 0x05, DecodeFormat6);
  AddSizeInstTable("NEG"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x08, DecodeFormat6);
  AddSizeInstTable("NOT"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x09, DecodeFormat6);
  AddSizeInstTable("ROT"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), FMT6_SRC8BIT | 0x00, DecodeFormat6);
  AddSizeInstTable("SBIT"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x06, DecodeFormat6);
  AddSizeInstTable("SBITI" , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x07, DecodeFormat6);
  AddSizeInstTable("SUBP"  , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0b, DecodeFormat6);

  /* Format 7 */

  AddSizeInstTable("DIV"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0f, DecodeFormat7);
  AddSizeInstTable("MOD"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeFormat7);
  AddSizeInstTable("MUL"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x08, DecodeFormat7);
  AddSizeInstTable("QUO"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0c, DecodeFormat7);
  AddSizeInstTable("REM"   , (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0d, DecodeFormat7);

  AddInstTable(InstTable, "MOVXBW", (eSymbolSize8Bit  << 8) | (eSymbolSize16Bit << 12) | 1, DecodeMOVExt);
  AddInstTable(InstTable, "MOVXBD", (eSymbolSize8Bit  << 8) | (eSymbolSize32Bit << 12) | 1, DecodeMOVExt);
  AddInstTable(InstTable, "MOVXWD", (eSymbolSize16Bit << 8) | (eSymbolSize32Bit << 12) | 1, DecodeMOVExt);
  AddInstTable(InstTable, "MOVZBW", (eSymbolSize8Bit  << 8) | (eSymbolSize16Bit << 12) | 0, DecodeMOVExt);
  AddInstTable(InstTable, "MOVZBD", (eSymbolSize8Bit  << 8) | (eSymbolSize32Bit << 12) | 0, DecodeMOVExt);
  AddInstTable(InstTable, "MOVZWD", (eSymbolSize16Bit << 8) | (eSymbolSize32Bit << 12) | 0, DecodeMOVExt);

  AddSizeInstTable("MOVM", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x00, DecodeMOVM_CMPM);
  AddSizeInstTable("CMPM", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x01, DecodeMOVM_CMPM);

  AddSizeInstTable("DEI", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0b, DecodeDoubleDest);
  AddSizeInstTable("MEI", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x09, DecodeDoubleDest);

  AddSizeInstTable("EXTS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x03, DecodeINSS_EXTS);
  AddSizeInstTable("INSS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x02, DecodeINSS_EXTS);

  /* Format 8 */

  AddSizeInstTable("CHECK", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeCHECK_INDEX);
  AddInstTable(InstTable, "CVTP", (eSymbolSize32Bit << 8) | 0x06, DecodeCHECK_INDEX);
  AddSizeInstTable("INDEX", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x42, DecodeCHECK_INDEX);

  AddSizeInstTable("EXT", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0, DecodeINS_EXT);
  AddSizeInstTable("INS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 1, DecodeINS_EXT);

  AddSizeInstTable("FFS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x01, DecodeFFS);

  AddSizeInstTable("MOVSU", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x3, DecodeMOVSU);
  AddSizeInstTable("MOVUS", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x7, DecodeMOVSU);

  /* Format 9 */

  AddSizeInstTable("FLOORF", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0f, DecodeFLOOR_ROUND_TRUNC);
  AddSizeInstTable("FLOORL", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeFLOOR_ROUND_TRUNC);
  AddSizeInstTable("ROUNDF", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x09, DecodeFLOOR_ROUND_TRUNC);
  AddSizeInstTable("ROUNDL", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x08, DecodeFLOOR_ROUND_TRUNC);
  AddSizeInstTable("TRUNCF", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0b, DecodeFLOOR_ROUND_TRUNC);
  AddSizeInstTable("TRUNCL", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0a, DecodeFLOOR_ROUND_TRUNC);
  AddInstTable(InstTable, "MOVBF", 0x01 | (eSymbolSize8Bit << 8), DecodeMOVif);
  AddInstTable(InstTable, "MOVWF", 0x01 | (eSymbolSize16Bit << 8), DecodeMOVif);
  AddInstTable(InstTable, "MOVDF", 0x01 | (eSymbolSize32Bit << 8), DecodeMOVif);
  AddInstTable(InstTable, "MOVBL", 0x00 | (eSymbolSize8Bit << 8), DecodeMOVif);
  AddInstTable(InstTable, "MOVWL", 0x00 | (eSymbolSize16Bit << 8), DecodeMOVif);
  AddInstTable(InstTable, "MOVDL", 0x00 | (eSymbolSize32Bit << 8), DecodeMOVif);

  AddInstTable(InstTable, "LFSR", 0x0f | FMT9_MAYIMM, DecodeLFSR_SFSR);
  AddInstTable(InstTable, "SFSR", 0x37, DecodeLFSR_SFSR);

  AddInstTable(InstTable, "MOVFL"  , 0x1b3e, DecodeMOVF);
  AddInstTable(InstTable, "MOVLF"  , 0x163e, DecodeMOVF);

  /* Format 11 */

  AddFSizeInstTable("ABS", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x0d, DecodeFormat11);
  AddFSizeInstTable("ADD", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x00, DecodeFormat11);
  AddFSizeInstTable("CMP", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x02 | FMT11_DESTMAYIMM, DecodeFormat11);
  AddFSizeInstTable("DIV", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x08, DecodeFormat11);
  AddFSizeInstTable("MOV", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x01, DecodeFormat11);
  AddFSizeInstTable("MUL", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x0c, DecodeFormat11);
  AddFSizeInstTable("NEG", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x05, DecodeFormat11);
  AddFSizeInstTable("SUB", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x04, DecodeFormat11);

  /* Format 12 - only newer FPUs? */

  AddFSizeInstTable("DOT"  , (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x03 | FMT12_DESTMAYIMM, DecodeFormat12);
  AddFSizeInstTable("LOGB" , (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x05, DecodeFormat12);
  AddFSizeInstTable("POLY" , (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x02 | FMT12_DESTMAYIMM, DecodeFormat12);
  AddFSizeInstTable("SCALB", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x04, DecodeFormat12);
  AddFSizeInstTable("REM"  , (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), 0x00, DecodeFormat12);
  AddFSizeInstTable("SQRT" , (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), FMT12_580 | 0x01, DecodeFormat12);
  AddFSizeInstTable("ATAN2", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), FMT12_580 | 0x0c, DecodeFormat12);
  AddFSizeInstTable("SICOS", (1 << eSymbolSizeFloat32Bit) | (1 << eSymbolSizeFloat64Bit), FMT12_580 | 0x0d, DecodeFormat12);

  /* Format 14 */

  AddInstTable(InstTable, "LMR"  , 0x02 | (eSymbolSize32Bit << 8), DecodeLMR_SMR);
  AddInstTable(InstTable, "SMR"  , 0x03 | (eSymbolSize32Bit << 8), DecodeLMR_SMR);
  AddInstTable(InstTable, "RDVAL", 0x00 | (eSymbolSize32Bit << 8), DecodeRDVAL_WRVAL);
  AddInstTable(InstTable, "WRVAL", 0x01 | (eSymbolSize32Bit << 8), DecodeRDVAL_WRVAL);

  AddInstTable(InstTable, "REG" , 0, CodeREG);
  AddInstTable(InstTable, "BYTE"   , eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString , DecodeIntelDB);
  AddInstTable(InstTable, "WORD"   , eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString , DecodeIntelDW);
  AddInstTable(InstTable, "DOUBLE" , eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString , DecodeIntelDD);
  AddInstTable(InstTable, "FLOAT"  , eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowFloat , DecodeIntelDD);
  AddInstTable(InstTable, "LONG"   , eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowFloat , DecodeIntelDQ);
  AddInstTable(InstTable, "FPU"    , 0, CodeFPU);
  AddInstTable(InstTable, "PMMU"   , 0, CodePMMU);

  /* Format 15.0 */

  AddInstTable(InstTable, "LCR", 0x0a | FMT15_0_MAYIMM, DecodeLCR_SCR);
  AddInstTable(InstTable, "SCR", 0x0b                 , DecodeLCR_SCR);
  AddInstTable(InstTable, "CATST0", 0x00, DecodeCATST);
  AddInstTable(InstTable, "CATST1", 0x01, DecodeCATST);

  /* Format 15.1 */

  AddSizeInstTable("CCV0Q", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0e, DecodeCCVci);
  AddSizeInstTable("CCV0D", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0f, DecodeCCVci);
  AddSizeInstTable("CCV1Q", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0a, DecodeCCVci);
  AddSizeInstTable("CCV1D", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x0b, DecodeCCVci);
  AddSizeInstTable("CCV2Q", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x08, DecodeCCVci);
  AddSizeInstTable("CCV2D", (1 << eSymbolSize8Bit) | (1 << eSymbolSize16Bit) | (1 << eSymbolSize32Bit), 0x09, DecodeCCVci);
  AddInstTable(InstTable, "CCV3BQ", (eSymbolSize8Bit  << 8) | 0x00, DecodeCCVic);
  AddInstTable(InstTable, "CCV3WQ", (eSymbolSize16Bit << 8) | 0x00, DecodeCCVic);
  AddInstTable(InstTable, "CCV3DQ", (eSymbolSize32Bit << 8) | 0x00, DecodeCCVic);
  AddInstTable(InstTable, "CCV3BD", (eSymbolSize8Bit  << 8) | 0x01, DecodeCCVic);
  AddInstTable(InstTable, "CCV3WD", (eSymbolSize16Bit << 8) | 0x01, DecodeCCVic);
  AddInstTable(InstTable, "CCV3DD", (eSymbolSize32Bit << 8) | 0x01, DecodeCCVic);
  AddInstTable(InstTable, "CCV4DQ", 0x07, DecodeCCVcc);
  AddInstTable(InstTable, "CCV5QD", 0x04, DecodeCCVcc);
  AddInstTable(InstTable, "LCSR", 0x01 | FMT15_1_MAYIMM, DecodeLCSR_SCSR);
  AddInstTable(InstTable, "SCSR", 0x06, DecodeLCSR_SCSR);

  /* Format 15.5/15.7 */

  AddCSizeInstTable("CCAL0", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x00, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV0", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x01, DecodeFormat15_5_7);
  AddCSizeInstTable("CCMP" , (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_5_DESTMAYIMM | 0x02, DecodeFormat15_5_7);
  AddCSizeInstTable("CCMP1", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_5_DESTMAYIMM | 0x03, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL1", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x04, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV2", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x05, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL3", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x08, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV3", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x09, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL2", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x0c, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV1", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), 0x0d, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL4", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x00, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV4", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x01, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL8", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x02, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL9", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x03, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL5", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x04, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV6", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x05, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL7", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x08, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV7", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x09, DecodeFormat15_5_7);
  AddCSizeInstTable("CCAL6", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x0c, DecodeFormat15_5_7);
  AddCSizeInstTable("CMOV5", (1 << eSymbolSize32Bit) | (1 << eSymbolSize64Bit), FMT15_7 | 0x0d, DecodeFormat15_5_7);

  /* BITBLT */

  AddInstTable(InstTable, "BBAND"  , 0x12b, DecodeBB);
  AddInstTable(InstTable, "BBOR"   , 0x019, DecodeBB);
  AddInstTable(InstTable, "BBXOR"  , 0x039, DecodeBB);
  AddInstTable(InstTable, "BBFOR"  , BB_NOOPT | 0x031, DecodeBB);
  AddInstTable(InstTable, "BBSTOD" , 0x011, DecodeBB);

  AddInstTable(InstTable, "BITWT"  , 0x21, DecodeBITxT);
  AddInstTable(InstTable, "EXTBLT" , 0x17, DecodeBITxT);
  AddInstTable(InstTable, "MOVMPB" , 0x1c, DecodeBITxT);
  AddInstTable(InstTable, "MOVMPW" , 0x1d, DecodeBITxT);
  AddInstTable(InstTable, "MOVMPD" , 0x1f, DecodeBITxT);
  AddInstTable(InstTable, "SBITS"  , 0x37, DecodeBITxT);
  AddInstTable(InstTable, "SBITPS" , 0x2f, DecodeBITxT);

  AddInstTable(InstTable, "TBITS"  , 0x27, DecodeTBITS);

  AddIntelPseudo(InstTable, eIntPseudoFlag_DynEndian);
}

/*!------------------------------------------------------------------------
 * \fn     DeinitFields(void)
 * \brief  destroy/cleanup lookup table
 * ------------------------------------------------------------------------ */

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(CtlRegs);
  order_array_free(MMURegs);
}

/*--------------------------------------------------------------------------*/
/* Interface Functions */

/*!------------------------------------------------------------------------
 * \fn     MakeCode_NS32K(void)
 * \brief  encode machine instruction
 * ------------------------------------------------------------------------ */

static void MakeCode_NS32K(void)
{
  OpSize = eSymbolSizeUnknown;

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

/*!------------------------------------------------------------------------
 * \fn     InternSymbol_NS32K(char *pArg, TempResult *pResult)
 * \brief  handle built-in symbols on NS32000
 * \param  pArg source argument
 * \param  pResult result buffer
 * ------------------------------------------------------------------------ */

static void InternSymbol_NS32K(char *pArg, TempResult *pResult)
{
  Word Reg;
  tSymbolSize Size;

  if (DecodeRegCore(pArg, &Reg, &Size))
  {
    pResult->Typ = TempReg;
    pResult->DataSize = Size;
    pResult->Contents.RegDescr.Reg = Reg;
    pResult->Contents.RegDescr.Dissect = DissectReg_NS32K;
    pResult->Contents.RegDescr.compare = NULL;
  }
}

/*!------------------------------------------------------------------------
 * \fn     InitCode_NS32K(void)
 * \brief  target-specific initializations before starting a pass
 * ------------------------------------------------------------------------ */

static void InitCode_NS32K(void)
{
  SetMomFPU(eFPUNone);
  SetMomPMMU(ePMMUNone);
}

/*!------------------------------------------------------------------------
 * \fn     IsDef_NS32K(void)
 * \brief  check whether insn makes own use of label
 * \return True if yes
 * ------------------------------------------------------------------------ */

static Boolean IsDef_NS32K(void)
{
  return Memo("REG");
}

/*!------------------------------------------------------------------------
 * \fn     SwitchTo_NS32K(void *pUser)
 * \brief  prepare to assemble code for this target
 * \param  pUser CPU properties
 * ------------------------------------------------------------------------ */

static Boolean ChkMoreZeroArg(void)
{
  return (ArgCnt > 0);
}

static void SwitchTo_NS32K(void *pUser)
{
  const TFamilyDescr *pDescr = FindFamilyByName("NS32000");

  TurnWords = True;
  SetIntConstMode(eIntConstModeIntel);
  SaveIsOccupiedFnc = ChkMoreZeroArg;
  RestoreIsOccupiedFnc = ChkMoreZeroArg;

  pCurrCPUProps = (const tCPUProps*)pUser;

  /* default selection of "typical" companion FPU/PMMU: */

  SetMomFPU((tFPU)pCurrCPUProps->DefFPU);
  SetMomPMMU((tPMMU)pCurrCPUProps->DefPMMU);

  PCSymbol = "*"; HeaderID = pDescr->Id;
  NOPCode = 0xa2;
  DivideChars = ",";
  HasAttrs = True; AttrChars = ".";

  ValidSegs = (1 << SegCode);
  Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  SegLimits[SegCode] = IntTypeDefs[pCurrCPUProps->MemIntType].Max;

  MakeCode = MakeCode_NS32K;
  IsDef = IsDef_NS32K;
  DissectReg = DissectReg_NS32K;
  InternSymbol = InternSymbol_NS32K;
  SwitchFrom = DeinitFields;
  IntConstModeIBMNoTerm = True;
  QualifyQuote = QualifyQuote_SingleQuoteConstant;
  InitFields();
  onoff_supmode_add();
  onoff_bigendian_add();
  if (!onoff_test_and_set(e_onoff_reg_custom))
    SetFlag(&CustomAvail, CustomAvailSymName, False);
  AddONOFF(CustomAvailCmdName, &CustomAvail, CustomAvailSymName, False);
}

/*!------------------------------------------------------------------------
 * \fn     codens32000_init(void)
 * \brief  register target to AS
 * ------------------------------------------------------------------------ */

static const tCPUProps CPUProps[] =
{
  { "NS16008", eCoreGen1   , eFPU16081, ePMMU16082, UInt24 },
  { "NS32008", eCoreGen1   , eFPU32081, ePMMU32082, UInt24 },
  { "NS08032", eCoreGen1   , eFPU32081, ePMMU32082, UInt24 },
  { "NS16032", eCoreGen1   , eFPU16081, ePMMU16082, UInt24 },
  { "NS32016", eCoreGen1   , eFPU32081, ePMMU32082, UInt24 },
  { "NS32032", eCoreGen1   , eFPU32081, ePMMU32082, UInt24 },
  { "NS32332", eCoreGen1Ext, eFPU32381, ePMMU32382, UInt32 },
  { "NS32CG16",eCoreGenE   , eFPU32181, ePMMU32082, UInt24 },
  { "NS32532", eCoreGen2   , eFPU32381, ePMMU32532, UInt32 },
  { NULL     , eCoreNone   , eFPUNone , ePMMUNone , UInt1  }
};

void codens32k_init(void)
{
  const tCPUProps *pRun;

  for (pRun = CPUProps; pRun->pName; pRun++)
    (void)AddCPUUser(pRun->pName, SwitchTo_NS32K, (void*)pRun, NULL);

  AddInitPassProc(InitCode_NS32K);
}
