/* codexa.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* AS-Codegenerator Philips XA                                               */
/*                                                                           */
/*****************************************************************************/

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

#include "nls.h"
#include "strutil.h"
#include "bpemu.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "asmitree.h"
#include "asmcode.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "motpseudo.h"
#include "codevars.h"
#include "assume.h"
#include "errmsg.h"
#include "headids.h"

#include "codexa.h"

/*-------------------------------------------------------------------------*/
/* Definitionen */

#define ModNone (-1)
#define ModReg 0
#define MModReg (1 << ModReg)
#define ModMem 1
#define MModMem (1 << ModMem)
#define ModImm 2
#define MModImm (1 << ModImm)
#define ModAbs 3
#define MModAbs (1 << ModAbs)

#define REG_SP 7

#define RETICode 0xd690

#define eSymbolSize5Bit ((tSymbolSize)-4)
#define eSymbolSizeSigned4Bit ((tSymbolSize)-3)
#define eSymbolSize4Bit ((tSymbolSize)-2)

typedef struct
{
  Byte SizeMask;
  Byte Code;
} RegOrder;

typedef struct
{
  const char *Name;
  Byte SizeMask;
  Byte Code;
  Byte Inversion;
} InvOrder;

static CPUVar CPUXAG1,CPUXAG2,CPUXAG3;

static InvOrder *JBitOrders;
static RegOrder *RegOrders;
static InvOrder *RelOrders;

static LongInt Reg_DS;

static ShortInt AdrMode;
static Byte AdrPart,MemPart;
static Byte AdrVals[4];
static tSymbolSize OpSize;
static Boolean DoBranchExt; /* automatically extend branches */

static as_assume_rec_t ASSUMEXAs[] =
{
  {"DS", &Reg_DS, 0, 0xff, 0x100, NULL}
};

/*-------------------------------------------------------------------------*/
/* Hilfsroutinen */

static void SetOpSize(tSymbolSize NSize)
{
  if (OpSize == eSymbolSizeUnknown) OpSize = NSize;
  else if (OpSize != NSize)
  {
    AdrMode = ModNone; AdrCnt = 0; WrError(ErrNum_ConfOpSizes);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRegCore(const char *pArg, tSymbolSize *pSize, Byte *pResult)
 * \brief  check whether argument is a CPU register
 * \param  pArg source argument
 * \param  pSize register size if yes
 * \param  pResult register number if yes
 * \return Reg eval result
 * ------------------------------------------------------------------------ */

static tRegEvalResult DecodeRegCore(const char *pArg, tSymbolSize *pSize, Byte *pResult)
{
  int len;

  if (!as_strcasecmp(pArg, "SP"))
  {
    *pResult = REG_SP | REGSYM_FLAG_ALIAS;
    *pSize = eSymbolSize16Bit;
    return eIsReg;
  }

  len = strlen(pArg);
  if ((len >= 2) && (as_toupper(*pArg) == 'R') && (pArg[1] >= '0') && (pArg[1] <= '7'))
  {
    *pResult = pArg[1] - '0';
    if (len == 2)
    {
      if (OpSize == eSymbolSize32Bit)
      {
        *pSize = eSymbolSize32Bit;
        if (*pResult & 1)
        {
          WrError(ErrNum_InvRegPair);
          (*pResult)--;
          return eRegAbort;
        }
        else
          return eIsReg;
      }
      else
      {
        *pSize = eSymbolSize16Bit;
        return eIsReg;
      }
    }
    else if ((len == 3) && (as_toupper(pArg[2]) == 'L'))
    {
      *pResult <<= 1;
      *pSize = eSymbolSize8Bit;
      return eIsReg;
    }
    else if ((len == 3) && (as_toupper(pArg[2]) == 'H'))
    {
      *pResult = (*pResult << 1) + 1;
      *pSize = eSymbolSize8Bit;
      return eIsReg;
    }
    else
      return eIsNoReg;
  }
  return eIsNoReg;
}

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

static void DissectReg_XA(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
  switch (InpSize)
  {
    case eSymbolSize8Bit:
      as_snprintf(pDest, DestSize, "R%u%c", (unsigned)(Value >> 1), "LH"[Value & 1]);
      break;
    case eSymbolSize16Bit:
      as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
      break;
    case eSymbolSize32Bit:
      as_snprintf(pDest, DestSize, "R%u.D", (unsigned)Value);
      break;
    default:
      as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
  }
}


/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, tSymbolSize *pSize, Byte *pResult, Boolean MustBeReg)
 * \brief  check whether argument is a CPU register or register alias
 * \param  pArg source argument
 * \param  pSize register size if yes
 * \param  pResult register number if yes
 * \param  MustBeReg expecting register?
 * \return Reg eval result
 * ------------------------------------------------------------------------ */

static tRegEvalResult DecodeReg(const tStrComp *pArg, tSymbolSize *pSize, Byte *pResult, Boolean MustBeReg)
{
  tRegDescr RegDescr;
  tEvalResult EvalResult;
  tRegEvalResult RegEvalResult;

  RegEvalResult = DecodeRegCore(pArg->str.p_str, pSize, pResult);
  if (RegEvalResult != eIsNoReg)
  {
    *pResult &= ~REGSYM_FLAG_ALIAS;
    return RegEvalResult;
  }

  RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSizeUnknown, MustBeReg);
  if (RegEvalResult == eIsReg)
  {
    *pResult = RegDescr.Reg & ~REGSYM_FLAG_ALIAS;
    *pSize = EvalResult.DataSize;
  }
  else
  {
    *pResult = 0;
    *pSize = eSymbolSizeUnknown;
  }
  return RegEvalResult;
}

static Boolean ChkAdr(Word Mask, const tStrComp *pComp)
{
  if ((AdrMode != ModNone) && (!(Mask & (1 << AdrMode))))
  {
    WrStrErrorPos(ErrNum_InvAddrMode, pComp);
    AdrMode = ModNone;
    AdrCnt = 0;
    return False;
  }
  return True;
}

typedef struct
{
  as_eval_cb_data_t cb_data;
  Byte reg;
} xa_eval_cb_data_t;

DECLARE_AS_EVAL_CB(xa_eval_cb)
{
  xa_eval_cb_data_t *p_xa_eval_cb_data = (xa_eval_cb_data_t*)p_data;
  Byte reg;
  tSymbolSize reg_size;

  switch (DecodeReg(p_arg, &reg_size, &reg, False))
  {
    case eIsReg:
      if ((reg_size != eSymbolSize16Bit)
       || (p_xa_eval_cb_data->reg != 0xff)
       || !as_eval_cb_data_stack_plain_add(p_data->p_stack))
      {
        WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
        return e_eval_fail;
      }
      p_xa_eval_cb_data->reg = reg;
      as_tempres_set_int(p_res, 0);
      return e_eval_ok;
    case eRegAbort:
      return e_eval_fail;
    default:
      return e_eval_none;
  }
}

static Boolean DecodeAdrIndirect(tStrComp *pArg, Word Mask)
{
  unsigned ArgLen;

  ArgLen = strlen(pArg->str.p_str);
  if (pArg->str.p_str[ArgLen - 1] == '+')
  {
    tSymbolSize NSize;

    StrCompShorten(pArg, 1); ArgLen--;
    if (!DecodeReg(pArg, &NSize, &AdrPart, True));
    else if (NSize != eSymbolSize16Bit) WrStrErrorPos(ErrNum_InvAddrMode, pArg);
    else
    {
      AdrMode = ModMem; MemPart = 3;
    }
  }
  else
  {
    LongInt DispAcc;
    xa_eval_cb_data_t xa_eval_cb_data;
    tEvalResult eval_result;

    as_eval_cb_data_ini(&xa_eval_cb_data.cb_data, xa_eval_cb);
    xa_eval_cb_data.reg = 0xff;
    DispAcc = EvalStrIntExprWithResultAndCallback(pArg, SInt16, &eval_result, &xa_eval_cb_data.cb_data);

    AdrPart = xa_eval_cb_data.reg;
    if (xa_eval_cb_data.reg == 0xff) WrStrErrorPos(ErrNum_InvAddrMode, pArg);
    else if (DispAcc == 0)
    {
      AdrMode = ModMem; MemPart = 2;
    }
    else if ((DispAcc >= -128) && (DispAcc < 127))
    {
      AdrMode = ModMem; MemPart = 4;
      AdrVals[0] = DispAcc & 0xff; AdrCnt = 1;
    }
    else if (ChkRange(DispAcc, -0x8000l, 0x7fffl))
    {
      AdrMode = ModMem; MemPart = 5;
      AdrVals[0] = (DispAcc >> 8) & 0xff;
      AdrVals[1] = DispAcc & 0xff;
      AdrCnt = 2;
    }
  }
  return ChkAdr(Mask, pArg);
}

static Boolean DecodeAdr(tStrComp *pArg, Word Mask)
{
  tSymbolSize NSize;
  LongInt AdrLong;
  tEvalResult EvalResult;
  Word AdrInt;
  int ArgLen;

  AdrMode = ModNone; AdrCnt = 0;
  KillPrefBlanksStrComp(pArg);
  KillPostBlanksStrComp(pArg);

  switch (DecodeReg(pArg, &NSize, &AdrPart, False))
  {
    case eIsReg:
      if (Mask & MModReg)
      {
        AdrMode = ModReg;
        SetOpSize(NSize);
      }
      else
      {
        AdrMode = ModMem;
        MemPart = 1;
        SetOpSize(NSize);
      }
      return ChkAdr(Mask, pArg);
    case eRegAbort:
      return False;
    default:
      break;
  }

  if (*pArg->str.p_str == '#')
  {
    tStrComp ImmComp;
    Boolean OK;

    StrCompRefRight(&ImmComp, pArg, 1);
    switch ((int)OpSize)
    {
      case eSymbolSize5Bit:
        AdrVals[0] = EvalStrIntExpression(&ImmComp, UInt5, &OK);
        if (OK)
        {
          AdrCnt = 1; AdrMode = ModImm;
        }
        break;
      case eSymbolSizeSigned4Bit:
        AdrVals[0] = EvalStrIntExpression(&ImmComp, SInt4, &OK);
        if (OK)
        {
          AdrCnt = 1; AdrMode = ModImm;
        }
        break;
      case eSymbolSize4Bit:
        AdrVals[0] = EvalStrIntExpression(&ImmComp, UInt4, &OK);
        if (OK)
        {
          AdrCnt = 1; AdrMode = ModImm;
        }
        break;
      case eSymbolSizeUnknown:
        WrError(ErrNum_UndefOpSizes);
        break;
      case eSymbolSize8Bit:
        AdrVals[0] = EvalStrIntExpression(&ImmComp, Int8, &OK);
        if (OK)
        {
          AdrCnt = 1; AdrMode = ModImm;
        }
        break;
      case eSymbolSize16Bit:
        AdrInt = EvalStrIntExpression(&ImmComp, Int16, &OK);
        if (OK)
        {
          AdrVals[0] = Hi(AdrInt);
          AdrVals[1] = Lo(AdrInt);
          AdrCnt = 2;
          AdrMode = ModImm;
        }
        break;
      case eSymbolSize32Bit:
        AdrLong = EvalStrIntExpression(&ImmComp, Int32, &OK);
        if (OK)
        {
          AdrVals[0] = (AdrLong >> 24) & 0xff;
          AdrVals[1] = (AdrLong >> 16) & 0xff;
          AdrVals[2] = (AdrLong >> 8) & 0xff;
          AdrVals[3] = AdrLong & 0xff;
          AdrCnt = 4;
          AdrMode = ModImm;
        }
        break;
      default:
        break;
    }
    return ChkAdr(Mask, pArg);
  }

  ArgLen = strlen(pArg->str.p_str);
  if ((*pArg->str.p_str == '[') && (pArg->str.p_str[ArgLen - 1] == ']'))
  {
    tStrComp IndirComp;

    StrCompShorten(pArg, 1);
    StrCompRefRight(&IndirComp, pArg, 1);
    KillPrefBlanksStrComp(&IndirComp);
    KillPostBlanksStrComp(&IndirComp);

    return DecodeAdrIndirect(&IndirComp, Mask);
  }

  AdrLong = EvalStrIntExpressionWithResult(pArg, UInt24, &EvalResult);
  if (EvalResult.OK)
  {
    if (mFirstPassUnknown(EvalResult.Flags))
    {
      if (!(Mask & MModAbs)) AdrLong &= 0x3ff;
    }
    if ((AdrLong & 0xffff) > 0x7ff) WrError(ErrNum_AdrOverflow);
    else if ((AdrLong & 0xffff) <= 0x3ff)
    {
      if ((AdrLong >> 16) != Reg_DS) WrError(ErrNum_InAccPage);
      ChkSpace(SegData, EvalResult.AddrSpaceMask);
      AdrMode = ModMem; MemPart = 6;
      AdrPart = Hi(AdrLong);
      AdrVals[0] = Lo(AdrLong);
      AdrCnt = 1;
    }
    else if (AdrLong > 0x7ff) WrError(ErrNum_AdrOverflow);
    else
    {
      ChkSpace(SegIO, EvalResult.AddrSpaceMask);
      AdrMode = ModMem; MemPart = 6;
      AdrPart = Hi(AdrLong);
      AdrVals[0] = Lo(AdrLong);
      AdrCnt = 1;
    }
  }

  return ChkAdr(Mask, pArg);
}

static Boolean DecodeBitAddr(tStrComp *pArg, LongInt *Erg)
{
  char *p;
  Byte BPos, Reg;
  ShortInt Res;
  tSymbolSize Size;
  LongInt AdrLong;
  tEvalResult EvalResult;

  p = RQuotPos(pArg->str.p_str, '.'); Res = 0;
  if (!p)
  {
    AdrLong = EvalStrIntExpressionWithResult(pArg, UInt24, &EvalResult);
    if (mFirstPassUnknown(EvalResult.Flags)) AdrLong &= 0x3ff;
    *Erg = AdrLong; Res = 1;
  }
  else
  {
    int l = p - pArg->str.p_str;

    BPos = EvalStrIntExpressionOffsWithResult(pArg, l + 1, UInt4, &EvalResult);
    if (mFirstPassUnknown(EvalResult.Flags)) BPos &= 7;

    *p = '\0'; pArg->Pos.Len -= l + 1;
    if (EvalResult.OK)
    {
      switch (DecodeReg(pArg, &Size, &Reg, False))
      {
        case eRegAbort:
          return False;
        case eIsReg:
          if ((Size == eSymbolSize8Bit) && (BPos > 7)) WrError(ErrNum_OverRange);
          else
          {
            if (Size == eSymbolSize8Bit) *Erg = (Reg << 3) + BPos;
            else *Erg = (Reg << 4) + BPos;
            Res = 1;
          }
          break;
        default:
          if (BPos > 7) WrError(ErrNum_OverRange);
          else
          {
            AdrLong = EvalStrIntExpressionWithResult(pArg, UInt24, &EvalResult);
            if (EvalResult.AddrSpaceMask & (1 << SegIO))
            {
              ChkSpace(SegIO, EvalResult.AddrSpaceMask);
              if (mFirstPassUnknown(EvalResult.Flags)) AdrLong = (AdrLong & 0x3f) | 0x400;
              if (ChkRange(AdrLong, 0x400, 0x43f))
              {
                *Erg = 0x200 + ((AdrLong & 0x3f) << 3) + BPos;
                Res = 1;
              }
              else
                Res = -1;
            }
            else
            {
              ChkSpace(SegData, EvalResult.AddrSpaceMask);
              if (mFirstPassUnknown(EvalResult.Flags)) AdrLong = (AdrLong & 0x00ff003f) | 0x20;
              if (ChkRange(AdrLong & 0xff, 0x20, 0x3f))
              {
                *Erg = 0x100 + ((AdrLong & 0x1f) << 3) + BPos + (AdrLong & 0xff0000);
                Res = 1;
              }
              else
                Res = -1;
            }
          }
        break;
      }
    }
    *p = '.';
  }
  if (Res == 0) WrError(ErrNum_InvAddrMode);
  return (Res == 1);
}

static void ChkBitPage(LongInt Adr)
{
  if ((Adr >> 16) != Reg_DS) WrError(ErrNum_InAccPage);
}

static LongWord MkEven24(LongWord Inp)
{
  return Inp & 0xfffffeul;
}

static LongWord GetBranchDest(const tStrComp *pComp, tEvalResult *pEvalResult)
{
  LongWord Result;

  Result = EvalStrIntExpressionWithResult(pComp, UInt24, pEvalResult);
  if (pEvalResult->OK)
  {
    if (mFirstPassUnknown(pEvalResult->Flags)) Result = MkEven24(Result);
    ChkSpace(SegCode, pEvalResult->AddrSpaceMask);
    if (Result & 1)
    {
      WrStrErrorPos(ErrNum_NotAligned, pComp);
      pEvalResult->OK = False;
    }
  }
  return Result;
}

static Boolean ChkShortEvenDist(LongInt *pDist, tSymbolFlags Flags)
{
  if (!mSymbolQuestionable(Flags) && ((*pDist > 254) || (*pDist < -256)))
    return False;
  else
  {
    *pDist >>= 1;
    return True;
  }
}

static Boolean ChkLongEvenDist(LongInt *pDist, const tStrComp *pComp, tSymbolFlags Flags)
{
  if (!mSymbolQuestionable(Flags) && ((*pDist > 65534) || (*pDist < -65536)))
  {
    WrStrErrorPos(ErrNum_JmpDistTooBig, pComp);
    return False;
  }
  else
  {
    *pDist >>= 1;
    return True;
  }
}

/*-------------------------------------------------------------------------*/
/* Befehlsdekoder */

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

  code_equate_range(SegIO, 0x400, 0x7ff);
}

static void DecodeBIT(Word Index)
{
  LongInt BAdr;

  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (DecodeBitAddr(&ArgStr[1], &BAdr))
  {
    EnterIntSymbol(&LabPart, BAdr, SegNone, False);
    switch ((BAdr & 0x3ff) >> 8)
    {
      case 0:
        as_snprintf(ListLine, STRINGSIZE, "=R%d.%d",
                    (unsigned)((BAdr >> 4) & 15),
                    (unsigned) (BAdr & 15));
        break;
      case 1:
        as_snprintf(ListLine, STRINGSIZE, "=%x:%x.%d",
                    (unsigned)((BAdr >> 16) & 255),
                    (unsigned)((BAdr & 0x1f8) >> 3), (unsigned)(BAdr & 7));
        break;
      default:
        as_snprintf(ListLine, STRINGSIZE, "=S:%x.%d",
                    (unsigned)(((BAdr >> 3) & 0x3f) + 0x400),
                    (unsigned)(BAdr & 7));
        break;
    }
  }
}

static void DecodeFixed(Word Code)
{
  if (ChkArgCnt(0, 0))
  {
    if (Hi(Code) != 0) BAsmCode[CodeLen++] = Hi(Code);
    BAsmCode[CodeLen++] = Lo(Code);
    if ((Code == RETICode) && (!SupAllowed)) WrError(ErrNum_PrivOrder);
  }
}

static void DecodeStack(Word Code)
{
  Byte HReg;
  Boolean OK;
  Word Mask;
  int i;

  if (ChkArgCnt(1, ArgCntMax))
  {
    HReg = 0xff; OK = True; Mask = 0;
    for (i = 1; i <= ArgCnt; i++)
      if (OK)
      {
        DecodeAdr(&ArgStr[i], MModMem);
        if (AdrMode == ModNone) OK = False;
        else switch (MemPart)
        {
          case 1:
            if (HReg == 0)
            {
              WrError(ErrNum_InvAddrMode); OK = False;
            }
            else
            {
              HReg = 1; Mask |= (1 << AdrPart);
            }
            break;
          case 6:
            if (HReg != 0xff)
            {
              WrError(ErrNum_InvAddrMode); OK = False;
            }
            else
              HReg = 0;
            break;
          default:
            WrError(ErrNum_InvAddrMode); OK = False;
        }
      }
    if (OK)
    {
      if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
      else if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
      else if (HReg == 0)
      {
        BAsmCode[CodeLen++] = 0x87 + (OpSize << 3);
        BAsmCode[CodeLen++] = Hi(Code) + AdrPart;
        BAsmCode[CodeLen++] = AdrVals[0];
      }
      else if (Code < 0x2000)  /* POP(U): obere Register zuerst */
      {
        if (Hi(Mask) != 0)
        {
          BAsmCode[CodeLen++] = Lo(Code) + (OpSize << 3) + 0x40;
          BAsmCode[CodeLen++]=Hi(Mask);
        }
        if (Lo(Mask) != 0)
        {
          BAsmCode[CodeLen++] = Lo(Code) + (OpSize << 3);
          BAsmCode[CodeLen++] = Lo(Mask);
        }
        if ((OpSize == eSymbolSize16Bit) && (Code == 0x1027) && (Mask & 0x80)) WrError(ErrNum_Unpredictable);
      }
      else              /* PUSH(U): untere Register zuerst */
      {
        if (Lo(Mask) != 0)
        {
          BAsmCode[CodeLen++] = Lo(Code) + (OpSize << 3);
          BAsmCode[CodeLen++] = Lo(Mask);
        }
        if (Hi(Mask) != 0)
        {
          BAsmCode[CodeLen++] = Lo(Code) + (OpSize << 3) + 0x40;
          BAsmCode[CodeLen++] = Hi(Mask);
        }
      }
    }
  }
}

static void DecodeALU(Word Index)
{
  Byte HReg, HCnt, HVals[3], HMem;

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg | MModMem);
    switch (AdrMode)
    {
      case ModReg:
        if (OpSize >= eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
        else if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
        else
        {
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModMem | MModImm);
          switch (AdrMode)
          {
            case ModMem:
              BAsmCode[CodeLen++] = (Index << 4) + (OpSize << 3) + MemPart;
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
              if ((MemPart == 3) && ((HReg >> (1 - OpSize)) == AdrPart)) WrError(ErrNum_Unpredictable);
              break;
            case ModImm:
              BAsmCode[CodeLen++] = 0x91 + (OpSize << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + Index;
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
              break;
          }
        }
        break;
      case ModMem:
        HReg = AdrPart; HMem = MemPart; HCnt = AdrCnt;
        memcpy(HVals, AdrVals, AdrCnt);
        DecodeAdr(&ArgStr[2], MModReg | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            if (OpSize == eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
            else if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
            else
            {
              BAsmCode[CodeLen++] = (Index << 4) + (OpSize << 3) + HMem;
              BAsmCode[CodeLen++] = (AdrPart << 4) + 8 + HReg;
              memcpy(BAsmCode + CodeLen, HVals, HCnt);
              CodeLen += HCnt;
              if ((HMem == 3) && ((AdrPart >> (1 - OpSize)) == HReg)) WrError(ErrNum_Unpredictable);
            }
            break;
          case ModImm:
            if (OpSize == eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
            else if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
            else
            {
              BAsmCode[CodeLen++] = 0x90 + HMem + (OpSize << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + Index;
              memcpy(BAsmCode + CodeLen, HVals, HCnt);
              memcpy(BAsmCode + CodeLen + HCnt, AdrVals, AdrCnt);
              CodeLen += AdrCnt + HCnt;
            }
            break;
        }
        break;
    }
  }
}

static void DecodeRegO(Word Index)
{
  RegOrder *Op = RegOrders + Index;

  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        if ((Op->SizeMask & (1 << OpSize)) == 0) WrError(ErrNum_InvOpSize);
        else
        {
          BAsmCode[CodeLen++] = 0x90 + (OpSize << 3);
          BAsmCode[CodeLen++] = (AdrPart << 4) + Op->Code;
        }
        break;
    }
  }
}

static void DecodeShift(Word Index)
{
  Byte HReg, HMem;

  if (!ChkArgCnt(2, 2));
  else if (OpSize > eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
  else
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        HReg = AdrPart; HMem = OpSize;
        if (*ArgStr[2].str.p_str == '#')
          OpSize = (HMem == 2) ? eSymbolSize5Bit : eSymbolSize4Bit;
        else
          OpSize = eSymbolSize8Bit;
        DecodeAdr(&ArgStr[2], MModReg | ((Index == 3) ? 0 : MModImm));
        switch (AdrMode)
        {
          case ModReg:
            BAsmCode[CodeLen++] = 0xc0 + ((HMem & 1) << 3) + Index;
            if (HMem == 2) BAsmCode[CodeLen - 1] += 12;
            BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            if (Index == 3)
            {
              if (HMem == 2)
              {
                if ((AdrPart >> 2) == (HReg >> 1)) WrError(ErrNum_Unpredictable);
              }
              else if ((AdrPart >> HMem) == HReg) WrError(ErrNum_Unpredictable);
            }
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0xd0 + ((HMem & 1) << 3) + Index;
            if (HMem == 2)
            {
              BAsmCode[CodeLen - 1] += 12;
              BAsmCode[CodeLen++] = ((HReg & 14) << 4) + AdrVals[0];
            }
            else
              BAsmCode[CodeLen++] = (HReg << 4) + AdrVals[0];
            break;
        }
        break;
    }
  }
}

static void DecodeRotate(Word Code)
{
  Byte HReg, HMem;

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        if (OpSize == eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
        else
        {
          HReg = AdrPart; HMem = OpSize; OpSize = eSymbolSize4Bit;
          DecodeAdr(&ArgStr[2], MModImm);
          switch (AdrMode)
          {
            case ModImm:
              BAsmCode[CodeLen++] = Code + (HMem << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + AdrVals[0];
              break;
          }
        }
        break;
    }
  }
}

static void DecodeRel(Word Index)
{
  InvOrder *Op = RelOrders + Index;
  LongWord Dest;
  LongInt Dist;
  tEvalResult EvalResult;

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    Dest = GetBranchDest(&ArgStr[1], &EvalResult);
    if (EvalResult.OK)
    {
      Dist = Dest - MkEven24(EProgCounter() + CodeLen + 2);
      if (ChkShortEvenDist(&Dist, EvalResult.Flags))
      {
        BAsmCode[CodeLen++] = Op->Code;
        BAsmCode[CodeLen++] = Dist & 0xff;
      }
      else if (!DoBranchExt) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
      else if (Op->Inversion == 255)  /* BR */
      {
        Dist = Dest - MkEven24(EProgCounter() + CodeLen + 3);
        if (ChkLongEvenDist(&Dist, &ArgStr[1], EvalResult.Flags))
        {
          Dist >>= 1;
          BAsmCode[CodeLen++] = 0xd5;
          BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
          BAsmCode[CodeLen++] = Dist        & 0xff;
        }
      }
      else
      {
        Dist = Dest - MkEven24(EProgCounter() + CodeLen + 5);
        if (ChkLongEvenDist(&Dist, &ArgStr[1], EvalResult.Flags))
        {
          BAsmCode[CodeLen++] = RelOrders[Op->Inversion].Code;
          BAsmCode[CodeLen++] = 2;
          BAsmCode[CodeLen++] = 0xd5;
          BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
          BAsmCode[CodeLen++] = Dist        & 0xff;
          if (Odd(EProgCounter() + CodeLen)) BAsmCode[CodeLen++] = 0;
        }
      }
    }
  }
}

static void DecodeJBit(Word Index)
{
  LongInt BitAdr, Dist, odd;
  LongWord Dest;
  tEvalResult EvalResult;
  InvOrder *Op = JBitOrders + Index;

  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (DecodeBitAddr(&ArgStr[1], &BitAdr))
  {
    Dest = GetBranchDest(&ArgStr[2], &EvalResult);
    if (EvalResult.OK)
    {
      Dist = Dest - MkEven24(EProgCounter() + CodeLen + 4);
      if (ChkShortEvenDist(&Dist, EvalResult.Flags))
      {
        BAsmCode[CodeLen++] = 0x97;
        BAsmCode[CodeLen++] = Op->Code + Hi(BitAdr);
        BAsmCode[CodeLen++] = Lo(BitAdr);
        BAsmCode[CodeLen++] = Dist & 0xff;
      }
      else if (!DoBranchExt) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[2]);
      else if (Op->Inversion == 255)
      {
        odd = EProgCounter() & 1;
        Dist = Dest - MkEven24(EProgCounter() + CodeLen + 9 + odd);
        if (ChkLongEvenDist(&Dist, &ArgStr[2], EvalResult.Flags))
        {
          BAsmCode[CodeLen++] = 0x97;
          BAsmCode[CodeLen++] = Op->Code + Hi(BitAdr);
          BAsmCode[CodeLen++] = Lo(BitAdr);
          BAsmCode[CodeLen++] = 1 + odd;
          BAsmCode[CodeLen++] = 0xfe;
          BAsmCode[CodeLen++] = 2 + odd;
          if (odd) BAsmCode[CodeLen++] = 0;
          BAsmCode[CodeLen++] = 0xd5;
          BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
          BAsmCode[CodeLen++] = Dist        & 0xff;
          BAsmCode[CodeLen++] = 0;
        }
      }
      else
      {
        Dist = Dest - MkEven24(EProgCounter() + CodeLen + 7);
        if (ChkLongEvenDist(&Dist, &ArgStr[2], EvalResult.Flags))
        {
          BAsmCode[CodeLen++] = 0x97;
          BAsmCode[CodeLen++] = JBitOrders[Op->Inversion].Code + Hi(BitAdr);
          BAsmCode[CodeLen++] = Lo(BitAdr);
          BAsmCode[CodeLen++] = 2;
          BAsmCode[CodeLen++] = 0xd5;
          BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
          BAsmCode[CodeLen++] = Dist        & 0xff;
          if (Odd(EProgCounter() + CodeLen)) BAsmCode[CodeLen++] = 0;
        }
      }
    }
  }
}


static void DecodeMOV(Word Index)
{
  LongInt AdrLong;
  Byte HVals[3], HReg, HPart, HCnt;
  UNUSED(Index);

  if (!ChkArgCnt(2, 2));
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "C"))
  {
    if (DecodeBitAddr(&ArgStr[2], &AdrLong))
    {
      if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
      else
      {
        ChkBitPage(AdrLong);
        BAsmCode[CodeLen++] = 0x08;
        BAsmCode[CodeLen++] = 0x20 + Hi(AdrLong);
        BAsmCode[CodeLen++] = Lo(AdrLong);
      }
    }
  }
  else if (!as_strcasecmp(ArgStr[2].str.p_str, "C"))
  {
    if (DecodeBitAddr(&ArgStr[1], &AdrLong))
    {
      if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
      else
      {
        ChkBitPage(AdrLong);
        BAsmCode[CodeLen++] = 0x08;
        BAsmCode[CodeLen++] = 0x30 + Hi(AdrLong);
        BAsmCode[CodeLen++] = Lo(AdrLong);
      }
    }
  }
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "USP"))
  {
    SetOpSize(eSymbolSize16Bit);
    DecodeAdr(&ArgStr[2], MModReg);
    if (AdrMode == ModReg)
    {
      BAsmCode[CodeLen++] = 0x98;
      BAsmCode[CodeLen++] = (AdrPart << 4) + 0x0f;
    }
  }
  else if (!as_strcasecmp(ArgStr[2].str.p_str, "USP"))
  {
    SetOpSize(eSymbolSize16Bit);
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode == ModReg)
    {
      BAsmCode[CodeLen++] = 0x90;
      BAsmCode[CodeLen++] = (AdrPart << 4)+0x0f;
    }
  }
  else
  {
    DecodeAdr(&ArgStr[1], MModReg | MModMem);
    switch (AdrMode)
    {
      case ModReg:
        if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
        else
        {
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModMem | MModImm);
          switch (AdrMode)
          {
            case ModMem:
              BAsmCode[CodeLen++] = 0x80 + (OpSize << 3) + MemPart;
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
              if ((MemPart == 3) && ((HReg >> (1 - OpSize)) == AdrPart)) WrError(ErrNum_Unpredictable);
              break;
            case ModImm:
              BAsmCode[CodeLen++] = 0x91 + (OpSize << 3);
              BAsmCode[CodeLen++] = 0x08 + (HReg << 4);
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
              break;
          }
        }
        break;
      case ModMem:
        memcpy(HVals, AdrVals, AdrCnt); HCnt = AdrCnt; HPart = MemPart; HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModReg | MModMem | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              BAsmCode[CodeLen++] = 0x80 + (OpSize << 3) + HPart;
              BAsmCode[CodeLen++] = (AdrPart << 4) + 0x08 + HReg;
              memcpy(BAsmCode + CodeLen, HVals, HCnt);
              CodeLen += HCnt;
              if ((HPart == 3) && ((AdrPart >> (1 - OpSize)) == HReg)) WrError(ErrNum_Unpredictable);
            }
            break;
          case ModMem:
            if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
            else if ((OpSize != eSymbolSize8Bit) & (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else if ((HPart == 6) && (MemPart == 6))
            {
              BAsmCode[CodeLen++] = 0x97 + (OpSize << 3);
              BAsmCode[CodeLen++] = (HReg << 4)+AdrPart;
              BAsmCode[CodeLen++] = HVals[0];
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            else if ((HPart == 6) && (MemPart == 2))
            {
              BAsmCode[CodeLen++] = 0xa0 + (OpSize << 3);
              BAsmCode[CodeLen++] = 0x80 + (AdrPart << 4) + HReg;
              BAsmCode[CodeLen++] = HVals[0];
            }
            else if ((HPart == 2) && (MemPart == 6))
            {
              BAsmCode[CodeLen++] = 0xa0 + (OpSize << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            else if ((HPart == 3) && (MemPart == 3))
            {
              BAsmCode[CodeLen++] = 0x90 + (OpSize << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              if (HReg == AdrPart) WrError(ErrNum_Unpredictable);
            }
            else
              WrError(ErrNum_InvAddrMode);
            break;
          case ModImm:
            if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
            else if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              BAsmCode[CodeLen++] = 0x90 + (OpSize << 3) + HPart;
              BAsmCode[CodeLen++] = 0x08 + (HReg << 4);
              memcpy(BAsmCode + CodeLen, HVals, HCnt);
              memcpy(BAsmCode + CodeLen + HCnt, AdrVals, AdrCnt);
              CodeLen += HCnt + AdrCnt;
            }
            break;
        }
        break;
    }
  }
}

static void DecodeMOVC(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (!ChkArgCnt(2, 2));
  else
  {
    if (!*AttrPart.str.p_str && !as_strcasecmp(ArgStr[1].str.p_str, "A")) OpSize = eSymbolSize8Bit;
    if (!as_strcasecmp(ArgStr[2].str.p_str, "[A+DPTR]"))
    {
      if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrError(ErrNum_InvAddrMode);
      else if (OpSize != eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else
      {
        BAsmCode[CodeLen++] = 0x90;
        BAsmCode[CodeLen++] = 0x4e;
      }
    }
    else if (!as_strcasecmp(ArgStr[2].str.p_str, "[A+PC]"))
    {
      if (as_strcasecmp(ArgStr[1].str.p_str, "A")) WrError(ErrNum_InvAddrMode);
      else if (OpSize != eSymbolSize8Bit) WrError(ErrNum_InvOpSize);
      else
      {
        BAsmCode[CodeLen++] = 0x90;
        BAsmCode[CodeLen++] = 0x4c;
      }
    }
    else
    {
      DecodeAdr(&ArgStr[1], MModReg);
      if (AdrMode != ModNone)
      {
        if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
        else
        {
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModMem);
          if (AdrMode != ModNone)
          {
            if (MemPart != 3) WrError(ErrNum_InvAddrMode);
            else
            {
              BAsmCode[CodeLen++] = 0x80 + (OpSize << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              if ((MemPart == 3) && ((HReg >> (1 - OpSize)) == AdrPart)) WrError(ErrNum_Unpredictable);
            }
          }
        }
      }
    }
  }
}

static void DecodeMOVX(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (!ChkArgCnt(2, 2));
  else
  {
    DecodeAdr(&ArgStr[1], MModMem);
    if (AdrMode == ModMem)
    {
      switch (MemPart)
      {
        case 1:
          if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
          else
          {
            HReg = AdrPart; DecodeAdr(&ArgStr[2], MModMem);
            if (AdrMode == ModMem)
            {
              if (MemPart != 2) WrError(ErrNum_InvAddrMode);
              else
              {
                BAsmCode[CodeLen++] = 0xa7 + (OpSize << 3);
                BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              }
            }
          }
          break;
        case 2:
          HReg = AdrPart; DecodeAdr(&ArgStr[2], MModReg);
          if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
          else
          {
            BAsmCode[CodeLen++] = 0xa7 + (OpSize << 3);
            BAsmCode[CodeLen++] = 0x08 + (AdrPart << 4) + HReg;
          }
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
    }
  }
}

static void DecodeXCH(Word Index)
{
  Byte HReg, HPart, HVals[3];
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModMem);
    if (AdrMode == ModMem)
    {
      switch (MemPart)
      {
        case 1:
          HReg = AdrPart; DecodeAdr(&ArgStr[2], MModMem);
          if (AdrMode == ModMem)
          {
            if ((OpSize != eSymbolSize16Bit) && (OpSize != eSymbolSize8Bit)) WrError(ErrNum_InvOpSize);
            else switch (MemPart)
            {
              case 1:
                BAsmCode[CodeLen++] = 0x60 + (OpSize << 3);
                BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
                if (HReg == AdrPart) WrError(ErrNum_Unpredictable);
                break;
              case 2:
                BAsmCode[CodeLen++] = 0x50 + (OpSize << 3);
                BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
                break;
              case 6:
                BAsmCode[CodeLen++] = 0xa0 + (OpSize << 3);
                BAsmCode[CodeLen++] = 0x08 + (HReg << 4) + AdrPart;
                BAsmCode[CodeLen++] = AdrVals[0];
                break;
              default:
                WrError(ErrNum_InvAddrMode);
            }
          }
          break;
        case 2:
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModReg);
          if (AdrMode == ModReg)
          {
            if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              BAsmCode[CodeLen++] = 0x50 + (OpSize << 3);
              BAsmCode[CodeLen++] = (AdrPart << 4) + HReg;
            }
          }
          break;
        case 6:
          HPart = AdrPart; HVals[0] = AdrVals[0];
          DecodeAdr(&ArgStr[2], MModReg);
          if (AdrMode == ModReg)
          {
            if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              BAsmCode[CodeLen++] = 0xa0 + (OpSize << 3);
              BAsmCode[CodeLen++] = 0x08 + (AdrPart << 4) + HPart;
              BAsmCode[CodeLen++] = HVals[0];
            }
          }
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
    }
  }
}

static void DecodeADDSMOVS(Word Index)
{
  Byte HReg;
  tSymbolSize HSize;

  if (ChkArgCnt(2, 2))
  {
    HSize = OpSize;
    OpSize = eSymbolSizeSigned4Bit;
    DecodeAdr(&ArgStr[2], MModImm);
    switch (AdrMode)
    {
      case ModImm:
        HReg = AdrVals[0]; OpSize = HSize;
        DecodeAdr(&ArgStr[1], MModMem);
        switch (AdrMode)
        {
          case ModMem:
            if (OpSize == eSymbolSize32Bit) WrError(ErrNum_InvOpSize);
            else if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
            else
            {
               BAsmCode[CodeLen++] = 0xa0 + (Index << 4) + (OpSize << 3) + MemPart;
               BAsmCode[CodeLen++] = (AdrPart << 4) + (HReg & 0x0f);
               memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
               CodeLen += AdrCnt;
            }
            break;
        }
        break;
    }
  }
}

static void DecodeDIV(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode == ModReg)
    {
      if ((OpSize != eSymbolSize16Bit) && (OpSize != eSymbolSize32Bit)) WrError(ErrNum_InvOpSize);
      else
      {
        HReg = AdrPart; OpSize--; DecodeAdr(&ArgStr[2], MModReg | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            BAsmCode[CodeLen++] = 0xe7 + (OpSize << 3);
            BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0xe8 + OpSize;
            BAsmCode[CodeLen++] = (HReg << 4) + 0x0b - (OpSize << 1);
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
        }
      }
    }
  }
}

static void DecodeDIVU(Word Index)
{
  Byte HReg;
  int z;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode == ModReg)
    {
      if ((OpSize == eSymbolSize8Bit) && (AdrPart & 1)) WrError(ErrNum_InvReg);
      else
      {
        HReg = AdrPart; z = OpSize; if (OpSize != eSymbolSize8Bit) OpSize--;
        DecodeAdr(&ArgStr[2], MModReg | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            BAsmCode[CodeLen++] = 0xe1 + (z << 2);
            if (z == 2) BAsmCode[CodeLen - 1] += 4;
            BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0xe8 + Ord(z == 2);
            BAsmCode[CodeLen++] = (HReg << 4) + 0x01 + (Ord(z == 1) << 1);
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
        }
      }
    }
  }
}

static void DecodeMUL(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode == ModReg)
    {
      if (OpSize != eSymbolSize16Bit) WrError(ErrNum_InvOpSize);
      else if (AdrPart & 1) WrError(ErrNum_InvReg);
      else
      {
        HReg = AdrPart; DecodeAdr(&ArgStr[2], MModReg | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            BAsmCode[CodeLen++] = 0xe6;
            BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0xe9;
            BAsmCode[CodeLen++] = (HReg << 4) + 0x08;
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
        }
      }
    }
  }
}

static void DecodeMULU(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode == ModReg)
    {
      if (AdrPart & 1) WrError(ErrNum_InvReg);
      else
      {
        HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModReg | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            BAsmCode[CodeLen++] = 0xe0 + (OpSize << 2);
            BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0xe8 + OpSize;
            BAsmCode[CodeLen++] = (HReg << 4);
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
        }
      }
    }
  }
}

static void DecodeLEA(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    if (AdrMode == ModReg)
    {
      if (OpSize != eSymbolSize16Bit) WrError(ErrNum_InvOpSize);
      else
      {
        HReg = AdrPart;
        DecodeAdrIndirect(&ArgStr[2], MModMem);
        if (AdrMode == ModMem)
          switch (MemPart)
          {
            case 4:
            case 5:
              BAsmCode[CodeLen++] = 0x20 + (MemPart << 3);
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
              break;
            default:
              WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
          }
      }
    }
  }
}

static void DecodeANLORL(Word Index)
{
  if (!ChkArgCnt(2, 2));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (as_strcasecmp(ArgStr[1].str.p_str, "C")) WrError(ErrNum_InvAddrMode);
  else
  {
    Byte Invert = 0;
    LongInt AdrLong;
    Boolean Result;

    if (*ArgStr[2].str.p_str == '/')
    {
      tStrComp Comp;

      StrCompRefRight(&Comp, &ArgStr[2], 1);
      Result = DecodeBitAddr(&Comp, &AdrLong);
      Invert = 1;
    }
    else
      Result = DecodeBitAddr(&ArgStr[2], &AdrLong);
    if (Result)
    {
      ChkBitPage(AdrLong);
      BAsmCode[CodeLen++] = 0x08;
      BAsmCode[CodeLen++] = 0x40 | (Index << 5) | (Ord(Invert) << 4) | (Hi(AdrLong) & 3);
      BAsmCode[CodeLen++] = Lo(AdrLong);
    }
  }
}

static void DecodeCLRSETB(Word Index)
{
  LongInt AdrLong;

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (DecodeBitAddr(&ArgStr[1], &AdrLong))
  {
    ChkBitPage(AdrLong);
    BAsmCode[CodeLen++] = 0x08;
    BAsmCode[CodeLen++] = (Index << 4) + (Hi(AdrLong) & 3);
    BAsmCode[CodeLen++] = Lo(AdrLong);
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    OpSize = eSymbolSize4Bit;
    DecodeAdr(&ArgStr[1], MModImm);
    switch (AdrMode)
    {
      case ModImm:
        BAsmCode[CodeLen++] = 0xd6;
        BAsmCode[CodeLen++] = 0x30 + AdrVals[0];
        break;
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (*ArgStr[1].str.p_str == '[')
  {
    DecodeAdr(&ArgStr[1], MModMem);
    if (AdrMode != ModNone)
    {
      if (MemPart != 2) WrError(ErrNum_InvAddrMode);
      else
      {
        BAsmCode[CodeLen++] = 0xc6;
        BAsmCode[CodeLen++] = AdrPart;
      }
    }
  }
  else
  {
    tEvalResult EvalResult;
    LongWord Dest = GetBranchDest(&ArgStr[1], &EvalResult);

    if (EvalResult.OK)
    {
      LongInt Dist = Dest - MkEven24(EProgCounter() + CodeLen + 3);

      if (ChkLongEvenDist(&Dist, &ArgStr[1], EvalResult.Flags))
      {
        BAsmCode[CodeLen++] = 0xc5;
        BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
        BAsmCode[CodeLen++] = Dist & 0xff;
      }
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "[A+DPTR]"))
  {
    BAsmCode[CodeLen++] = 0xd6;
    BAsmCode[CodeLen++] = 0x46;
  }
  else if (!strncmp(ArgStr[1].str.p_str, "[[", 2))
  {
    tStrComp Comp;

    ArgStr[1].str.p_str[strlen(ArgStr[1].str.p_str) - 1] = '\0';
    ArgStr[1].Pos.Len--;
    StrCompRefRight(&Comp, &ArgStr[1], 1);
    DecodeAdr(&Comp, MModMem);
    if (AdrMode == ModMem)
     switch (MemPart)
     {
       case 3:
         BAsmCode[CodeLen++] = 0xd6;
         BAsmCode[CodeLen++] = 0x60 + AdrPart;
         break;
       default:
         WrError(ErrNum_InvAddrMode);
     }
  }
  else if (*ArgStr[1].str.p_str == '[')
  {
    DecodeAdr(&ArgStr[1], MModMem);
    if (AdrMode == ModMem)
      switch (MemPart)
      {
        case 2:
          BAsmCode[CodeLen++] = 0xd6;
          BAsmCode[CodeLen++] = 0x70 + AdrPart;
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
  }
  else
  {
    tEvalResult EvalResult;
    LongWord Dest = GetBranchDest(&ArgStr[1], &EvalResult);

    if (EvalResult.OK)
    {
      LongInt Dist = Dest - MkEven24(EProgCounter() + CodeLen + 3);

      if (ChkLongEvenDist(&Dist, &ArgStr[1], EvalResult.Flags))
      {
        BAsmCode[CodeLen++] = 0xd5;
        BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
        BAsmCode[CodeLen++] = Dist & 0xff;
      }
    }
  }
}

static void DecodeCJNE(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(3, 3))
  {
    tEvalResult EvalResult;
    LongWord Dest = GetBranchDest(&ArgStr[3], &EvalResult);

    if (EvalResult.OK)
    {
      EvalResult.OK = False; HReg = 0;
      DecodeAdr(&ArgStr[1], MModMem);
      if (AdrMode == ModMem)
      {
        switch (MemPart)
        {
          case 1:
            if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              HReg = AdrPart; DecodeAdr(&ArgStr[2], MModMem | MModImm);
              switch (AdrMode)
              {
                case ModMem:
                  if (MemPart != 6) WrError(ErrNum_InvAddrMode);
                  else
                  {
                    BAsmCode[CodeLen] = 0xe2 + (OpSize << 3);
                    BAsmCode[CodeLen + 1] = (HReg << 4) + AdrPart;
                    BAsmCode[CodeLen + 2] = AdrVals[0];
                    HReg=CodeLen + 3;
                    CodeLen += 4; EvalResult.OK = True;
                  }
                  break;
                case ModImm:
                  BAsmCode[CodeLen] = 0xe3 + (OpSize << 3);
                  BAsmCode[CodeLen + 1] = HReg << 4;
                  HReg=CodeLen + 2;
                  memcpy(BAsmCode + CodeLen + 3, AdrVals, AdrCnt);
                  CodeLen += 3 + AdrCnt; EvalResult.OK = True;
                  break;
              }
            }
            break;
          case 2:
            if ((OpSize != eSymbolSizeUnknown) && (OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              HReg = AdrPart; DecodeAdr(&ArgStr[2], MModImm);
              if (AdrMode == ModImm)
              {
                BAsmCode[CodeLen] = 0xe3 + (OpSize << 3);
                BAsmCode[CodeLen + 1] = (HReg << 4)+8;
                HReg = CodeLen + 2;
                memcpy(BAsmCode + CodeLen + 3, AdrVals, AdrCnt);
                CodeLen += 3 + AdrCnt; EvalResult.OK = True;
              }
            }
            break;
          default:
            WrError(ErrNum_InvAddrMode);
        }
      }
      if (EvalResult.OK)
      {
        LongInt Dist = Dest - MkEven24(EProgCounter() + CodeLen);

        EvalResult.OK = False;
        if (ChkShortEvenDist(&Dist, EvalResult.Flags))
        {
          BAsmCode[HReg] = Dist & 0xff;
          EvalResult.OK = True;
        }
        else if (!DoBranchExt) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[3]);
        else
        {
          LongWord odd = (EProgCounter() + CodeLen) & 1;

          Dist = Dest - MkEven24(EProgCounter() + CodeLen + 5 + odd);
          if (ChkLongEvenDist(&Dist, &ArgStr[3], EvalResult.Flags))
          {
            BAsmCode[HReg] = 1 + odd;
            BAsmCode[CodeLen++] = 0xfe;
            BAsmCode[CodeLen++] = 2 + odd;
            if (odd) BAsmCode[CodeLen++] = 0;
            BAsmCode[CodeLen++] = 0xd5;
            BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
            BAsmCode[CodeLen++] = Dist        & 0xff;
            BAsmCode[CodeLen++] = 0;
            EvalResult.OK = True;
          }
        }
      }
      if (!EvalResult.OK)
        CodeLen = 0;
    }
  }
}

static void DecodeDJNZ(Word Index)
{
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    tEvalResult EvalResult;
    LongInt Dest = GetBranchDest(&ArgStr[2], &EvalResult);

    if (EvalResult.OK)
    {
      HReg = 0;
      DecodeAdr(&ArgStr[1], MModMem);
      EvalResult.OK = False; DecodeAdr(&ArgStr[1], MModMem);
      if (AdrMode == ModMem)
        switch (MemPart)
        {
          case 1:
            if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              BAsmCode[CodeLen] = 0x87 + (OpSize << 3);
              BAsmCode[CodeLen + 1] = (AdrPart << 4) + 0x08;
              HReg=CodeLen + 2;
              CodeLen += 3; EvalResult.OK = True;
            }
            break;
          case 6:
            if (OpSize == eSymbolSizeUnknown) WrError(ErrNum_UndefOpSizes);
            else if ((OpSize != eSymbolSize8Bit) && (OpSize != eSymbolSize16Bit)) WrError(ErrNum_InvOpSize);
            else
            {
              BAsmCode[CodeLen] = 0xe2 + (OpSize << 3);
              BAsmCode[CodeLen+1] = 0x08 + AdrPart;
              BAsmCode[CodeLen+2] = AdrVals[0];
              HReg=CodeLen + 3;
              CodeLen += 4; EvalResult.OK = True;
            }
            break;
          default:
            WrError(ErrNum_InvAddrMode);
        }
      if (EvalResult.OK)
      {
        LongInt Dist = Dest - MkEven24(EProgCounter() + CodeLen);

        EvalResult.OK = False;
        if (ChkShortEvenDist(&Dist, EvalResult.Flags))
        {
          BAsmCode[HReg] = Dist & 0xff;
          EvalResult.OK = True;
        }
        else if (!DoBranchExt) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[2]);
        else
        {
          LongWord odd = (EProgCounter() + CodeLen) & 1;

          Dist = Dest - MkEven24(EProgCounter() + CodeLen + 5 + odd);
          if (ChkLongEvenDist(&Dist, &ArgStr[2], EvalResult.Flags))
          {
            BAsmCode[HReg] = 1 + odd;
            BAsmCode[CodeLen++] = 0xfe;
            BAsmCode[CodeLen++] = 2 + odd;
            if (odd) BAsmCode[CodeLen++] = 0;
            BAsmCode[CodeLen++] = 0xd5;
            BAsmCode[CodeLen++] = (Dist >> 8) & 0xff;
            BAsmCode[CodeLen++] = Dist        & 0xff;
            BAsmCode[CodeLen++] = 0;
            EvalResult.OK = True;
          }
        }
      }
      if (!EvalResult.OK)
        CodeLen = 0;
    }
  }
}

static void DecodeFCALLJMP(Word Index)
{
  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else
  {
    tEvalResult EvalResult;
    LongInt AdrLong = GetBranchDest(&ArgStr[1], &EvalResult);
    if (EvalResult.OK)
    {
      BAsmCode[CodeLen++] = 0xc4 | (Index << 4);
      BAsmCode[CodeLen++] = (AdrLong >> 8) & 0xff;
      BAsmCode[CodeLen++] = AdrLong & 0xff;
      BAsmCode[CodeLen++] = (AdrLong >> 16) & 0xff;
    }
  }
}

static Boolean IsRealDef(void)
{
  switch (*OpPart.str.p_str)
  {
    case 'P':
      return Memo("PORT");
    case 'B':
      return Memo("BIT");
    case 'R':
      return Memo("REG");
    default:
      return FALSE;
  }
}

static void ForceAlign(void)
{
  if (EProgCounter() & 1)
  {
    BAsmCode[0] = NOPCode; CodeLen = 1;
  }
}

static Boolean DecodeAttrPart_XA(void)
{
  if (strlen(AttrPart.str.p_str) > 1)
  {
    WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
    return False;
  }

  if (*AttrPart.str.p_str)
    switch (as_toupper(*AttrPart.str.p_str))
    {
      case 'B': AttrPartOpSize[0] = eSymbolSize8Bit; break;
      case 'W': AttrPartOpSize[0] = eSymbolSize16Bit; break;
      case 'D': AttrPartOpSize[0] = eSymbolSize32Bit; break;
      default : WrStrErrorPos(ErrNum_UndefAttr, &AttrPart); return False;
    }
  return True;
}

static void MakeCode_XA(void)
{
  /* Operandengroesse */

  OpSize = eSymbolSizeUnknown;
  if (*AttrPart.str.p_str)
    SetOpSize(AttrPartOpSize[0]);

  /* Labels muessen auf geraden Adressen liegen.
     TODO: Do not enforce for DB...DO, DC/DS */

  if ( (ActPC == SegCode) && (!IsRealDef()) &&
       ((*LabPart.str.p_str != '\0') ||((ArgCnt == 1) && (!strcmp(ArgStr[1].str.p_str, "$")))) )
  {
    ForceAlign();
    if (*LabPart.str.p_str != '\0')
      EnterIntSymbol(&LabPart, EProgCounter() + CodeLen, (as_addrspace_t)ActPC, False);
  }

  /* via Tabelle suchen */

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

/*-------------------------------------------------------------------------*/
/* Codetabellenverwaltung */

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

static void AddJBit(const char *NName, Word NCode)
{
  order_array_rsv_end(JBitOrders, InvOrder);
  JBitOrders[InstrZ].Name = NName;
  JBitOrders[InstrZ].Inversion = 255;
  JBitOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeJBit);
}

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

static void AddReg(const char *NName, Byte NMask, Byte NCode)
{
  order_array_rsv_end(RegOrders, RegOrder);
  RegOrders[InstrZ].Code = NCode;
  RegOrders[InstrZ].SizeMask = NMask;
  AddInstTable(InstTable, NName, InstrZ++, DecodeRegO);
}

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

static void AddRel(const char *NName, Word NCode)
{
  order_array_rsv_end(RelOrders, InvOrder);
  RelOrders[InstrZ].Name = NName;
  RelOrders[InstrZ].Inversion = 255;
  RelOrders[InstrZ].Code = NCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeRel);
}

static void SetInv(const char *Name1, const char *Name2, InvOrder *Orders)
{
  InvOrder *Order1, *Order2;

  for (Order1 = Orders; strcmp(Order1->Name, Name1); Order1++);
  for (Order2 = Orders; strcmp(Order2->Name, Name2); Order2++);
  Order1->Inversion = Order2 - Orders;
  Order2->Inversion = Order1 - Orders;
}

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

  add_null_pseudo(InstTable);

  AddInstTable(InstTable, "MOV"  , 0, DecodeMOV);
  AddInstTable(InstTable, "MOVC" , 0, DecodeMOVC);
  AddInstTable(InstTable, "MOVX" , 0, DecodeMOVX);
  AddInstTable(InstTable, "XCH"  , 0, DecodeXCH);
  AddInstTable(InstTable, "ADDS" , 0, DecodeADDSMOVS);
  AddInstTable(InstTable, "MOVS" , 1, DecodeADDSMOVS);
  AddInstTable(InstTable, "DIV"  , 0, DecodeDIV);
  AddInstTable(InstTable, "DIVU" , 0, DecodeDIVU);
  AddInstTable(InstTable, "MUL"  , 0, DecodeMUL);
  AddInstTable(InstTable, "MULU" , 0, DecodeMULU);
  AddInstTable(InstTable, "LEA"  , 0, DecodeLEA);
  AddInstTable(InstTable, "ANL"  , 0, DecodeANLORL);
  AddInstTable(InstTable, "ORL"  , 1, DecodeANLORL);
  AddInstTable(InstTable, "CLR"  , 0, DecodeCLRSETB);
  AddInstTable(InstTable, "SETB" , 1, DecodeCLRSETB);
  AddInstTable(InstTable, "TRAP" , 0, DecodeTRAP);
  AddInstTable(InstTable, "CALL" , 0, DecodeCALL);
  AddInstTable(InstTable, "JMP"  , 0, DecodeJMP);
  AddInstTable(InstTable, "CJNE" , 0, DecodeCJNE);
  AddInstTable(InstTable, "DJNZ" , 0, DecodeDJNZ);
  AddInstTable(InstTable, "FCALL", 0, DecodeFCALLJMP);
  AddInstTable(InstTable, "FJMP" , 1, DecodeFCALLJMP);
  AddInstTable(InstTable, "PORT" , 0, DecodePORT);
  AddInstTable(InstTable, "BIT"  , 0, DecodeBIT);
  AddInstTable(InstTable, "REG"  , 0, CodeREG);

  AddFixed("NOP"  , 0x0000);
  AddFixed("RET"  , 0xd680);
  AddFixed("RETI" , RETICode);
  AddFixed("BKPT" , 0x00ff);
  AddFixed("RESET", 0xd610);

  InstrZ = 0;
  AddJBit("JB"  , 0x80);
  AddJBit("JBC" , 0xc0);
  AddJBit("JNB" , 0xa0);
  SetInv("JB", "JNB", JBitOrders);

  AddStack("POP"  , 0x1027);
  AddStack("POPU" , 0x0037);
  AddStack("PUSH" , 0x3007);
  AddStack("PUSHU", 0x2017);

  InstrZ = 0;
  AddInstTable(InstTable, "ADD" , InstrZ++, DecodeALU);
  AddInstTable(InstTable, "ADDC", InstrZ++, DecodeALU);
  AddInstTable(InstTable, "SUB" , InstrZ++, DecodeALU);
  AddInstTable(InstTable, "SUBB", InstrZ++, DecodeALU);
  AddInstTable(InstTable, "CMP" , InstrZ++, DecodeALU);
  AddInstTable(InstTable, "AND" , InstrZ++, DecodeALU);
  AddInstTable(InstTable, "OR"  , InstrZ++, DecodeALU);
  AddInstTable(InstTable, "XOR" , InstrZ++, DecodeALU);

  InstrZ = 0;
  AddReg("NEG" , 3, 0x0b);
  AddReg("CPL" , 3, 0x0a);
  AddReg("SEXT", 3, 0x09);
  AddReg("DA"  , 1, 0x08);

  AddInstTable(InstTable, "LSR" , 0, DecodeShift);
  AddInstTable(InstTable, "ASL" , 1, DecodeShift);
  AddInstTable(InstTable, "ASR" , 2, DecodeShift);
  AddInstTable(InstTable, "NORM", 3, DecodeShift);

  AddRotate("RR" , 0xb0); AddRotate("RL" , 0xd3);
  AddRotate("RRC", 0xb7); AddRotate("RLC", 0xd7);

  InstrZ = 0;
  AddRel("BCC", 0xf0); AddRel("BCS", 0xf1); AddRel("BNE", 0xf2);
  AddRel("BEQ", 0xf3); AddRel("BNV", 0xf4); AddRel("BOV", 0xf5);
  AddRel("BPL", 0xf6); AddRel("BMI", 0xf7); AddRel("BG" , 0xf8);
  AddRel("BL" , 0xf9); AddRel("BGE", 0xfa); AddRel("BLT", 0xfb);
  AddRel("BGT", 0xfc); AddRel("BLE", 0xfd); AddRel("BR" , 0xfe);
  AddRel("JZ" , 0xec); AddRel("JNZ", 0xee);
  SetInv("BCC", "BCS", RelOrders);
  SetInv("BNE", "BEQ", RelOrders);
  SetInv("BNV", "BOV", RelOrders);
  SetInv("BPL", "BMI", RelOrders);
  SetInv("BG" , "BL" , RelOrders);
  SetInv("BGE", "BLT", RelOrders);
  SetInv("BGT", "BLE", RelOrders);
  SetInv("JZ" , "JNZ", RelOrders);

  AddIntelPseudo(InstTable, eIntPseudoFlag_LittleEndian);
  AddInstTable(InstTable, "DC", e_moto_pseudo_flags_le, DecodeMotoDC);
}

static void DeinitFields(void)
{
  order_array_free(JBitOrders);
  order_array_free(RegOrders);
  order_array_free(RelOrders);

  DestroyInstTable(InstTable);
}

/*-------------------------------------------------------------------------*/
/* Callbacks */

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

static void InternSymbol_XA(char *pArg, TempResult *pResult)
{
  Byte Reg;
  tSymbolSize Size;

  if (*AttrPart.str.p_str)
    OpSize = AttrPartOpSize[0];

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

static void InitCode_XA(void)
{
  Reg_DS = 0;
}

static Boolean ChkPC_XA(LargeWord Addr)
{
  switch (ActPC)
  {
    case SegCode:
    case SegData:
      return (Addr<0x1000000);
    case SegIO:
      return ((Addr > 0x3ff) && (Addr < 0x800));
    default:
      return False;
  }
}

static Boolean IsDef_XA(void)
{
  return (ActPC == SegCode) || IsRealDef();
}

static void SwitchTo_XA(void)
{
  const TFamilyDescr *p_descr = FindFamilyByName("XA");

  TurnWords = False;
  SetIntConstMode(eIntConstModeIntel);

  PCSymbol = "$";
  HeaderID = p_descr->Id;
  NOPCode = 0x00;
  DivideChars = ",";
  HasAttrs = True;
  AttrChars = ".";

  ValidSegs =(1 << SegCode) | (1 << SegData) | (1 << SegIO);
  Grans[SegCode ] = 1; ListGrans[SegCode ] = 1; SegInits[SegCode ] = 0;
  Grans[SegData ] = 1; ListGrans[SegData ] = 1; SegInits[SegData ] = 0;
  Grans[SegIO   ] = 1; ListGrans[SegIO   ] = 1; SegInits[SegIO   ] = 0x400;

  DecodeAttrPart = DecodeAttrPart_XA;
  MakeCode = MakeCode_XA;
  ChkPC = ChkPC_XA;
  IsDef = IsDef_XA;
  InternSymbol = InternSymbol_XA;
  DissectReg = DissectReg_XA;
  SwitchFrom = DeinitFields; InitFields();
  onoff_supmode_add();
  if (!onoff_test_and_set(e_onoff_reg_branchext))
    SetFlag(&DoBranchExt, BranchExtSymName, False);
  AddONOFF(BranchExtCmdName, &DoBranchExt, BranchExtSymName , False);
  AddMoto16PseudoONOFF(False);

  assume_set(ASSUMEXAs, as_array_size(ASSUMEXAs));
}

void codexa_init(void)
{
  CPUXAG1 = AddCPU("XAG1", SwitchTo_XA);
  CPUXAG2 = AddCPU("XAG2", SwitchTo_XA);
  CPUXAG3 = AddCPU("XAG3", SwitchTo_XA);

  AddInitPassProc(InitCode_XA);
}
