/* code78k4.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator 78K4-Familie                                                */
/*                                                                           */
/*****************************************************************************/

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

#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "assume.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "headids.h"
#include "errmsg.h"

#include "code78k4.h"

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

typedef enum
{
  ModNone = -1,
  ModImm = 0,
  ModReg8,
  ModReg8_U16,
  ModReg16,
  ModReg24,
  ModMem,
  ModShort1,
  ModShort2,
  ModSFR,
  ModAbs16,
  ModAbs20,
  ModAbs24,
  ModShortIndir1_16,
  ModShortIndir2_16,
  ModShortIndir1_24,
  ModShortIndir2_24,
  ModSP,
  ModSTBC,
  ModWDM,
  ModPSW  /* no associated mask, only used for PUSH/POP! */
} tAdrMode;

typedef enum
{
  eBitTypePSW = 2,
  eBitTypeAX = 3,
  eBitTypeSAddr2_SFR = 4,
  eBitTypeSAddr1 = 5,
  eBitTypeAbs = 6,
  eBitTypeMem = 13
} tBitType;

typedef LongWord tAdrModeMask;

static const Word PSWLAddr = 0xfffe,
                  PSWHAddr = 0xffff;
static const ShortInt WHLReg = 3;
static const LongWord Bit27 = ((LongWord)1) << 27;

static const tAdrModeMask MModImm = (1UL << ModImm),
                          MModReg8 = (1UL << ModReg8),
                          MModReg8_U16 = (1UL << ModReg8_U16),
                          MModReg16 = (1UL << ModReg16),
                          MModReg24 = (1UL << ModReg24),
                          MModMem = (1UL << ModMem),
                          MModShort1 = (1UL << ModShort1),
                          MModShort2 = (1UL << ModShort2),
                          MModSFR = (1UL << ModSFR),
                          MModAbs16 = (1UL << ModAbs16),
                          MModAbs20 = (1UL << ModAbs20),
                          MModAbs24 = (1UL << ModAbs24),
                          MModAbsAll = ((1UL << ModAbs16) | (1UL << ModAbs24)),
                          MModShortIndir1_16 = (1UL << ModShortIndir1_16),
                          MModShortIndir2_16 = (1UL << ModShortIndir2_16),
                          MModShortIndir1_24 = (1UL << ModShortIndir1_24),
                          MModShortIndir2_24 = (1UL << ModShortIndir2_24),
                          MModShortIndir_All = ((1UL << ModShortIndir1_16) | (1UL << ModShortIndir2_16) | (1UL << ModShortIndir1_24) | (1UL << ModShortIndir2_24)),
                          MModSP = (1UL << ModSP),
                          MModSTBC = (1UL << ModSTBC),
                          MModWDM = (1UL << ModWDM);

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

static CPUVar CPU784026;

typedef struct
{
  tAdrMode AdrMode;
  ShortInt AdrVal;
  int AdrCnt;
  Byte AdrVals[4];
  tSymbolFlags AdrValSymFlags;
  Byte ForceRel;
  Boolean ForceAbs;
} tEncodedAddress;

static ShortInt OpSize;
static Boolean AssumeByte;

static LongInt Reg_RSS, Reg_LOCATION;
static as_assume_rec_t ASSUME78K4s[] =
{
  {"RSS"      , &Reg_RSS      , 0,  0x1,  0x0, NULL},
  {"LOCATION" , &Reg_LOCATION , 0,  0xf,  0x0, NULL},
};

/*-------------------------------------------------------------------------*/
/* Address Decoders */

static Byte AccReg8(void)
{
  return Reg_RSS ? 5 : 1;
}

static Byte BReg8(void)
{
  return Reg_RSS ? 7 : 3;
}

static Byte CReg8(void)
{
  return Reg_RSS ? 6 : 2;
}

static Byte AccReg16(void)
{
  return Reg_RSS ? 2 : 0;
}

static Boolean SetOpSize(ShortInt NewSize)
{
  if (OpSize < 0)
  {
    OpSize = NewSize;
    return True;
  }
  else if (OpSize != NewSize)
  {
    char Sizes[30];

    as_snprintf(Sizes, sizeof(Sizes), "%d<->%d",
                (int)((OpSize + 1) * 8), (int)((NewSize + 1) * 8));
    WrXError(ErrNum_ConfOpSizes, Sizes);
    return False;
  }
  else
    return True;
}

static void ClearEncodedAddress(tEncodedAddress *pAddress)
{
  pAddress->AdrMode = ModNone;
  pAddress->AdrVal = 0;
  pAddress->AdrCnt = 0;
  pAddress->ForceAbs = 0;
  pAddress->ForceRel = False;
}

static ShortInt DecodeReg8(const char *pAsc)
{
  switch (strlen(pAsc))
  {
    case 1:
    {
      static const char Reg8Names[9] = "XACBEDLH";
      const char *pPos = strchr(Reg8Names, as_toupper(*pAsc));

      if (pPos)
      {
        ShortInt Result = pPos - Reg8Names;
        /* E/D/L/H maps to R12..R15 */
        if (Result >= 4)
          return Result + 8;
        /* X/A/C/B maps to R4..7 if RSS=1 */
        else if (Reg_RSS)
          return Result + 4;
        else
          return Result;
      }
      else
        return -1;
    }

    case 2:
      if ((toupper(pAsc[0]) == 'R') && isdigit(pAsc[1]))
        return pAsc[1] - '0';
      else
        return -1;

    case 3:
    {
      static const char Reg8Names[][4] = { "VPL", "VPH", "UPL", "UPH", "R10", "R11", "R12", "R13", "R14", "R15", "" };
      int z;

      for (z = 0; *Reg8Names[z]; z++)
        if (!as_strcasecmp(pAsc, Reg8Names[z]))
        {
          /* map to 8..11 resp. 10..15 */
          return (z > 4) ? z + 6 : z + 8;
        }
      return -1;
    }

    default:
      return -1;
  }
}

static ShortInt DecodeReg8_U16(const char *pAsc)
{
  static const char Reg8Names[5] = "VUTW";
  const char *pPos;

  if (strlen(pAsc) != 1)
    return -1;
  pPos = strchr(Reg8Names, as_toupper(*pAsc));
  return pPos ? pPos - Reg8Names : -1;
}

static ShortInt DecodeReg16(const char *pAsc)
{
  ShortInt Result = -1;

  switch (strlen(pAsc))
  {
    case  2:
    {
      static const char Reg16Names[][3] = { "AX", "BC", "VP", "UP", "DE", "HL", "" };
      int z;

      for (z = 0; *Reg16Names[z]; z++)
        if (!as_strcasecmp(Reg16Names[z], pAsc))
        {
          Result = ((z >= 2) || Reg_RSS) ? z + 2 : z;
          break;
        }
      break;
    }

    case 3:
    {
      if ((toupper(pAsc[0]) == 'R') && (toupper(pAsc[1]) == 'P')
       && (pAsc[2] >= '0') && (pAsc[2] <= '7'))
        Result = pAsc[2] - '0';

      break;
    }
  }

  return Result;
}

static ShortInt DecodeReg24(const char *pAsc)
{
  static const char Reg24Names[][4] = { "VVP", "UUP", "TDE", "WHL", "RG4", "RG5", "RG6", "RG7", "" };
  int z;

  for (z = 0; *Reg24Names[z]; z++)
    if (!as_strcasecmp(Reg24Names[z], pAsc))
      return (z & 3);

  return -1;
}

static Boolean DecodeRB(const char *pAsc, Byte *pErg)
{
  if ((strlen(pAsc) != 3) || (toupper(*pAsc) != 'R') || (toupper(pAsc[1]) != 'B') || (pAsc[2] < '0') || (pAsc[2] > '7'))
    return False;
  else
  {
    *pErg = pAsc[2] - '0';
    return True;
  }
}

static void ExecAssumeByte(void)
{
  if ((OpSize == -1) && AssumeByte)
  {
    SetOpSize(0);
    AssumeByte = False;
  }
}

static Boolean ChkSAddr1(LongWord Addr, Byte *pShortAddr)
{
  LongWord Start = 0xfe00 + (Reg_LOCATION << 16);

  if ((Addr & 0xffff00) == (Start & 0xffff00))
  {
    *pShortAddr = Addr & 0xff;
    return True;
  }
  else
    return False;
}

static Boolean ChkSAddr2(LongWord Addr, Byte *pShortAddr)
{
  LongWord Start1 = 0xff00 + (Reg_LOCATION << 16),
           Start2 = 0xfd00 + (Reg_LOCATION << 16);

  if ((Addr & 0xffffe0) == Start1)
  {
    *pShortAddr = Addr & 0x1f;
    return True;
  }
  else if (((Addr & 0xffff00) == Start2) && (Lo(Addr) >= 0x20))
  {
    *pShortAddr = Addr & 0x1f;
    return True;
  }
  else
    return False;
}

static Boolean ChkSFR(LongWord Addr, Byte *pShortAddr)
{
  LongWord Start = 0xff00 + (Reg_LOCATION << 16);

  if ((Addr & 0xffff00) == (Start & 0xffff00))
  {
    *pShortAddr = Addr & 0xff;
    return True;
  }
  else
    return False;
}

static Boolean StripIndirect(tStrComp *pArg)
{
  int ArgLen = strlen(pArg->str.p_str);

  if ((ArgLen >= 2) && (*pArg->str.p_str == '[') && (pArg->str.p_str[ArgLen - 1] == ']'))
  {
    strmov(pArg->str.p_str, pArg->str.p_str + 1);
    pArg->str.p_str[ArgLen - 2] = '\0';
    pArg->Pos.StartCol++;
    pArg->Pos.Len -= 2;
    return True;
  }
  else
    return False;
}

static Boolean DecodeAdr(const tStrComp *pArg, tAdrModeMask AdrModeMask, tEncodedAddress *pAddress)
{
  int z, ArgLen;
  LongWord Addr;
  ShortInt AddrSize;
  Boolean OK, Is16, IsShort1, IsShort2, IsSFR;
  unsigned Offset;

  ClearEncodedAddress(pAddress);

  /* 8 bit Register? */

  if ((pAddress->AdrVal = DecodeReg8(pArg->str.p_str)) >= 0)
  {
    if (!SetOpSize(0))
      return False;
    pAddress->AdrMode = ModReg8;
    goto AdrFound;
  }

  if ((pAddress->AdrVal = DecodeReg8_U16(pArg->str.p_str)) >= 0)
  {
    if (!SetOpSize(0))
      return False;
    pAddress->AdrMode = ModReg8_U16;
    goto AdrFound;
  }

  if ((pAddress->AdrVal = DecodeReg16(pArg->str.p_str)) >= 0)
  {
    if (!SetOpSize(1))
      return False;
    pAddress->AdrMode = ModReg16;
    goto AdrFound;
  }

  if ((pAddress->AdrVal = DecodeReg24(pArg->str.p_str)) >= 0)
  {
    if (!SetOpSize(2))
      return False;
    pAddress->AdrMode = ModReg24;
    goto AdrFound;
  }

  if (!as_strcasecmp(pArg->str.p_str, "SP"))
  {
    if (!SetOpSize(2))
      return False;
    pAddress->AdrMode = ModSP;
    goto AdrFound;
  }

  if (!as_strcasecmp(pArg->str.p_str, "STBC"))
  {
    if (!SetOpSize(0))
      return False;
    pAddress->AdrMode = ModSTBC;
    goto AdrFound;
  }

  if (!as_strcasecmp(pArg->str.p_str, "WDM"))
  {
    if (!SetOpSize(0))
      return False;
    pAddress->AdrMode = ModWDM;
    goto AdrFound;
  }

  /* immediate ? */

  if (*pArg->str.p_str == '#')
  {
    ExecAssumeByte();
    if ((OpSize >= 0) && (OpSize < 3))
    {
      static const IntType IntTypes[3] = { Int8, Int16, Int24 };
      Boolean OK;
      LongWord Value = EvalStrIntExpressionOffs(pArg, 1, IntTypes[OpSize], &OK);
      if (OK)
      {
        ShortInt z;

        for (z = 0; z <= OpSize; z++)
        {
          pAddress->AdrVals[pAddress->AdrCnt++] = Value & 0xff;
          Value >>= 8;
        }
        pAddress->AdrMode = ModImm;
      }
    }
    else
      WrError(ErrNum_UndefOpSizes);
    goto AdrFound;
  }

  /* memory-indirect addressing? */

  ArgLen = strlen(pArg->str.p_str);
  if ((ArgLen >= 2) && (pArg->str.p_str[ArgLen - 1] == ']'))
  {
    String Asc;
    tStrComp Arg;
    char *pStart;

    StrCompMkTemp(&Arg, Asc, sizeof(Asc));
    StrCompCopy(&Arg, pArg);

    /* remove ']' */

    StrCompShorten(&Arg, 1);

    pStart = RQuotPos(Arg.str.p_str, '[');
    if (!pStart)
    {
      WrError(ErrNum_BrackErr);
      goto AdrFound;
    }

    /* purely indirect? */

    if (pStart == Arg.str.p_str)
    {
      static const char Modes[][5] = { "TDE+", "WHL+", "TDE-", "WHL-", "TDE", "WHL", "VVP", "UUP",
                                       "RG6+", "RG7+", "RG6-", "RG7-", "RG6", "RG7", "RG4", "RG5" };
      unsigned z;
      char *pSep, Save;
      tStrComp Base, Remainder;

      /* skip '[' */

      StrCompCutLeft(&Arg, 1);

      /* simple expression without displacement? */

      for (z = 0; z < sizeof(Modes) / sizeof(*Modes); z++)
        if (!as_strcasecmp(Arg.str.p_str, Modes[z]))
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x16;
          pAddress->AdrVals[0] = z % (sizeof(Modes) / sizeof(*Modes) / 2);
          pAddress->AdrCnt = 1;
          goto AdrFound;
        }

      /* no -> extract base register. Its name ends with the first non-letter,
         which either means +/- or a blank */

      for (pSep = Arg.str.p_str; *pSep; pSep++)
        if (!as_isalpha(*pSep))
          break;

      /* decode base register.  SP is not otherwise handled. */

      Save = StrCompSplitRef(&Base, &Remainder, &Arg, pSep);
      if (!as_strcasecmp(Base.str.p_str, "SP"))
        pAddress->AdrVals[0] = 1;
      else
      {
        int tmp;

        tmp = DecodeReg24(Base.str.p_str);
        switch (tmp)
        {
          case -1: pAddress->AdrVals[0] = 0xff; break; /* no register */
          case 0: pAddress->AdrVals[0] = 4; break; /* VVP */
          case 1: pAddress->AdrVals[0] = 3; break; /* UUP */
          case 2: pAddress->AdrVals[0] = 0; break; /* TDE */
          case 3: pAddress->AdrVals[0] = 2; break; /* WHL */
          default:
            WrStrErrorPos(ErrNum_InvReg, &Base);
            goto AdrFound;
        }
      }
      *pSep = Save;

      /* no base register detected: purely indirect */

      if (0xff == pAddress->AdrVals[0])
      {
        unsigned Is24 = !!(*Arg.str.p_str == '%');
        tSymbolFlags Flags;

        Addr = EvalStrIntExpressionOffsWithFlags(&Arg, Is24, UInt24, &OK, &Flags);
        if (OK)
        {
          if (mFirstPassUnknown(Flags))
            Addr = 0xfe20 + (Reg_LOCATION << 16);
          if (ChkSAddr1(Addr, &pAddress->AdrVals[0]))
            pAddress->AdrMode = Is24 ? ModShortIndir1_24 : ModShortIndir1_16;
          if (ChkSAddr2(Addr, &pAddress->AdrVals[0]))
            pAddress->AdrMode = Is24 ? ModShortIndir2_24 : ModShortIndir2_16;
        }
        goto AdrFound;
      }

      /* Now that we have the base, prepare displacement.  May
         be an 8/16-bit register in certain combinations, or a number: */

      if (*pSep == '+')
      {
        int tmp;

        tmp = DecodeReg8(pSep + 1);
        if (tmp == -1); /* no reg at all, go on with 16-bit reg below */
        else if ((tmp == AccReg8()) && (pAddress->AdrVals[0] == 0)) /* TDE + A */
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x17;
          pAddress->AdrCnt = 1;
          pAddress->AdrVals[0] = 0;
          goto AdrFound;
        }
        else if ((tmp == BReg8()) && (pAddress->AdrVals[0] == 0)) /* TDE + B */
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x17;
          pAddress->AdrCnt = 1;
          pAddress->AdrVals[0] = 2;
          goto AdrFound;
        }
        else if ((tmp == CReg8()) && (pAddress->AdrVals[0] == 0)) /* TDE + C */
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x17;
          pAddress->AdrCnt = 1;
          pAddress->AdrVals[0] = 6;
          goto AdrFound;
        }
        else if ((tmp == AccReg8()) && (pAddress->AdrVals[0] == 2)) /* WHL + A */
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x17;
          pAddress->AdrCnt = 1;
          pAddress->AdrVals[0] = 1;
          goto AdrFound;
        }
        else if ((tmp == BReg8()) && (pAddress->AdrVals[0] == 2)) /* WHL + B */
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x17;
          pAddress->AdrCnt = 1;
          pAddress->AdrVals[0] = 3;
          goto AdrFound;
        }
        else if ((tmp == CReg8()) && (pAddress->AdrVals[0] == 2)) /* WHL + C */
        {
          pAddress->AdrMode = ModMem;
          pAddress->AdrVal = 0x17;
          pAddress->AdrCnt = 1;
          pAddress->AdrVals[0] = 7;
          goto AdrFound;
        }
        else
        {
          WrError(ErrNum_InvAddrMode);
          goto AdrFound;
        }
        tmp = DecodeReg16(pSep + 1);
        switch (tmp)
        {
          case -1: /* no reg at all */
            break;
          case 6: /* DE */
          case 7: /* HL */
            if (pAddress->AdrVals[0] == 4) /* VVP+DE/HL */
            {
              pAddress->AdrMode = ModMem;
              pAddress->AdrVal = 0x17;
              pAddress->AdrCnt = 1;
              pAddress->AdrVals[0] = tmp - 2;
              goto AdrFound;
            }
            /* fall-through */
          default:
            WrError(ErrNum_InvAddrMode);
            goto AdrFound;
        }
      }

      /* it's a number: put a fake 0 in front so displacement expression evaluates correctly! */

      if (pSep > Arg.str.p_str)
        pSep--;
      *pSep = '0';
      pAddress->AdrVals[1] = EvalStrIntExpressionOffs(&Arg, pSep - Arg.str.p_str, Int8, &OK);
      if (OK)
      {
        pAddress->AdrMode = ModMem;
        pAddress->AdrVal = 0x06;
        pAddress->AdrCnt = 2;
        goto AdrFound;
      }
    }

    /* no -> with outer displacement */

    else
    {
      tStrComp RegArg, DispArg;
      int tmp;

      /* split displacement + register */

      StrCompSplitRef(&DispArg, &RegArg, &Arg, pStart);

       /* handle base register */

      tmp = DecodeReg8(RegArg.str.p_str);
      if ((tmp == AccReg8()) /* A */
       || (tmp == BReg8())) /* B */
      {
        pAddress->AdrVals[0] = tmp & 3;
      }
      else if (tmp == -1)
      {
        tmp = DecodeReg16(RegArg.str.p_str);
        if (tmp >= 6) /* DE/HL */
        {
          pAddress->AdrVals[0] = (tmp - 6) << 1;
        }
        else
        {
          WrStrErrorPos(ErrNum_InvReg, &RegArg);
          goto AdrFound;
        }
      }
      else
      {
        WrStrErrorPos(ErrNum_InvReg, &RegArg);
        goto AdrFound;
      }

      /* compute displacement */

      Addr = EvalStrIntExpression(&DispArg, Int24, &OK);
      if (OK)
      {
        pAddress->AdrMode = ModMem;
        pAddress->AdrVal = 0x0a;
        pAddress->AdrVals[1] = (Addr >>  0) & 0xff;
        pAddress->AdrVals[2] = (Addr >>  8) & 0xff;
        pAddress->AdrVals[3] = (Addr >> 16) & 0xff;
        pAddress->AdrCnt = 4;
        goto AdrFound;
      }
    }
  } /* indirect */

  /* absolute: */

  Offset = 0;
  if (pArg->str.p_str[Offset] == '$')
  {
    pAddress->ForceRel = True;
    Offset++;
  }
  for (AddrSize = 0, z = 0; z < 2; z++)
    if (pArg->str.p_str[Offset] == '!')
    {
      AddrSize++;
      Offset++;
      pAddress->ForceAbs++;
    }
  Addr = EvalStrIntExpressionOffsWithFlags(pArg, Offset, (AdrModeMask & MModAbs20) ? UInt20 : UInt24, &OK, &pAddress->AdrValSymFlags);
  if (!OK)
    return False;

  IsShort1 = ChkSAddr1(Addr, &pAddress->AdrVals[0]);
  IsShort2 = ChkSAddr2(Addr, &pAddress->AdrVals[1]);
  IsSFR = ChkSFR(Addr, &pAddress->AdrVals[2]);
  Is16 = Addr <= 0xffff;

  if (!AddrSize)
  {
    if (!IsShort1 && !IsShort2 && !IsSFR && !Is16 && (AdrModeMask & (MModAbs24 | MModAbs20)))
      AddrSize = 2;
    else if (!IsShort1 && !IsShort2 && !IsSFR && Is16 && (!(AdrModeMask & MModAbs16)))
      AddrSize = 2;
    else if (!IsShort1 && !IsShort2 && !IsSFR && (AdrModeMask & MModAbs16))
      AddrSize = 1;
  }

  switch (AddrSize)
  {
    case 2:
      pAddress->AdrMode = (AdrModeMask & MModAbs20) ? ModAbs20 : ModAbs24;
      pAddress->AdrVals[pAddress->AdrCnt++] = (Addr >>  0) & 0xff;
      pAddress->AdrVals[pAddress->AdrCnt++] = (Addr >>  8) & 0xff;
      pAddress->AdrVals[pAddress->AdrCnt++] = (Addr >> 16) & 0xff;
      break;
    case 1:
      if (!Is16 && mFirstPassUnknown(pAddress->AdrValSymFlags))
      {
        Addr &= 0xffff;
        Is16 = True;
      }
      if (Is16)
      {
        pAddress->AdrMode = ModAbs16;
        pAddress->AdrVals[pAddress->AdrCnt++] = (Addr >>  0) & 0xff;
        pAddress->AdrVals[pAddress->AdrCnt++] = (Addr >>  8) & 0xff;
      }
      else
        WrError(ErrNum_OverRange);
      break;
    case 0:
      if (IsShort1)
      {
        pAddress->AdrMode = ModShort1;
        pAddress->AdrCnt++;
      }
      else if (IsShort2)
      {
        pAddress->AdrMode = ModShort2;
        pAddress->AdrVals[pAddress->AdrCnt++] = pAddress->AdrVals[1];
      }
      else if (IsSFR)
      {
        pAddress->AdrMode = ModSFR;
        pAddress->AdrVals[pAddress->AdrCnt++] = pAddress->AdrVals[2];
      }
      else if (mFirstPassUnknown(pAddress->AdrValSymFlags))
      {
        if (AdrModeMask & MModShort1)
        {
          pAddress->AdrMode = ModShort1;
          pAddress->AdrVals[pAddress->AdrCnt++] = Lo(Addr);
        }
        else if (AdrModeMask & MModShort2)
        {
          pAddress->AdrMode = ModShort2;
          pAddress->AdrVals[pAddress->AdrCnt++] = Lo(Addr);
        }
        else if (AdrModeMask & MModSFR)
        {
          pAddress->AdrMode = ModSFR;
          pAddress->AdrVals[pAddress->AdrCnt++] = Lo(Addr);
        }
        else
          WrError(ErrNum_InvAddrMode);
      }
      else
        WrError(ErrNum_OverRange);
      break;
  }

AdrFound:
  if ((pAddress->AdrMode != ModNone) && (!(AdrModeMask & (1UL << pAddress->AdrMode))))
  {
    WrError(ErrNum_InvAddrMode);
    ClearEncodedAddress(pAddress);
    return False;
  }
  return True;
}

static Boolean DecodeMem3(const char *pAsc, Byte *pResult)
{
  int l = strlen(pAsc);
  char Reg[10];
  ShortInt BinReg;

  if ((l < 3) || (l > 5) || (pAsc[0] != '[') || (pAsc[l - 1] != ']'))
    return False;
  memcpy(Reg, pAsc + 1, l - 2);
  Reg[l - 2] = '\0';
  BinReg = DecodeReg16(Reg);
  if ((BinReg >= 0) && (BinReg <= 3))
  {
    *pResult = (BinReg << 1);
    return True;
  }
  BinReg = DecodeReg24(Reg);
  if ((BinReg >= 0) && (BinReg <= 3))
  {
    *pResult = (BinReg << 1) | 1;
    return True;
  }
  return False;
}

static void AppendAdrVals(const tEncodedAddress *pAddress)
{
  /* weird byte order for !!abs24: */

  if (pAddress->AdrMode == ModAbs24)
  {
    BAsmCode[CodeLen++] = pAddress->AdrVals[2];
    BAsmCode[CodeLen++] = pAddress->AdrVals[0];
    BAsmCode[CodeLen++] = pAddress->AdrVals[1];
  }
  else
  {
    memcpy(BAsmCode + CodeLen, pAddress->AdrVals, pAddress->AdrCnt);
    CodeLen += pAddress->AdrCnt;
  }
}

static void AppendAdrValsMem(const tEncodedAddress *pAddress, Byte LowNibble)
{
  AppendAdrVals(pAddress);
  BAsmCode[CodeLen - pAddress->AdrCnt] = (BAsmCode[CodeLen - pAddress->AdrCnt] << 4) | LowNibble;
}

static Byte ModShortVal(tAdrMode AdrMode)
{
  switch (AdrMode)
  {
    case ModShort2:
      return 0;
    case ModShort1:
      return 1;
    case ModSFR:
      return 2;
    default:
      return 255;
  }
}

static LongWord GetAbsVal(const tEncodedAddress *pAddress)
{
  LongWord Result = 0;

  switch (pAddress->AdrMode)
  {
    case ModAbs24:
    case ModAbs20:
      Result |= (((LongWord)pAddress->AdrVals[2]) << 16);
      /* fall-through */
    case ModAbs16:
      Result |= (((LongWord)pAddress->AdrVals[1]) <<  8);
      Result |= (((LongWord)pAddress->AdrVals[0]) <<  0);
      return Result;
    default:
      return 0xfffffffful;
  }
}

static Byte ModIs24(tAdrMode AdrMode)
{
  switch (AdrMode)
  {
    case ModAbs24:
    case ModShortIndir1_24:
    case ModShortIndir2_24:
      return 1;
    case ModAbs16:
    case ModShortIndir1_16:
    case ModShortIndir2_16:
      return 0;
    default:
      return 0xff;
  }
}

static Byte ModIsShort1(tAdrMode AdrMode)
{
  switch (AdrMode)
  {
    case ModShort1:
    case ModShortIndir1_24:
    case ModShortIndir1_16:
      return 1;
    case ModShort2:
    case ModShortIndir2_24:
    case ModShortIndir2_16:
      return 0;
    default:
      return 0xff;
  }
}

static Boolean DecodeBitAdr(const tStrComp *pArg, LongWord *pResult)
{
  char *pSplit;
  Boolean OK;

  pSplit = RQuotPos(pArg->str.p_str, '.');

  if (pSplit)
  {
    tEncodedAddress Addr;
    tStrComp AddrArg, BitArg;

    StrCompSplitRef(&AddrArg, &BitArg, pArg, pSplit);
    *pResult = EvalStrIntExpression(&BitArg, UInt3, &OK) << 24;
    if (OK)
    {
      DecodeAdr(&AddrArg, MModReg8 | MModSFR | MModShort1 | MModShort2 | MModMem | MModAbsAll, &Addr);
      switch (Addr.AdrMode)
      {
        case ModReg8:
          if ((Addr.AdrVal != AccReg8()) && (Addr.AdrVal != AccReg8() - 1))
          {
            WrStrErrorPos(ErrNum_InvReg, &AddrArg);
            OK = FALSE;
          }
          else
          {
            *pResult |= (((LongWord)eBitTypeAX) << 28);
            if (Addr.AdrVal & 1)
              *pResult |= Bit27;
          }
          break;
        case ModSFR:
          if (Addr.AdrVals[0] == (PSWLAddr & 0xff))
            *pResult |= ((LongWord)eBitTypePSW) << 28;
          else if (Addr.AdrVals[0] == (PSWHAddr & 0xff))
            *pResult |= (((LongWord)eBitTypePSW) << 28) | Bit27;
          else
            *pResult |= Addr.AdrVals[0]
                     | (((LongWord)eBitTypeSAddr2_SFR) << 28)
                     | Bit27;
          break;
        case ModShort1:
          *pResult |= Addr.AdrVals[0]
                   | (((LongWord)eBitTypeSAddr1) << 28);
          break;
        case ModShort2:
          *pResult |= Addr.AdrVals[0]
                   | (((LongWord)eBitTypeSAddr2_SFR) << 28);
          break;
        case ModMem:
          if ((Addr.AdrVal != 0x16) || ((Addr.AdrVals[0] & 0x0e) != 4))
          {
            OK = False;
            WrError(ErrNum_InvAddrMode);
          }
          else
          {
            *pResult |= (((LongWord)eBitTypeMem) << 28);
            if (Addr.AdrVals[0] & 1)
              *pResult |= Bit27;
          }
          break;
        case ModAbs16:
        case ModAbs24:
          *pResult |= ((LongWord)eBitTypeAbs) << 28;
          *pResult |= ((LongWord)Addr.AdrVals[0]) << 0;
          *pResult |= ((LongWord)Addr.AdrVals[1]) << 8;
          if (Addr.AdrMode == ModAbs24)
          {
            *pResult |= Bit27;
            *pResult |= ((LongWord)Addr.AdrVals[2]) << 16;
          }
          break;
        default:
          OK = FALSE;
      }
    }
  }
  else
    *pResult = EvalStrIntExpression(pArg, UInt32, &OK);

  return OK;
}

static void AppendRel8(const tStrComp *pArg)
{
  Boolean OK;
  LongInt Dist;
  tSymbolFlags Flags;

  Dist = EvalStrIntExpressionOffsWithFlags(pArg, !!(*pArg->str.p_str == '$'), UInt20, &OK, &Flags) - (EProgCounter() + CodeLen + 1);
  if (!OK) CodeLen = 0;
  else if (!mSymbolQuestionable(Flags) && ((Dist < -0x80) || (Dist > 0x7f)))
  {
    WrError(ErrNum_JmpDistTooBig);
    CodeLen = 0;
  }
  else
    BAsmCode[CodeLen++] = Dist & 0xff;
}

/*-------------------------------------------------------------------------*/
/* Instruction Decoders */

static void PutCode(Word Code)
{
  if (Hi(Code))
    BAsmCode[CodeLen++] = Hi(Code);
  BAsmCode[CodeLen++] = Lo(Code);
}

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

static void DecodeBitOpCore2(LongWord BitAddr, Word Code)
{
  switch ((BitAddr >> 28) & 15)
  {
    case eBitTypePSW:
    case eBitTypeAX:
      BAsmCode[CodeLen++] = (BitAddr >> 28) & 15;
      BAsmCode[CodeLen++] = Code | ((BitAddr >> 24) & 15);
      break;
    case eBitTypeSAddr1:
      BAsmCode[CodeLen++] = 0x3c;
      /* fall-through */
    case eBitTypeSAddr2_SFR:
      BAsmCode[CodeLen++] = 0x08;
      BAsmCode[CodeLen++] = Code | ((BitAddr >> 24) & 15);
      BAsmCode[CodeLen++] = Lo(BitAddr);
      break;
    case eBitTypeMem:
      BAsmCode[CodeLen++] = 0x3d;
      BAsmCode[CodeLen++] = Code | ((BitAddr >> 24) & 15);
      break;
    case eBitTypeAbs:
      BAsmCode[CodeLen++] = 0x09;
      BAsmCode[CodeLen++] = 0xd0;
      BAsmCode[CodeLen++] = Code | ((BitAddr >> 24) & 15);
      if (BAsmCode[CodeLen - 1] & 0x08)
        BAsmCode[CodeLen++] = (BitAddr >> 16) & 255;
      BAsmCode[CodeLen++] = (BitAddr >> 0) & 255;
      BAsmCode[CodeLen++] = (BitAddr >> 8) & 255;
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeBitOpCore(const tStrComp *pBitArg, Word Code)
{
  LongWord BitAddr;

  if (!DecodeBitAdr(pBitArg, &BitAddr))
    return;
  DecodeBitOpCore2(BitAddr, Code);
}

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

  if (!ChkArgCnt(2, 2))
    return;
  if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
    DecodeBitOpCore(&ArgStr[2], 0x00);
  else if (!as_strcasecmp(ArgStr[2].str.p_str, "CY"))
    DecodeBitOpCore(&ArgStr[1], 0x10);
  else
  {
    WrError(ErrNum_InvAddrMode);
    return;
  }
}

static void DecodeAND1_OR1(Word Code)
{
  if (!ChkArgCnt(2, 2))
    return;
  if (as_strcasecmp(ArgStr[1].str.p_str, "CY"))
  {
    WrError(ErrNum_InvAddrMode);
    return;
  }
  if (*ArgStr[2].str.p_str == '/')
  {
    tStrComp BitArg;

    StrCompRefRight(&BitArg, &ArgStr[2], 1);
    DecodeBitOpCore(&BitArg, Code | 0x10);
  }
  else
    DecodeBitOpCore(&ArgStr[2], Code);
}

static void DecodeXOR1(Word Code)
{
  if (!ChkArgCnt(2, 2))
    return;
  if (as_strcasecmp(ArgStr[1].str.p_str, "CY"))
  {
    WrError(ErrNum_InvAddrMode);
    return;
  }
  DecodeBitOpCore(&ArgStr[2], Code);
}

static void DecodeNOT1(Word Code)
{
  if (!ChkArgCnt(1, 1))
    return;
  if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
    BAsmCode[CodeLen++] = 0x42;
  else
    DecodeBitOpCore(&ArgStr[1], Code);
}

static void DecodeSET1_CLR1(Word Code)
{
  if (!ChkArgCnt(1, 1))
    return;
  if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
    BAsmCode[CodeLen++] = 0x41 - ((Code >> 4) & 1);
  else
  {
    LongWord BitAddr;

    if (!DecodeBitAdr(&ArgStr[1], &BitAddr))
      return;
    switch ((BitAddr >> 28) & 15)
    {
      case eBitTypeSAddr1:
        BAsmCode[CodeLen++] = 0x3c;
        /* fall-through */
      case eBitTypeSAddr2_SFR:
        if (!(BitAddr & Bit27))
        {
          BAsmCode[CodeLen++] = (0x130 - Code) | ((BitAddr >> 24) & 7);
          BAsmCode[CodeLen++] = Lo(BitAddr);
          break;
        }
        /* else fall-through */ /* SFR is regularly coded for SET1/CLR1 */
      default:
        DecodeBitOpCore2(BitAddr, Code);
    }
  }
}

static void DecodeMOV(Word ForceOpSize)
{
  tEncodedAddress Dest, Src;
  tAdrModeMask AdrModeMask;

  if (ForceOpSize)
    SetOpSize(ForceOpSize);

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

  if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
  {
    DecodeBitOpCore(&ArgStr[2], 0x00);
    return;
  }
  else if (!as_strcasecmp(ArgStr[2].str.p_str, "CY"))
  {
    DecodeBitOpCore(&ArgStr[1], 0x10);
    return;
  }

  AdrModeMask = MModShort1 | MModShort2 | MModAbsAll | MModShortIndir1_24 | MModShortIndir2_24 | MModMem;
  if (OpSize != 2)
    AdrModeMask |= MModSFR | MModShortIndir1_16 | MModShortIndir2_16;
  if ((OpSize == -1) || (OpSize == 0))
    AdrModeMask |= MModReg8 | MModReg8_U16 | MModSTBC | MModWDM;
  if ((OpSize == -1) || (OpSize == 1))
    AdrModeMask |= MModReg16;
  if ((OpSize == -1) || (OpSize == 2))
    AdrModeMask |= MModReg24 | MModSP;
  DecodeAdr(&ArgStr[1], AdrModeMask, &Dest);
  switch (Dest.AdrMode)
  {
    case ModReg8:
      AdrModeMask = MModImm | MModReg8 | MModShort1 | MModShort2 | MModSFR | MModAbsAll;
      if (Dest.AdrVal == AccReg8())
        AdrModeMask |= MModReg8_U16 | MModShortIndir_All | MModMem;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal >= 8)
          {
            BAsmCode[CodeLen++] = 0x3c;
            Src.AdrVal -= 8;
          }
          if (Dest.AdrVal == AccReg8())
            BAsmCode[CodeLen++] = 0xd0 | Src.AdrVal;
          else
          {
            BAsmCode[CodeLen++] = 0x24;
            BAsmCode[CodeLen++] = (Dest.AdrVal << 4) | Src.AdrVal;
          }
          break;
        case ModReg8_U16:
          BAsmCode[CodeLen++] = 0x05;
          BAsmCode[CodeLen++] = 0xc1 | (Src.AdrVal << 1);
          break;
        case ModImm:
          if (Dest.AdrVal >= 8)
          {
            BAsmCode[CodeLen++] = 0x3c;
            Dest.AdrVal -= 8;
          }
          BAsmCode[CodeLen++] = 0xb8 | Dest.AdrVal;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModShort2:
          if (Dest.AdrVal == AccReg8())
          {
            BAsmCode[CodeLen++] = 0x20;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          else
            goto CommonReg8ModShort;
        case ModSFR:
          if (Dest.AdrVal == AccReg8())
          {
            BAsmCode[CodeLen++] = 0x10;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          else
            goto CommonReg8ModShort;
        CommonReg8ModShort:
        case ModShort1:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x00 | ModShortVal(Src.AdrMode) | (Dest.AdrVal << 4);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModAbs16:
        case ModAbs24:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x00 | (ModIs24(Src.AdrMode) << 1) | (Dest.AdrVal << 4);
          AppendAdrVals(&Src);
          break;
        case ModShortIndir1_16:
        case ModShortIndir2_16:
        case ModShortIndir1_24:
        case ModShortIndir2_24:
          if (ModIsShort1(Src.AdrMode))
            BAsmCode[CodeLen++] = 0x3c;
          if (ModIs24(Src.AdrMode))
          {
            BAsmCode[CodeLen++] = 0x07;
            BAsmCode[CodeLen++] = 0x30;
          }
          else
            BAsmCode[CodeLen++] = 0x18;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModMem:
          if ((Src.AdrVal == 0x16) && (Src.AdrVals[0] < 6))
            BAsmCode[CodeLen++] = 0x58 + Src.AdrVals[0];
          else
          {
            BAsmCode[CodeLen++] = Src.AdrVal;
            AppendAdrValsMem(&Src, 0x00);
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModReg8_U16:
      DecodeAdr(&ArgStr[2], MModImm | MModReg8, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal == AccReg8())
          {
            BAsmCode[CodeLen++] = 0x05;
            BAsmCode[CodeLen++] = 0xc9 | (Dest.AdrVal << 1);
          }
          break;
        case ModImm:
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0x61 | (Dest.AdrVal << 1);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModReg16:
      AdrModeMask = MModImm | MModReg16 | MModShort1 | MModShort2 | MModSFR | MModAbsAll;
      if (Dest.AdrVal == AccReg16())
        AdrModeMask |= MModShortIndir_All | MModMem;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x60 | Dest.AdrVal;
          AppendAdrVals(&Src);
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x24;
          BAsmCode[CodeLen++] = 0x08 | (Src.AdrVal << 5) | Dest.AdrVal;
          AppendAdrVals(&Src);
          break;
        case ModShort2:
          if (Dest.AdrVal == AccReg16())
          {
            BAsmCode[CodeLen++] = 0x1c;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          else
            goto CommonReg16ModShort;
        case ModSFR:
          if (Dest.AdrVal == AccReg16())
          {
            BAsmCode[CodeLen++] = 0x11;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
            goto CommonReg16ModShort;
        CommonReg16ModShort:
        case ModShort1:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x08 | ModShortVal(Src.AdrMode) | (Dest.AdrVal << 5);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModAbs16:
        case ModAbs24:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x08 | (ModIs24(Src.AdrMode) << 1) | (Dest.AdrVal << 5);
          AppendAdrVals(&Src);
          break;
        case ModShortIndir1_16:
          BAsmCode[CodeLen++] = 0x3c;
          /* fall-through */
        case ModShortIndir2_16:
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0x21;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModShortIndir1_24:
          BAsmCode[CodeLen++] = 0x3c;
          /* fall-through */
        case ModShortIndir2_24:
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0x31;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModMem:
          BAsmCode[CodeLen++] = Src.AdrVal;
          AppendAdrValsMem(&Src, 0x01);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModReg24:
      AdrModeMask = MModImm | MModReg24 | MModAbs24 | MModShort1 | MModShort2;
      if (Dest.AdrVal == WHLReg)
        AdrModeMask |= MModShortIndir1_24 | MModShortIndir2_24 | MModMem | MModSP;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x9b | (Dest.AdrVal << 5);
          AppendAdrVals(&Src);
          break;
        case ModReg24:
          BAsmCode[CodeLen++] = 0x24;
          BAsmCode[CodeLen++] = 0x99 | (Dest.AdrVal << 5) | (Src.AdrVal << 1);
          AppendAdrVals(&Src);
          break;
        case ModAbs24:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x9a | (Dest.AdrVal << 5);
          AppendAdrVals(&Src);
          break;
        case ModShort1:
        case ModShort2:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x98 | ModShortVal(Src.AdrMode) | (Dest.AdrVal << 5);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModShortIndir1_24:
          BAsmCode[CodeLen++] = 0x3c;
          /* fall-through */
        case ModShortIndir2_24:
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0x32;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModMem:
          if ((Src.AdrVal == 0x16) && ((Src.AdrVals[0] == 1) || (Src.AdrVals[0] == 3))) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = Src.AdrVal;
            AppendAdrValsMem(&Src, 0x02);
          }
          break;
        case ModSP:
          BAsmCode[CodeLen++] = 0x05;
          BAsmCode[CodeLen++] = 0xfa;
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModSP:
      DecodeAdr(&ArgStr[2], MModImm | MModReg24, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x09;
          BAsmCode[CodeLen++] = 0x20;
          AppendAdrVals(&Src);
          break;
        case ModReg24:
          if (Src.AdrVal != WHLReg) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = 0x05;
            BAsmCode[CodeLen++] = 0xfb;
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModSTBC:
    case ModWDM:
      if (DecodeAdr(&ArgStr[2], MModImm, &Src))
      {
        BAsmCode[CodeLen++] = 0x09;
        BAsmCode[CodeLen++] = (Dest.AdrMode == ModSTBC) ? 0xc0: 0xc2;
        BAsmCode[CodeLen++] = ~Src.AdrVals[0];
        BAsmCode[CodeLen++] = Src.AdrVals[0];
      }
      break;

    case ModShort1:
      AssumeByte = True;
      AdrModeMask = 0;
      if (OpSize != 2) AdrModeMask |= MModImm | MModShort2 | MModShort1;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      if ((OpSize == -1) || (OpSize == 2)) AdrModeMask |= MModReg24;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x3c;
          BAsmCode[CodeLen++] = OpSize ? 0x0c : 0x3a;
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x05 | (Src.AdrVal << 4);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x0d | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg24:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x9d | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort1:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          BAsmCode[CodeLen++] = 0x30 | (OpSize << 7);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort2:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          BAsmCode[CodeLen++] = 0x20 | (OpSize << 7);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShort2:
      AssumeByte = True;
      AdrModeMask = 0;
      if (OpSize != 2) AdrModeMask |= MModImm | MModShort2 | MModShort1;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      if ((OpSize == -1) || (OpSize == 2)) AdrModeMask |= MModReg24;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = OpSize ? 0x0c : 0x3a;
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          if (Src.AdrVal == AccReg8())
            BAsmCode[CodeLen++] = 0x22;
          else
          {
            BAsmCode[CodeLen++] = 0x38;
            BAsmCode[CodeLen++] = 0x04 | (Src.AdrVal << 4);
          }
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          if (Src.AdrVal == AccReg16())
            BAsmCode[CodeLen++] = 0x1a;
          else
          {
            BAsmCode[CodeLen++] = 0x38;
            BAsmCode[CodeLen++] = 0x0c | (Src.AdrVal << 5);
          }
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg24:
          BAsmCode[CodeLen++] = 0x38;
          BAsmCode[CodeLen++] = 0x9c | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort2:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          BAsmCode[CodeLen++] = OpSize << 7;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort1:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          BAsmCode[CodeLen++] = 0x10 | (OpSize << 7);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModSFR:
      AssumeByte = True;
      AdrModeMask = 0;
      if (OpSize != 2) AdrModeMask |= MModImm;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = OpSize ? 0x0b : 0x2b;
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          if (Src.AdrVal == AccReg8())
            BAsmCode[CodeLen++] = 0x12;
          else
          {
            BAsmCode[CodeLen++] = 0x38;
            BAsmCode[CodeLen++] = 0x06 | (Src.AdrVal << 4);
          }
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          if (Src.AdrVal == AccReg8())
            BAsmCode[CodeLen++] = 0x13;
          else
          {
            BAsmCode[CodeLen++] = 0x38;
            BAsmCode[CodeLen++] = 0x0e | (Src.AdrVal << 5);
          }
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModAbs16:
    case ModAbs24:
      AssumeByte = True;
      AdrModeMask = 0;
      if (OpSize != 2) AdrModeMask |= MModImm;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      if ((OpSize == -1) || (OpSize == 2)) AdrModeMask |= MModReg24;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x09;
          BAsmCode[CodeLen++] = 0x40 | (ModIs24(Dest.AdrMode) << 4) | OpSize;
          AppendAdrVals(&Dest);
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x01 | (ModIs24(Dest.AdrMode) << 1) | (Src.AdrVal << 4);
          AppendAdrVals(&Dest);
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x09 | (ModIs24(Dest.AdrMode) << 1) | (Src.AdrVal << 5);
          AppendAdrVals(&Dest);
          break;
        case ModReg24:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x9b | (Src.AdrVal << 5);
          if (Dest.AdrMode == ModAbs16)
            BAsmCode[CodeLen++] = 0x00;
          AppendAdrVals(&Dest);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShortIndir2_16:
    case ModShortIndir1_16:
      AssumeByte = True;
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
          {
            if (ModIsShort1(Dest.AdrMode))
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0x19;
            BAsmCode[CodeLen++] = Dest.AdrVals[0];
          }
          break;
        case ModReg16:
          if (Src.AdrVal != AccReg16()) WrError(ErrNum_InvAddrMode);
          else
          {
            if (ModIsShort1(Dest.AdrMode))
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0x07;
            BAsmCode[CodeLen++] = 0xa1;
            BAsmCode[CodeLen++] = Dest.AdrVals[0];
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShortIndir2_24:
    case ModShortIndir1_24:
      AssumeByte = True;
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      if ((OpSize == -1) || (OpSize == 2)) AdrModeMask |= MModReg24;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
            goto CommonRegIndir;
          break;
        case ModReg16:
          if (Src.AdrVal != AccReg16()) WrError(ErrNum_InvAddrMode);
          else
            goto CommonRegIndir;
          break;
        case ModReg24:
          if (Src.AdrVal != WHLReg) WrError(ErrNum_InvAddrMode);
          else
            goto CommonRegIndir;
          break;
        CommonRegIndir:
          if (ModIsShort1(Dest.AdrMode))
            BAsmCode[CodeLen++] = 0x3c;
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0xb0 + OpSize;
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModMem:
      AssumeByte = True;
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      if ((OpSize == -1) || (OpSize == 2)) AdrModeMask |= MModReg24;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else if ((Dest.AdrVal == 0x16) && (Dest.AdrVals[0] < 6))
            BAsmCode[CodeLen++] = 0x50 + Dest.AdrVals[0];
          else
            goto CommonRegMem;
          break;
        case ModReg16:
          if (Src.AdrVal != AccReg16()) WrError(ErrNum_InvAddrMode);
          else
            goto CommonRegMem;
          break;
        case ModReg24:
          if (Src.AdrVal != WHLReg) WrError(ErrNum_InvAddrMode);
          else
            goto CommonRegMem;
          break;
        CommonRegMem:
          BAsmCode[CodeLen++] = Dest.AdrVal;
          AppendAdrValsMem(&Dest, 0x80 + OpSize);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;
    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeXCH(Word ForceOpSize)
{
  tEncodedAddress Dest, Src;
  tAdrModeMask AdrModeMask;

  if (ForceOpSize)
    SetOpSize(ForceOpSize);

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

  AdrModeMask = MModShort1 | MModShort2 | MModSFR | MModAbsAll | MModShortIndir_All | MModMem;
  if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
  if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
  DecodeAdr(&ArgStr[1], AdrModeMask, &Dest);
  switch (Dest.AdrMode)
  {
    case ModReg8:
      AdrModeMask = MModReg8 | MModShort2 | MModShort1 | MModSFR | MModAbsAll;
      if (Dest.AdrVal == AccReg8())
        AdrModeMask |= MModShortIndir_All | MModMem;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Dest.AdrVal == AccReg8())
          {
            if (Src.AdrVal >= 8)
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0xd8 | (Src.AdrVal & 7);
          }
          else if (Src.AdrVal == AccReg8())
          {
            if (Dest.AdrVal >= 8)
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0xd8 | (Dest.AdrVal & 7);
          }
          else
          {
            if (Src.AdrVal >= 8)
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0x25;
            BAsmCode[CodeLen++] = (Dest.AdrVal << 4) | (Src.AdrVal & 7);
          }
          break;
        case ModShort2:
          if (Dest.AdrVal == AccReg8())
          {
            BAsmCode[CodeLen++] = 0x21;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          /* fall-through */
        case ModShort1:
        case ModSFR:
          BAsmCode[CodeLen++] = 0x39;
          BAsmCode[CodeLen++] = 0x00 | ModShortVal(Src.AdrMode) | (Dest.AdrVal << 4);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModAbs16:
        case ModAbs24:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x04 | (ModIs24(Src.AdrMode) << 1) | (Dest.AdrVal << 4);
          AppendAdrVals(&Src);
          break;
        case ModShortIndir1_16:
        case ModShortIndir2_16:
        case ModShortIndir1_24:
        case ModShortIndir2_24:
          if (ModIsShort1(Src.AdrMode))
            BAsmCode[CodeLen++] = 0x3c;
          if (ModIs24(Src.AdrMode))
          {
            BAsmCode[CodeLen++] = 0x07;
            BAsmCode[CodeLen++] = 0x34;
          }
          else
            BAsmCode[CodeLen++] = 0x23;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModMem:
          BAsmCode[CodeLen++] = Src.AdrVal;
          AppendAdrValsMem(&Src, 0x04);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModReg16:
      AdrModeMask = MModReg16 | MModShort1 | MModShort2 | MModSFR;
      if (Dest.AdrVal == AccReg16())
        AdrModeMask |= MModShortIndir_All | MModAbsAll | MModMem;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg16:
          BAsmCode[CodeLen++] = 0x25;
          BAsmCode[CodeLen++] = 0x08 | (Src.AdrVal << 5) | Dest.AdrVal;
          break;
        case ModShort2:
          if (Dest.AdrVal == AccReg16())
          {
            BAsmCode[CodeLen++] = 0x1b;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          /* fall-through */
        case ModShort1:
        case ModSFR:
          BAsmCode[CodeLen++] = 0x39;
          BAsmCode[CodeLen++] = 0x08 | ModShortVal(Src.AdrMode) | (Dest.AdrVal << 5);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModShortIndir1_16:
        case ModShortIndir2_16:
        case ModShortIndir1_24:
        case ModShortIndir2_24:
          if (ModIsShort1(Src.AdrMode))
            BAsmCode[CodeLen++] = 0x3c;
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0x25 | (ModIs24(Src.AdrMode) << 4);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModAbs16:
        case ModAbs24:
          BAsmCode[CodeLen++] = 0x0a;
          BAsmCode[CodeLen++] = 0x45 | (ModIs24(Src.AdrMode) << 4);
          AppendAdrVals(&Src);
          break;
        case ModMem:
          BAsmCode[CodeLen++] = Src.AdrVal;
          AppendAdrValsMem(&Src, 0x05);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShort2:
      AssumeByte = True;
      AdrModeMask = MModShort2 | MModShort1;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal == AccReg8())
            BAsmCode[CodeLen++] = 0x21;
          else
          {
            BAsmCode[CodeLen++] = 0x39;
            BAsmCode[CodeLen++] = 0x00 | (Src.AdrVal << 4);
          }
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          if (Src.AdrVal == AccReg16())
            BAsmCode[CodeLen++] = 0x1b;
          else
          {
            BAsmCode[CodeLen++] = 0x39;
            BAsmCode[CodeLen++] = 0x08 | (Src.AdrVal << 5);
          }
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort2:
        case ModShort1:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          BAsmCode[CodeLen++] = (OpSize << 7) | ((Src.AdrMode == ModShort1) ? 0x14 : 0x04);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShort1:
      AssumeByte = True;
      AdrModeMask = MModShort2 | MModShort1;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          BAsmCode[CodeLen++] = 0x39;
          BAsmCode[CodeLen++] = 0x01 | (Src.AdrVal << 4);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x39;
          BAsmCode[CodeLen++] = 0x09 | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort2:
        case ModShort1:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          BAsmCode[CodeLen++] = (OpSize << 7) | ((Src.AdrMode == ModShort1) ? 0x34 : 0x24);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModSFR:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          BAsmCode[CodeLen++] = 0x39;
          BAsmCode[CodeLen++] = 0x02 | (Src.AdrVal << 4);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x39;
          BAsmCode[CodeLen++] = 0x0a | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModAbs16:
    case ModAbs24:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          BAsmCode[CodeLen++] = 0x3e;
          BAsmCode[CodeLen++] = 0x04 | (ModIs24(Dest.AdrMode) << 1) | (Src.AdrVal << 4);
          AppendAdrVals(&Dest);
          break;
        case ModReg16:
          if (Src.AdrVal != AccReg16()) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = 0x0a;
            BAsmCode[CodeLen++] = 0x45 | (ModIs24(Dest.AdrMode) << 4);
            AppendAdrVals(&Dest);
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShortIndir2_16:
    case ModShortIndir1_16:
    case ModShortIndir2_24:
    case ModShortIndir1_24:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
          {
            if (ModIsShort1(Dest.AdrMode))
              BAsmCode[CodeLen++] = 0x3c;
            if (ModIs24(Dest.AdrMode))
            {
              BAsmCode[CodeLen++] = 0x07;
              BAsmCode[CodeLen++] = 0x34;
            }
            else
              BAsmCode[CodeLen++] = 0x23;
            BAsmCode[CodeLen++] = Dest.AdrVals[0];
          }
          break;
        case ModReg16:
          if (Src.AdrVal != AccReg16()) WrError(ErrNum_InvAddrMode);
          else
          {
            if (ModIsShort1(Dest.AdrMode))
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0x07;
            BAsmCode[CodeLen++] = ModIs24(Dest.AdrMode) ? 0x35 : 0x25;
            BAsmCode[CodeLen++] = Dest.AdrVals[0];
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModMem:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = Dest.AdrVal;
            AppendAdrValsMem(&Dest, 0x04);
          }
          break;
        case ModReg16:
          if (Src.AdrVal != AccReg16()) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = Dest.AdrVal;
            AppendAdrValsMem(&Dest, 0x05);
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeALU(Word Code)
{
  tEncodedAddress Dest, Src;
  tAdrModeMask AdrModeMask;
  Byte Code16, Code16_AX, Code24;

  if (Code & 15)
    SetOpSize(Code & 15);
  Code16 = (Code >> 8) & 15;
  Code24 = (Code >> 12) & 15;
  Code16_AX = (Code16 == 0 ? 0x0d : (Code16 == 2 ? 0x0e : 0x0f));
  Code = (Code >> 4) & 15;

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

  if ((OpSize == -1) && (!as_strcasecmp(ArgStr[1].str.p_str, "CY")))
  {
    switch (Code)
    {
      case 4: /* AND CY,... -> AND1 CY,...*/
        DecodeAND1_OR1(0x20);
        return;
      case 6: /* OR CY,...  -> OR1 CY,...*/
        DecodeAND1_OR1(0x40);
        return;
      case 5: /* XOR CY,... -> XOR1 CY,...*/
        DecodeXOR1(0x60);
        return;
    }
  }

  AdrModeMask = 0;
  if ((OpSize == -1) || (OpSize == 0) || (OpSize == 1))
    AdrModeMask = MModShort1 | MModShort2 | MModSFR;
  if ((OpSize == -1) || (OpSize == 0))
    AdrModeMask |= MModReg8 | MModShortIndir_All | MModAbsAll | MModMem;
  if ((Code16 != 15) && ((OpSize == -1) || (OpSize == 1)))
    AdrModeMask |= MModReg16;
  if ((Code24 != 15) && ((OpSize == -1) || (OpSize == 2)))
    AdrModeMask |= MModReg24 | MModSP;
  DecodeAdr(&ArgStr[1], AdrModeMask, &Dest);
  switch (Dest.AdrMode)
  {
    case ModReg8:
      AdrModeMask = MModImm | MModReg8 | MModShort1 | MModShort2 | MModSFR | MModAbsAll;
      if (Dest.AdrVal == AccReg8())
        AdrModeMask |= MModShortIndir_All | MModMem;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          if (Dest.AdrVal == AccReg8())
            BAsmCode[CodeLen++] = 0xa8 | Code;
          else
          {
            BAsmCode[CodeLen++] = 0x78 | Code;
            BAsmCode[CodeLen++] = 0x03 | (Dest.AdrVal << 4);
          }
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModReg8:
          if (Src.AdrVal >= 8)
            BAsmCode[CodeLen++] = 0x3c;
          BAsmCode[CodeLen++] = 0x88 | Code;
          BAsmCode[CodeLen++] = (Dest.AdrVal << 4) | (Src.AdrVal & 7);
          break;
        case ModShort2:
          if (Dest.AdrVal == AccReg8())
          {
            BAsmCode[CodeLen++] = 0x98 | Code;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          /* else fall-through */
        case ModShort1:
        case ModSFR:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = (Dest.AdrVal << 4) | ModShortVal(Src.AdrMode);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModShortIndir1_16:
        case ModShortIndir2_16:
        case ModShortIndir1_24:
        case ModShortIndir2_24:
          if (ModIsShort1(Src.AdrMode))
            BAsmCode[CodeLen++] = 0x3c;
          BAsmCode[CodeLen++] = 0x07;
          BAsmCode[CodeLen++] = 0x28 | (ModIs24(Src.AdrMode) << 4) | Code;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModAbs16:
        case ModAbs24:
          BAsmCode[CodeLen++] = 0x0a;
          BAsmCode[CodeLen++] = 0x48 | (ModIs24(Src.AdrMode) << 4) | Code;
          AppendAdrVals(&Src);
          break;
        case ModMem:
          BAsmCode[CodeLen++] = Src.AdrVal;
          AppendAdrValsMem(&Src, 0x08 | Code);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModReg16:
      AdrModeMask = MModImm | MModReg16 | MModShort1 | MModShort2 | MModSFR;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          if (Dest.AdrVal == AccReg16())
            BAsmCode[CodeLen++] = 0x20 | Code16_AX;
          else
          {
            BAsmCode[CodeLen++] = 0x78 | Code16;
            BAsmCode[CodeLen++] = 0x0d | (Dest.AdrVal << 5);
          }
          AppendAdrVals(&Src);
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x88 | Code16;
          BAsmCode[CodeLen++] = (Src.AdrVal << 5) | 0x08 | Dest.AdrVal;
          break;
        case ModShort2:
          if (Dest.AdrVal == AccReg16())
          {
            BAsmCode[CodeLen++] = 0x10 | Code16_AX;
            BAsmCode[CodeLen++] = Src.AdrVals[0];
            break;
          }
          /* else fall-through */
        case ModShort1:
        case ModSFR:
          BAsmCode[CodeLen++] = 0x78 | Code16;
          BAsmCode[CodeLen++] = 0x08 | ModShortVal(Src.AdrMode) | (Dest.AdrVal << 5);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModReg24:
      AdrModeMask = MModImm | MModReg24;
      if (Dest.AdrVal == WHLReg)
        AdrModeMask |= MModShort1 | MModShort2;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg24:
          BAsmCode[CodeLen++] = 0x88 | Code24;
          BAsmCode[CodeLen++] = 0x99 | (Dest.AdrVal << 5) | (Src.AdrVal << 1);
          break;
        case ModImm:
          BAsmCode[CodeLen++] = 0x78 | Code24;
          BAsmCode[CodeLen++] = 0x9b | (Dest.AdrVal << 5);
          AppendAdrVals(&Src);
          break;
        case ModShort1:
        case ModShort2:
          BAsmCode[CodeLen++] = 0x78 | Code24;
          BAsmCode[CodeLen++] = 0xf8 | ModShortVal(Src.AdrMode);
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModSP:
      OpSize = 1; /* !!! ADDWG/SUBWG, i.e. 24-bit dest & 16-bit src */
      DecodeAdr(&ArgStr[2], MModImm, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x09;
          BAsmCode[CodeLen++] = 0x28 | Code24;
          AppendAdrVals(&Src);
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShort2:
      AssumeByte = True;
      AdrModeMask = MModImm | MModShort1 | MModShort2;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = OpSize ? Code16_AX : (0x68 | Code);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = 0x04 | (Src.AdrVal << 4);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = 0x0c | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort1:
        case ModShort2:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          if (OpSize)
            BAsmCode[CodeLen++] = 0x80 | (ModShortVal(Src.AdrMode) << 4) | Code16_AX;
          else
            BAsmCode[CodeLen++] = 0x08 | (ModShortVal(Src.AdrMode) << 4) | Code;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShort1:
      AssumeByte = True;
      AdrModeMask = MModImm | MModShort1 | MModShort2;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x3c;
          BAsmCode[CodeLen++] = OpSize ? Code16_AX : (0x68 | Code);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = 0x05 | (Src.AdrVal << 4);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = 0x0d | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModShort1:
        case ModShort2:
          ExecAssumeByte();
          BAsmCode[CodeLen++] = 0x2a;
          if (OpSize)
            BAsmCode[CodeLen++] = 0xa0 | (ModShortVal(Src.AdrMode) << 4) | Code16_AX;
          else
            BAsmCode[CodeLen++] = 0x28 | (ModShortVal(Src.AdrMode) << 4) | Code;
          BAsmCode[CodeLen++] = Src.AdrVals[0];
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModSFR:
      AssumeByte = True;
      AdrModeMask = MModImm;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModImm:
          BAsmCode[CodeLen++] = 0x01;
          BAsmCode[CodeLen++] = OpSize ? Code16_AX : (0x68 | Code);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          AppendAdrVals(&Src);
          break;
        case ModReg8:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = 0x06 | (Src.AdrVal << 4);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModReg16:
          BAsmCode[CodeLen++] = 0x78 | Code;
          BAsmCode[CodeLen++] = 0x0e | (Src.AdrVal << 5);
          BAsmCode[CodeLen++] = Dest.AdrVals[0];
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModShortIndir2_16:
    case ModShortIndir1_16:
    case ModShortIndir2_24:
    case ModShortIndir1_24:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
          {
            if (ModIsShort1(Dest.AdrMode))
              BAsmCode[CodeLen++] = 0x3c;
            BAsmCode[CodeLen++] = 0x07;
            BAsmCode[CodeLen++] = 0xa8 | (ModIs24(Dest.AdrMode) << 4) | Code;
            BAsmCode[CodeLen++] = Dest.AdrVals[0];
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModAbs16:
    case ModAbs24:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = 0x0a;
            BAsmCode[CodeLen++] = 0xc8 | (ModIs24(Dest.AdrMode) << 4) | Code;
            AppendAdrVals(&Dest);
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;

    case ModMem:
      AdrModeMask = 0;
      if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
      DecodeAdr(&ArgStr[2], AdrModeMask, &Src);
      switch (Src.AdrMode)
      {
        case ModReg8:
          if (Src.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = Dest.AdrVal;
            AppendAdrValsMem(&Dest, 0x88 | Code);
          }
          break;
        case ModNone:
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
      break;
    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeADDWG_SUBWG(Word Code)
{
  tEncodedAddress Addr;

  if (ChkArgCnt(2, 2))
  {
    OpSize = 2;
    if (DecodeAdr(&ArgStr[1], MModSP, &Addr))
    {
      OpSize = 1; /* !!! ADDWG/SUBWG, i.e. 24-bit dest & 16-bit src */
      if (DecodeAdr(&ArgStr[2], MModImm, &Addr))
      {
        BAsmCode[CodeLen++] = 0x09;
        BAsmCode[CodeLen++] = 0x28 | Code;
        AppendAdrVals(&Addr);
      }
    }
  }
}

static void DecodeMULU(Word Code)
{
  tEncodedAddress Src;
  tAdrModeMask AdrModeMask;

  if (Code & 15)
    SetOpSize(Code & 15);

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

  AdrModeMask = 0;
  if ((OpSize == -1) || (OpSize == 0))
    AdrModeMask |= MModReg8;
  if ((OpSize == -1) || (OpSize == 1))
    AdrModeMask |= MModReg16;
  DecodeAdr(&ArgStr[1], AdrModeMask, &Src);
  switch (Src.AdrMode)
  {
    case ModReg8:
      if (Src.AdrVal >= 8)
        BAsmCode[CodeLen++] = 0x3c;
      BAsmCode[CodeLen++] = 0x05;
      BAsmCode[CodeLen++] = 0x08 | (Src.AdrVal & 7);
      break;
    case ModReg16:
      BAsmCode[CodeLen++] = 0x05;
      BAsmCode[CodeLen++] = 0x28 | Src.AdrVal;
      break;
    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeDIVUW(Word Code)
{
  tEncodedAddress Src;
  UNUSED(Code);

  if (ChkArgCnt(1, 1)
   && DecodeAdr(&ArgStr[1], MModReg8, &Src))
  {
    if (Src.AdrVal >= 8)
      BAsmCode[CodeLen++] = 0x3c;
    BAsmCode[CodeLen++] = 0x05;
    BAsmCode[CodeLen++] = 0x18 | (Src.AdrVal & 7);
  }
}

static void DecodeMULW_DIVUX(Word Code)
{
  tEncodedAddress Src;

  if (ChkArgCnt(1, 1)
   && DecodeAdr(&ArgStr[1], MModReg16, &Src))
  {
    BAsmCode[CodeLen++] = 0x05;
    BAsmCode[CodeLen++] = Code | Src.AdrVal;
  }
}

static void DecodeMACW_MACSW(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;

    BAsmCode[2] = EvalStrIntExpression(&ArgStr[1], UInt8, &OK);
    if (OK)
    {
      BAsmCode[CodeLen++] = 0x07;
      BAsmCode[CodeLen++] = Code;
      CodeLen++;
    }
  }
}

static void DecodeSACW(Word Code)
{
  tEncodedAddress Addr;
  UNUSED(Code);

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModMem, &Addr))
  {
    if ((Addr.AdrVal != 0x16) || (Addr.AdrVals[0] != 0x00)) WrError(ErrNum_InvAddrMode);
    else if (DecodeAdr(&ArgStr[2], MModMem, &Addr))
    {
      if ((Addr.AdrVal != 0x16) || (Addr.AdrVals[0] != 0x01)) WrError(ErrNum_InvAddrMode);
      else
      {
        BAsmCode[CodeLen++] = 0x09;
        BAsmCode[CodeLen++] = 0x64;
        BAsmCode[CodeLen++] = 0x41;
        BAsmCode[CodeLen++] = 0x46;
      }
    }
  }
}

static void DecodeINCDEC(Word Code)
{
  tEncodedAddress Addr;
  tAdrModeMask AdrModeMask;

  if (Code & 15)
    SetOpSize(Code & 15);
  Code >>= 4;

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

  AdrModeMask = 0;
  if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8 | MModShort1 | MModShort2;
  if ((OpSize == -1) || (OpSize == 1)) AdrModeMask |= MModReg16 | MModShort1 | MModShort2;
  if ((OpSize == -1) || (OpSize == 2)) AdrModeMask |= MModReg24 | MModSP;
  AssumeByte = True;
  DecodeAdr(&ArgStr[1], AdrModeMask, &Addr);
  switch (Addr.AdrMode)
  {
    case ModReg8:
      if (Addr.AdrVal >= 8)
        BAsmCode[CodeLen++] = 0x3c;
      BAsmCode[CodeLen++] = 0xc0 | (Code << 3) | (Addr.AdrVal & 7);
      break;
    case ModReg16:
      if (Addr.AdrVal >= 4)
        BAsmCode[CodeLen++] = 0x40 | (Code << 3) | Addr.AdrVal;
      else
      {
        BAsmCode[CodeLen++] = 0x3e;
        BAsmCode[CodeLen++] = 0x0d | (Code << 1) | (Addr.AdrVal << 5);
      }
      break;
    case ModReg24:
      BAsmCode[CodeLen++] = 0x3e;
      BAsmCode[CodeLen++] = 0x9d | (Code << 1) | (Addr.AdrVal << 5);
      break;
    case ModSP:
      BAsmCode[CodeLen++] = 0x05;
      BAsmCode[CodeLen++] = 0xf8 | Code;
      break;
    case ModShort1:
      BAsmCode[CodeLen++] = 0x3c;
      /* fall-through */
    case ModShort2:
      ExecAssumeByte();
      if (OpSize)
      {
        BAsmCode[CodeLen++] = 0x07;
        BAsmCode[CodeLen++] = 0xe8 | Code;
      }
      else
        BAsmCode[CodeLen++] = 0x26 | Code;
      BAsmCode[CodeLen++] = Addr.AdrVals[0];
      break;
    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeShift(Word Code)
{
  tEncodedAddress Addr;
  Boolean OK;
  Byte Shift;
  tAdrModeMask AdrModeMask;

  if (!ChkArgCnt(2, 2))
    return;
  Shift = EvalStrIntExpression(&ArgStr[2], UInt3, &OK);
  if (!OK)
    return;

  if (Code & 15)
    SetOpSize(Code & 15);
  AdrModeMask = 0;
  if ((OpSize == -1) || (OpSize == 0)) AdrModeMask |= MModReg8;
  if ((Code & 0x8000) && ((OpSize == -1) || (OpSize == 1))) AdrModeMask |= MModReg16;
  DecodeAdr(&ArgStr[1], AdrModeMask, &Addr);
  switch (Addr.AdrMode)
  {
    case ModReg8:
      if (Addr.AdrVal >= 8)
        BAsmCode[CodeLen++] = 0x3c;
      BAsmCode[CodeLen++] = Hi(Code) & 0x7f;
      BAsmCode[CodeLen++] = (Lo(Code) & 0xc0) | (Shift << 3) | (Addr.AdrVal & 7);
      break;
    case ModReg16:
      BAsmCode[CodeLen++] = Hi(Code) & 0x7f;
      BAsmCode[CodeLen++] = 0x40 | (Lo(Code) & 0xc0) | (Shift << 3) | (Addr.AdrVal & 7);
      break;
    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeROR4_ROL4(Word Code)
{
  if (!ChkArgCnt(1, 1));
  else if (!DecodeMem3(ArgStr[1].str.p_str, BAsmCode + 1)) WrError(ErrNum_InvAddrMode);
  else
  {
    BAsmCode[CodeLen++] = 0x05;
    BAsmCode[CodeLen] |= Code; CodeLen++;
  }
}

static void DecodeBIT(Word Code)
{
  LongWord Result;

  UNUSED(Code);

  if (!ChkArgCnt(1, 1));
  else if (DecodeBitAdr(&ArgStr[1], &Result))
  {
    TempResult t;

    as_tempres_ini(&t);
    as_tempres_set_int(&t, Result);
    SetListLineVal(&t);
    EnterIntSymbol(&LabPart, Result, SegNone, False);
    as_tempres_free(&t);
  }
}

static void DecodePUSH_POP(Word Code)
{
  tEncodedAddress Address, SumAddress;
  int z;
  Boolean IsU, IsPUSH;

  if (Code & 15)
    SetOpSize(Code & 15);

  Code = (Code >> 4) & 0xff;
  IsU = (Code == 0x37) || (Code == 0x36),
  IsPUSH = (Code == 0x35);

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

  ClearEncodedAddress(&SumAddress);
  for (z = 1; z <= ArgCnt; z++)
  {
    ClearEncodedAddress(&Address);
    if (!as_strcasecmp(ArgStr[z].str.p_str, "PSW"))
    {
      /* PSW replaces UP in bitmask for PUSHU/POPU */
      if (IsU)
      {
        Address.AdrMode = ModReg16;
        Address.AdrVal = 5;
      }
      /* PSW only allowed a single (first) arg on for PUSH/POP */
      else if (z == 1)
        Address.AdrMode = ModPSW;
      else
      {
        WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[z]);
        return;
      }
      if (!SetOpSize(1))
        return;
    }
    else
    {
      tAdrModeMask AdrModeMask = MModReg16;

      /* sfr/sfrp/rg only allowed as single (first) argument, and only for PUSH/POP */

      if ((z == 1) && (!IsU))
        AdrModeMask |= MModSFR | MModReg24;
      if (!DecodeAdr(&ArgStr[z], AdrModeMask, &Address))
        return;

      /* UP not allowed for PUSHU(POPU */

      if (IsU && (Address.AdrVal == 5))
      {
        WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[z]);
        return;
      }
    }

    /* merge this argument with rest so far: */

    if (SumAddress.AdrMode == ModNone)
    {
      SumAddress = Address;
      if (Address.AdrMode == ModReg16)
        SumAddress.AdrVals[0] = 1 << Address.AdrVal;
    }
    else if ((Address.AdrMode != SumAddress.AdrMode) || (SumAddress.AdrMode != ModReg16))
    {
      WrError(ErrNum_InvAddrMode);
      return;
    }
    else
      SumAddress.AdrVals[0] |= 1 << Address.AdrVal;
  }

  AssumeByte = True;
  switch (SumAddress.AdrMode)
  {
    case ModReg16:
      BAsmCode[CodeLen++] = Code;
      BAsmCode[CodeLen++] = SumAddress.AdrVals[0];
      break;
    case ModPSW:
      BAsmCode[CodeLen++] = IsPUSH ? 0x49 : 0x48;
      break;
    case ModSFR:
      ExecAssumeByte();
      BAsmCode[CodeLen++] = 0x07;
      BAsmCode[CodeLen++] = (IsPUSH ? 0xdb: 0xda) - (OpSize << 1);
      BAsmCode[CodeLen++] = SumAddress.AdrVals[0];
      break;
    case ModReg24:
      BAsmCode[CodeLen++] = 0x09;
      BAsmCode[CodeLen++] = (IsPUSH ? 0x89 : 0x99) | (SumAddress.AdrVal << 1);
      break;
    case ModNone:
      break;
    default:
      WrError(ErrNum_InvAddrMode);
  }
}

static void DecodeCALL_BR(Word IsCALL)
{
  tEncodedAddress Addr;

  if (ChkArgCnt(1, 1)
   && StripIndirect(&ArgStr[1]))
  {
    DecodeAdr(&ArgStr[1], MModReg16 | MModReg24, &Addr);
    switch (Addr.AdrMode)
    {
      case ModReg16:
        BAsmCode[CodeLen++] = 0x05;
        BAsmCode[CodeLen++] = 0x68 | (IsCALL << 4) | Addr.AdrVal;
        break;
      case ModReg24:
        BAsmCode[CodeLen++] = 0x05;
        BAsmCode[CodeLen++] = 0x61 | (IsCALL << 4) | (Addr.AdrVal << 1);
        break;
      case ModNone:
        break;
      default:
        WrError(ErrNum_InvAddrMode);
    }
  }
  else
  {
    DecodeAdr(&ArgStr[1], MModReg16 | MModReg24 | MModAbs16 | MModAbs20, &Addr);
    switch (Addr.AdrMode)
    {
      case ModReg16:
        BAsmCode[CodeLen++] = 0x05;
        BAsmCode[CodeLen++] = 0x48 | (IsCALL << 4) | Addr.AdrVal;
        break;
      case ModReg24:
        BAsmCode[CodeLen++] = 0x05;
        BAsmCode[CodeLen++] = 0x41 | (IsCALL << 4) | (Addr.AdrVal << 1);
        break;
      case ModAbs16:
      case ModAbs20:
      {
        LongWord Dest = GetAbsVal(&Addr);
        LongInt Dist16 = Dest - (EProgCounter() + 3),
                Dist8 = Dest - (EProgCounter() + 2);
        Boolean Dist16OK = (Dist16 >= -0x8000l) && (Dist16 <= 0x7fffl),
                Dist8OK = (Dist8 >= -0x80) && (Dist8 <= 0x7f);

        if (!Addr.ForceAbs && !Addr.ForceRel)
        {
          if (Dist8OK && !IsCALL)
          {
            Addr.ForceRel = True; Addr.ForceAbs = False;
          }
          else if (Dist16OK)
          {
            Addr.ForceRel = Addr.ForceAbs = True;
          }
          else
          {
            Addr.ForceAbs = True; Addr.ForceRel = False;
          }
        }

        if (!Addr.ForceRel)
        {
          if (Addr.AdrMode == ModAbs20)
          {
            BAsmCode[CodeLen++] = 0x09;
            BAsmCode[CodeLen++] = 0xe0 | (IsCALL << 4) | Lo(Addr.AdrVals[2]);
          }
          else
            BAsmCode[CodeLen++] = IsCALL ? 0x28 : 0x2c;
          BAsmCode[CodeLen++] = Addr.AdrVals[0];
          BAsmCode[CodeLen++] = Addr.AdrVals[1];
        }
        else if (IsCALL || Addr.ForceAbs)
        {
          if (!mFirstPassUnknown(Addr.AdrValSymFlags) && !Dist16OK) WrError(ErrNum_JmpDistTooBig);
          else
          {
            BAsmCode[CodeLen++] = IsCALL ? 0x3f : 0x43;
            BAsmCode[CodeLen++] = Dist16 & 0xff;
            BAsmCode[CodeLen++] = (Dist16 >> 8) & 0xff;
          }
        }
        else
        {
          if (!mFirstPassUnknown(Addr.AdrValSymFlags) && !Dist8OK) WrError(ErrNum_JmpDistTooBig);
          else
          {
            BAsmCode[CodeLen++] = 0x14;
            BAsmCode[CodeLen++] = Dist8 & 0xff;
          }
        }

        break;
      }
      case ModNone:
        break;
      default:
        WrError(ErrNum_InvAddrMode);
    }
  }
}

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

  if (ArgCnt != 1) WrError(ErrNum_InvAddrMode);
  else
  {
    Boolean OK;
    Word Addr;
    tSymbolFlags Flags;

    Addr = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], !!(*ArgStr[1].str.p_str == '!'), UInt12, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      Addr |= 0x800;
    if (OK && ChkRange(Addr, 0x800, 0xfff))
    {
      BAsmCode[CodeLen++] = 0x90 | ((Addr >> 8) & 7);
      BAsmCode[CodeLen++] = Lo(Addr);
    }
  }
}

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

  if (ArgCnt != 1) WrError(ErrNum_InvAddrMode);
  else if (!StripIndirect(&ArgStr[1])) WrError(ErrNum_InvAddrMode);
  else
  {
    Boolean OK;
    Word Addr;
    tSymbolFlags Flags;

    Addr = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], !!(*ArgStr[1].str.p_str == '!'), UInt7, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      Addr = (Addr | 0x40) & 0xfe;
    if (OK && (Addr & 1)) WrError(ErrNum_NotAligned);
    else if (OK && ChkRange(Addr, 0x40, 0xff))
    {
      BAsmCode[CodeLen++] = 0xe0 | ((Addr >> 1) & 0x1f);
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (!DecodeRB(ArgStr[1].str.p_str, BAsmCode + 1)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  else
  {
    BAsmCode[CodeLen++] = 0x05;
    BAsmCode[CodeLen++] = BAsmCode[1] | 0xd8;
  }
}

static void DecodeRETCS(Word Code)
{
  if (ArgCnt != 1) WrError(ErrNum_InvAddrMode);
  else
  {
    Boolean OK;
    Word Addr;

    Addr = EvalStrIntExpressionOffs(&ArgStr[1], !!(*ArgStr[1].str.p_str == '!'), UInt16, &OK);
    if (OK)
    {
      PutCode(Code);
      BAsmCode[CodeLen++] = Lo(Addr);
      BAsmCode[CodeLen++] = Hi(Addr);
    }
  }
}

static void DecodeRel(Word Code)
{
  if (ArgCnt != 1) WrError(ErrNum_InvAddrMode);
  else
  {
    PutCode(Code);
    AppendRel8(&ArgStr[1]);
  }
}

static void DecodeBitRel(Word Code)
{
  LongWord BitAddr;

  if (ArgCnt != 2) WrError(ErrNum_InvAddrMode);
  else if (DecodeBitAdr(&ArgStr[1], &BitAddr))
  {
    switch ((BitAddr >> 28) & 15)
    {
      case eBitTypeSAddr1:
        if (Code != 0xb0)
          goto Common;
        BAsmCode[CodeLen++] = 0x3c;
        BAsmCode[CodeLen++] = 0x70 | ((BitAddr >> 24) & 7);
        BAsmCode[CodeLen++] = BitAddr & 0xff;
        break;
      case eBitTypeSAddr2_SFR:
        if ((Code != 0xb0) || (BitAddr & Bit27))
          goto Common;
        BAsmCode[CodeLen++] = 0x70 | ((BitAddr >> 24) & 7);
        BAsmCode[CodeLen++] = BitAddr & 0xff;
        break;
      Common:
      default:
        DecodeBitOpCore2(BitAddr, Code);
    }

    AppendRel8(&ArgStr[2]);
  }
}

static void DecodeDBNZ(Word Code)
{
  tEncodedAddress Addr;

  UNUSED(Code);

  if (ArgCnt != 2)
  {
    WrError(ErrNum_InvAddrMode);
    return;
  }

  DecodeAdr(&ArgStr[1], MModShort1 | MModShort2 | MModReg8, &Addr);
  switch (Addr.AdrMode)
  {
    case ModShort1:
      BAsmCode[CodeLen++] = 0x3c;
      /* fall-through */
    case ModShort2:
      BAsmCode[CodeLen++] = 0x3b;
      BAsmCode[CodeLen++] = Addr.AdrVals[0];
      break;
    case ModReg8:
      if (Addr.AdrVal == BReg8())
        BAsmCode[CodeLen++] = 0x33;
      else if (Addr.AdrVal == CReg8())
        BAsmCode[CodeLen++] = 0x32;
      else
      {
        WrError(ErrNum_InvAddrMode);
        return;
      }
      break;
    case ModNone:
      return;
    default:
      WrError(ErrNum_InvAddrMode);
      return;
  }

  AppendRel8(&ArgStr[2]);
}

static void DecodeLOCATION(Word Code)
{
  Byte Val;
  Boolean OK;
  tSymbolFlags Flags;

  UNUSED(Code);

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

  Val = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt4, &OK, &Flags);
  if (!OK)
    return;
  if (mFirstPassUnknown(Flags))
    Val = 0;
  switch (Val)
  {
    case 0:
      BAsmCode[CodeLen++] = 0x09;
      BAsmCode[CodeLen++] = 0xc1;
      BAsmCode[CodeLen++] = 0xfe;
      BAsmCode[CodeLen++] = 0x01;
      break;
    case 15:
      BAsmCode[CodeLen++] = 0x09;
      BAsmCode[CodeLen++] = 0xc1;
      BAsmCode[CodeLen++] = 0xff;
      BAsmCode[CodeLen++] = 0x00;
      break;
    default:
      WrError(ErrNum_OverRange);
  }
}

static void DecodeSEL(Word Code)
{
  Byte Bank;

  UNUSED(Code);

  if ((ArgCnt == 2) && (as_strcasecmp(ArgStr[2].str.p_str, "ALT")))
  {
    WrError(ErrNum_InvAddrMode);
    return;
  }
  if (!ChkArgCnt(1, 2))
    return;

  if (!DecodeRB(ArgStr[1].str.p_str, &Bank)) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  else
  {
    BAsmCode[CodeLen++] = 0x05;
    BAsmCode[CodeLen++] = 0xa8 | ((ArgCnt - 1) << 4) | Bank;
  }
}

static void DecodeCHK(Word Code)
{
  tEncodedAddress Address;

  if (ChkArgCnt(1, 1)
   && DecodeAdr(&ArgStr[1], MModSFR, &Address))
  {
    PutCode(Code);
    BAsmCode[CodeLen++] = Address.AdrVals[0];
  }
}

static void DecodeMOVTBLW(Word Code)
{
  Byte Addr, Value;
  Boolean OK;

  UNUSED(Code);

  if (ChkArgCnt(2, 2))
  {
    Addr = EvalStrIntExpressionOffs(&ArgStr[1], !!(*ArgStr[1].str.p_str == '!'), UInt8, &OK);
    if (OK)
    {
      Value = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
      if (OK)
      {
        BAsmCode[CodeLen++] = 0x09;
        BAsmCode[CodeLen++] = 0xa0;
        BAsmCode[CodeLen++] = Addr;
        BAsmCode[CodeLen++] = Value;
      }
    }
  }
}

static void DecodeStringAcc(Word Code)
{
  tEncodedAddress Addr;

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[2], MModReg8, &Addr))
  {
    if (Addr.AdrVal != AccReg8()) WrError(ErrNum_InvAddrMode);
    else if (DecodeAdr(&ArgStr[1], MModMem, &Addr))
    {
      if (Addr.AdrVal != 0x16) WrError(ErrNum_InvAddrMode);
      else if ((Addr.AdrVals[0] & 0xfd) != 0) WrError(ErrNum_InvAddrMode);
      else
        PutCode(Code | ((Addr.AdrVals[0] & 2) << 3));
    }
  }
}

static void DecodeStringString(Word Code)
{
  tEncodedAddress Addr;

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModMem, &Addr))
  {
    Byte Dir = Addr.AdrVals[0];

    if (Addr.AdrVal != 0x16) WrError(ErrNum_InvAddrMode);
    else if ((Addr.AdrVals[0] & 0xfd) != 0) WrError(ErrNum_InvAddrMode);
    else if (DecodeAdr(&ArgStr[2], MModMem, &Addr))
    {
      if (Addr.AdrVal != 0x16) WrError(ErrNum_InvAddrMode);
      else if (Addr.AdrVals[0] != Dir + 1) WrError(ErrNum_InvAddrMode);
      else
        PutCode(Code | ((Dir & 2) << 3));
    }
  }
}

/*-------------------------------------------------------------------------*/
/* dynamic code table handling */

static void AddInstr(const char *pInstr, InstProc Proc, Word Code, unsigned SizeMask)
{
  char Instr[20];

  Code <<= 4;

  if (SizeMask & 1)
    AddInstTable(InstTable, pInstr, Code, Proc);
  if (SizeMask & 2)
  {
    as_snprintf(Instr, sizeof(Instr), "%sW", pInstr);
    AddInstTable(InstTable, Instr, Code + 1, Proc);
  }
  if (SizeMask & 4)
  {
    as_snprintf(Instr, sizeof(Instr), "%sG", pInstr);
    AddInstTable(InstTable, Instr, Code + 2, Proc);
  }
}

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

  add_null_pseudo(InstTable);

  AddInstr("MOV"  , DecodeMOV, 0x000, 0x07);
  AddInstr("XCH"  , DecodeXCH, 0x000, 0x03);
  AddInstr("ADD"  , DecodeALU, 0x000, 0x07);
  AddInstr("ADDC" , DecodeALU, 0xff1, 0x01);
  AddInstr("SUB"  , DecodeALU, 0x222, 0x07);
  AddInstr("SUBC" , DecodeALU, 0xff3, 0x01);
  AddInstr("CMP"  , DecodeALU, 0xf77, 0x03);
  AddInstr("AND"  , DecodeALU, 0xff4, 0x01);
  AddInstr("OR"   , DecodeALU, 0xff6, 0x01);
  AddInstr("XOR"  , DecodeALU, 0xff5, 0x01);
  AddInstr("MULU" , DecodeMULU,0x000, 0x03);
  AddInstTable(InstTable, "DIVUW", 0, DecodeDIVUW);
  AddInstTable(InstTable, "MULW",  0x38, DecodeMULW_DIVUX);
  AddInstTable(InstTable, "DIVUX", 0xe8, DecodeMULW_DIVUX);
  AddInstTable(InstTable, "MACW" , 0x85, DecodeMACW_MACSW);
  AddInstTable(InstTable, "MACSW", 0x95, DecodeMACW_MACSW);
  AddInstTable(InstTable, "SACW",  0, DecodeSACW);
  AddInstr("INC"  , DecodeINCDEC, 0, 0x07);
  AddInstr("DEC"  , DecodeINCDEC, 1, 0x07);
  AddInstTable(InstTable, "ADJBA", 0x05fe, DecodeFixed);
  AddInstTable(InstTable, "ADJBS", 0x05ff, DecodeFixed);
  AddInstTable(InstTable, "CVTBW", 0x0004, DecodeFixed);
  AddInstr("ROR"  , DecodeShift, 0x304, 0x01);
  AddInstr("ROL"  , DecodeShift, 0x314, 0x01);
  AddInstr("RORC" , DecodeShift, 0x300, 0x01);
  AddInstr("ROLC" , DecodeShift, 0x310, 0x01);
  AddInstr("SHR"  , DecodeShift, 0xb08, 0x03);
  AddInstr("SHL"  , DecodeShift, 0xb18, 0x03);
  AddInstTable(InstTable, "ROR4", 0x88, DecodeROR4_ROL4);
  AddInstTable(InstTable, "ROL4", 0x98, DecodeROR4_ROL4);
  AddInstTable(InstTable, "MOV1", 0, DecodeMOV1);
  AddInstTable(InstTable, "AND1", 0x20, DecodeAND1_OR1);
  AddInstTable(InstTable, "OR1",  0x40, DecodeAND1_OR1);
  AddInstTable(InstTable, "XOR1", 0x60, DecodeXOR1);
  AddInstTable(InstTable, "NOT1", 0x70, DecodeNOT1);
  AddInstTable(InstTable, "SET1", 0x80, DecodeSET1_CLR1);
  AddInstTable(InstTable, "CLR1", 0x90, DecodeSET1_CLR1);
  AddInstr("PUSH", DecodePUSH_POP, 0x35, 0x07);
  AddInstr("PUSHU",DecodePUSH_POP, 0x37, 0x03);
  AddInstr("POP" , DecodePUSH_POP, 0x34, 0x07);
  AddInstr("POPU", DecodePUSH_POP, 0x36, 0x03);
  AddInstTable(InstTable, "ADDWG", 0, DecodeADDWG_SUBWG);
  AddInstTable(InstTable, "SUBWG", 2, DecodeADDWG_SUBWG);

  AddInstTable(InstTable, "CALL", 1, DecodeCALL_BR);
  AddInstTable(InstTable, "BR"  , 0, DecodeCALL_BR);
  AddInstTable(InstTable, "CALLF", 0, DecodeCALLF);
  AddInstTable(InstTable, "CALLT", 0, DecodeCALLT);
  AddInstTable(InstTable, "BRK", 0x5e, DecodeFixed);
  AddInstTable(InstTable, "BRKCS", 0, DecodeBRKCS);
  AddInstTable(InstTable, "RET", 0x56, DecodeFixed);
  AddInstTable(InstTable, "RETI", 0x57, DecodeFixed);
  AddInstTable(InstTable, "RETB", 0x5f, DecodeFixed);
  AddInstTable(InstTable, "RETCS", 0x29, DecodeRETCS);
  AddInstTable(InstTable, "RETCSB", 0x09b0, DecodeRETCS);

  AddInstTable(InstTable, "BNZ", 0x80, DecodeRel);
  AddInstTable(InstTable, "BNE", 0x80, DecodeRel);
  AddInstTable(InstTable, "BZ", 0x81, DecodeRel);
  AddInstTable(InstTable, "BE", 0x81, DecodeRel);
  AddInstTable(InstTable, "BNC", 0x82, DecodeRel);
  AddInstTable(InstTable, "BNL", 0x82, DecodeRel);
  AddInstTable(InstTable, "BC", 0x83, DecodeRel);
  AddInstTable(InstTable, "BL", 0x83, DecodeRel);
  AddInstTable(InstTable, "BNV", 0x84, DecodeRel);
  AddInstTable(InstTable, "BPO", 0x84, DecodeRel);
  AddInstTable(InstTable, "BV", 0x85, DecodeRel);
  AddInstTable(InstTable, "BPE", 0x85, DecodeRel);
  AddInstTable(InstTable, "BP", 0x86, DecodeRel);
  AddInstTable(InstTable, "BN", 0x87, DecodeRel);
  AddInstTable(InstTable, "BLT", 0x07f8, DecodeRel);
  AddInstTable(InstTable, "BGE", 0x07f9, DecodeRel);
  AddInstTable(InstTable, "BLE", 0x07fa, DecodeRel);
  AddInstTable(InstTable, "BGT", 0x07fb, DecodeRel);
  AddInstTable(InstTable, "BNH", 0x07fc, DecodeRel);
  AddInstTable(InstTable, "BH", 0x07fd, DecodeRel);
  AddInstTable(InstTable, "BF", 0xa0, DecodeBitRel);
  AddInstTable(InstTable, "BT", 0xb0, DecodeBitRel);
  AddInstTable(InstTable, "BTCLR", 0xd0, DecodeBitRel);
  AddInstTable(InstTable, "BFSET", 0xc0, DecodeBitRel);
  AddInstTable(InstTable, "DBNZ", 0, DecodeDBNZ);

  AddInstTable(InstTable, "LOCATION", 0, DecodeLOCATION);
  AddInstTable(InstTable, "SEL", 0, DecodeSEL);
  AddInstTable(InstTable, "SWRS", 0x05fc, DecodeFixed);
  AddInstTable(InstTable, "NOP", 0x00, DecodeFixed);
  AddInstTable(InstTable, "EI", 0x4b, DecodeFixed);
  AddInstTable(InstTable, "DI", 0x4a, DecodeFixed);

  AddInstTable(InstTable, "CHKL", 0x07c8, DecodeCHK);
  AddInstTable(InstTable, "CHKLA", 0x07c9, DecodeCHK);

  AddInstTable(InstTable, "MOVTBLW", 0, DecodeMOVTBLW);
  AddInstTable(InstTable, "MOVM"   , 0x1500, DecodeStringAcc);
  AddInstTable(InstTable, "MOVBK"  , 0x1520, DecodeStringString);
  AddInstTable(InstTable, "XCHM"   , 0x1501, DecodeStringAcc);
  AddInstTable(InstTable, "XCHBK"  , 0x1521, DecodeStringString);
  AddInstTable(InstTable, "CMPME"  , 0x1504, DecodeStringAcc);
  AddInstTable(InstTable, "CMPBKE" , 0x1524, DecodeStringString);
  AddInstTable(InstTable, "CMPMNE" , 0x1505, DecodeStringAcc);
  AddInstTable(InstTable, "CMPBKNE", 0x1525, DecodeStringString);
  AddInstTable(InstTable, "CMPMC"  , 0x1507, DecodeStringAcc);
  AddInstTable(InstTable, "CMPBKC" , 0x1527, DecodeStringString);
  AddInstTable(InstTable, "CMPMNC" , 0x1506, DecodeStringAcc);
  AddInstTable(InstTable, "CMPBKNC", 0x1526, DecodeStringString);

  AddInstTable(InstTable, "BIT", 0, DecodeBIT);
  AddIntelPseudo(InstTable, eIntPseudoFlag_LittleEndian);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
}

/*-------------------------------------------------------------------------*/
/* interface to common layer */

static void MakeCode_78K4(void)
{
  OpSize = eSymbolSizeUnknown;
  AssumeByte = False;

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

static Boolean IsDef_78K4(void)
{
  return Memo("BIT");
}

static void InternSymbol_78K4(char *pAsc, TempResult *pErg)
{
  if ((!as_strcasecmp(pAsc, "PSWL"))
   || (!as_strcasecmp(pAsc, "PSW")))
    as_tempres_set_int(pErg, PSWLAddr);
  else if (!as_strcasecmp(pAsc, "PSWH"))
    as_tempres_set_int(pErg, PSWHAddr);
}

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

static void SwitchTo_78K4(void)
{
  const TFamilyDescr *pDescr;

  pDescr = FindFamilyByName("78K4");

  TurnWords = False;
  SetIntConstMode(eIntConstModeIntel);

  PCSymbol = "PC";
  HeaderID = pDescr->Id;
  NOPCode = 0x00;
  DivideChars = ",";
  HasAttrs = False;

  ValidSegs = 1 << SegCode;
  Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  SegLimits[SegCode] = 0xffffff;

  assume_set(ASSUME78K4s, as_array_size(ASSUME78K4s));

  MakeCode = MakeCode_78K4;
  IsDef = IsDef_78K4;
  InternSymbol = InternSymbol_78K4;
  SwitchFrom = SwitchFrom_78K4; InitFields();
}

void code78k4_init(void)
{
  CPU784026 = AddCPU("784026", SwitchTo_78K4);
}
