Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

/* code51.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator fuer MCS-51/252 Prozessoren                                 */
/*                                                                           */
/*****************************************************************************/

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

#include "bpemu.h"
#include "strutil.h"
#include "chunks.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "asmrelocs.h"
#include "asmlist.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "asmitree.h"
#include "codevars.h"
#include "fileformat.h"
#include "errmsg.h"
#include "intformat.h"

#include "code51.h"

/*-------------------------------------------------------------------------*/
/* Daten */

typedef struct
{
  CPUVar MinCPU;
  Word Code;
} FixedOrder;

enum
{
  ModNone = -1,
  ModReg = 1,
  ModIReg8 = 2,
  ModIReg = 3,
  ModInd = 5,
  ModImm = 7,
  ModImmEx = 8,
  ModDir8 = 9,
  ModDir16 = 10,
  ModAcc = 11,
  ModBit51 = 12,
  ModBit251 = 13
};

#define MModReg (1 << ModReg)
#define MModIReg8 (1 << ModIReg8)
#define MModIReg (1 << ModIReg)
#define MModInd (1 << ModInd)
#define MModImm (1 << ModImm)
#define MModImmEx (1 << ModImmEx)
#define MModDir8 (1 << ModDir8)
#define MModDir16 (1 << ModDir16)
#define MModAcc (1 << ModAcc)
#define MModBit51 (1 << ModBit51)
#define MModBit251 (1 << ModBit251)

#define MMod51 (MModReg | MModIReg8 | MModImm | MModAcc | MModDir8)
#define MMod251 (MModIReg | MModInd | MModImmEx | MModDir16)

#define AccReg 11
#define DPXValue 14
#define SPXValue 15

static FixedOrder *FixedOrders;
static FixedOrder *AccOrders;
static FixedOrder *CondOrders;
static FixedOrder *BCondOrders;

static Byte AdrVals[5];
static Byte AdrPart, AdrSize;
static ShortInt AdrMode,OpSize;
static Boolean MinOneIs0;

static Boolean SrcMode;

static CPUVar CPU87C750, CPU8051, CPU8052, CPU80C320,
       CPU80501, CPU80502, CPU80504, CPU80515, CPU80517,
       CPU80C390,
       CPU80251, CPU80251T;

static PRelocEntry AdrRelocInfo, BackupAdrRelocInfo;
static LongWord AdrOffset, AdrRelocType,
                BackupAdrOffset, BackupAdrRelocType;

/*-------------------------------------------------------------------------*/
/* Adressparser */

static void SetOpSize(ShortInt NewSize)
{
  if (OpSize == -1)
    OpSize = NewSize;
  else if (OpSize != NewSize)
  {
    WrError(ErrNum_ConfOpSizes);
    AdrMode = ModNone;
    AdrCnt = 0;
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRegCore(const char *pAsc, tRegInt *pValue, tSymbolSize *pSize)
 * \brief  check whether argument describes a CPU register
 * \param  pAsc argument
 * \param  pValue resulting register # if yes
 * \param  pSize resulting register size if yes
 * \return true if yes
 * ------------------------------------------------------------------------ */


static Boolean DecodeRegCore(const char *pAsc, tRegInt *pValue, tSymbolSize *pSize)
{
  static Byte Masks[3] = { 0, 1, 3 };

  const char *Start;
  int alen = strlen(pAsc);
  Boolean IO;

  if (!as_strcasecmp(pAsc, "DPX"))
  {
    *pValue = DPXValue;
    *pSize = eSymbolSize32Bit;
    return True;
  }

  if (!as_strcasecmp(pAsc, "SPX"))
  {
    *pValue = SPXValue;
    *pSize = eSymbolSize32Bit;
    return True;
  }

  if ((alen >= 2) && (as_toupper(*pAsc) == 'R'))
  {
    Start = pAsc + 1;
    *pSize = eSymbolSize8Bit;
  }
  else if ((MomCPU >= CPU80251) && (alen >= 3) && (as_toupper(*pAsc) == 'W') && (as_toupper(pAsc[1]) == 'R'))
  {
    Start = pAsc + 2;
    *pSize = eSymbolSize16Bit;
  }
  else if ((MomCPU >= CPU80251) && (alen >= 3) && (as_toupper(*pAsc) == 'D') && (as_toupper(pAsc[1]) == 'R'))
  {
    Start = pAsc + 2;
    *pSize = eSymbolSize32Bit;
  }
  else
    return False;

  *pValue = ConstLongInt(Start, &IO, 10);
  if (!IO) return False;
  else if (*pValue & Masks[*pSize]) return False;
  else
  {
    *pValue >>= *pSize;
    switch (*pSize)
    {
      case eSymbolSize8Bit:
        return ((*pValue < 8) || ((MomCPU >= CPU80251) && (*pValue < 16)));
      case eSymbolSize16Bit:
        return (*pValue < 16);
      case eSymbolSize32Bit:
        return ((*pValue < 8) || (*pValue == DPXValue) || (*pValue == SPXValue));
      default:
        return False;
    }
  }
}

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


static void DissectReg_51(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
  switch (InpSize)
  {
    case eSymbolSize8Bit:
      as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
      break;
    case eSymbolSize16Bit:
      as_snprintf(pDest, DestSize, "WR%u", (unsigned)Value << 1);
      break;
    case eSymbolSize32Bit:
      if (SPXValue == Value)
        strmaxcpy(pDest, "SPX", DestSize);
      else if (DPXValue == Value)
        strmaxcpy(pDest, "DPX", DestSize);
      else
        as_snprintf(pDest, DestSize, "DR%u", (unsigned)Value << 2);
      break;
    default:
      as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, Byte *pValue, tSymbolSize *pSize, Boolean MustBeReg)
 * \brief  check whether argument is a CPU register or user-defined register alias
 * \param  pArg argument
 * \param  pValue resulting register # if yes
 * \param  pSize resulting register size if yes
 * \param  MustBeReg operand must be a register
 * \return reg eval result
 * ------------------------------------------------------------------------ */


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

  if (DecodeRegCore(pArg->str.p_str, &RegDescr.Reg, pSize))
  {
    *pValue = RegDescr.Reg;
    return eIsReg;
  }

  RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSizeUnknown, MustBeReg);
  *pValue = RegDescr.Reg;
  *pSize = EvalResult.DataSize;
  return RegEvalResult;
}

static void SaveAdrRelocs(LongWord Type, LongWord Offset)
{
  AdrOffset = Offset;
  AdrRelocType = Type;
  AdrRelocInfo = LastRelocs;
  LastRelocs = NULL;
}

static void SaveBackupAdrRelocs(void)
{
  BackupAdrOffset = AdrOffset;
  BackupAdrRelocType = AdrRelocType;
  BackupAdrRelocInfo = AdrRelocInfo;
  AdrRelocInfo = NULL;
}

static void TransferAdrRelocs(LongWord Offset)
{
  TransferRelocs2(AdrRelocInfo, ProgCounter() + AdrOffset + Offset, AdrRelocType);
  AdrRelocInfo = NULL;
}

static void TransferBackupAdrRelocs(LargeWord Offset)
{
  TransferRelocs2(BackupAdrRelocInfo, ProgCounter() + BackupAdrOffset + Offset, BackupAdrRelocType);
  AdrRelocInfo = NULL;
}

static void DecodeAdr(tStrComp *pArg, Word Mask)
{
  Boolean OK, FirstFlag;
  tEvalResult EvalResult;
  tSymbolSize HSize;
  Word H16;
  LongWord H32;
  tStrComp SegComp, AddrComp, *pAddrComp;
  int SegType;
  char Save = '\0', *pSegSepPos;
  Word ExtMask;

  AdrMode = ModNone; AdrCnt = 0;

  ExtMask = MMod251 & Mask;
  if (MomCPU < CPU80251) Mask &= MMod51;

  if (!*pArg->str.p_str)
     return;

  if (!as_strcasecmp(pArg->str.p_str, "A"))
  {
    if (!(Mask & MModAcc))
    {
      AdrMode = ModReg;
      AdrPart = AccReg;
    }
    else
      AdrMode = ModAcc;
    SetOpSize(0);
    goto chk;
  }

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

    StrCompRefRight(&Comp, pArg, 1);
    if ((OpSize == -1) && (MinOneIs0)) OpSize = 0;
    switch (OpSize)
    {
      case -1:
        WrError(ErrNum_UndefOpSizes);
        break;
      case 0:
        AdrVals[0] = EvalStrIntExpression(&Comp, Int8, &OK);
        if (OK)
        {
          AdrMode = ModImm;
          AdrCnt = 1;
          SaveAdrRelocs(RelocTypeB8, 0);
        }
        break;
      case 1:
        H16 = EvalStrIntExpression(&Comp, Int16, &OK);
        if (OK)
        {
          AdrVals[0] = Hi(H16);
          AdrVals[1] = Lo(H16);
          AdrMode = ModImm;
          AdrCnt = 2;
          SaveAdrRelocs(RelocTypeB16, 0);
        }
        break;
      case 2:
        H32 = EvalStrIntExpressionWithResult(&Comp, Int32, &EvalResult);
        if (mFirstPassUnknown(EvalResult.Flags))
          H32 &= 0xffff;
        if (EvalResult.OK)
        {
          AdrVals[1] = H32 & 0xff;
          AdrVals[0] = (H32 >> 8) & 0xff;
          H32 >>= 16;
          if (H32 == 0)
            AdrMode = ModImm;
          else if ((H32 == 1) || (H32 == 0xffff))
            AdrMode = ModImmEx;
          else
            WrError(ErrNum_UndefOpSizes);
          if (AdrMode != ModNone)
            AdrCnt = 2;
          SaveAdrRelocs(RelocTypeB16, 0);
        }
        break;
      case 3:
        H32 = EvalStrIntExpression(&Comp, Int24, &OK);
        if (OK)
        {
          AdrVals[0] = (H32 >> 16) & 0xff;
          AdrVals[1] = (H32 >> 8) & 0xff;
          AdrVals[2] = H32 & 0xff;
          AdrCnt = 3;
          AdrMode = ModImm;
          SaveAdrRelocs(RelocTypeB24, 0);
        }
        break;
    }
    goto chk;
  }

  switch (DecodeReg(pArg, &AdrPart, &HSize, False))
  {
    case eIsReg:
      if ((MomCPU >= CPU80251) && ((Mask & MModReg) == 0))
        AdrMode = ((HSize == 0) && (AdrPart == AccReg)) ? ModAcc : ModReg;
      else
        AdrMode = ModReg;
      SetOpSize(HSize);
      goto chk;
    case eIsNoReg:
      break;
    case eRegAbort:
      return;
  }

  if (*pArg->str.p_str == '@')
  {
    tStrComp IndirComp;
    char *PPos, *MPos;

    StrCompRefRight(&IndirComp, pArg, 1);
    PPos = strchr(IndirComp.str.p_str, '+');
    MPos = strchr(IndirComp.str.p_str, '-');
    if ((MPos) && ((MPos < PPos) || (!PPos)))
      PPos = MPos;
    if (PPos)
    {
      Save = *PPos;
      *PPos = '\0';
      IndirComp.Pos.Len = PPos - IndirComp.str.p_str;
    }
    switch (DecodeReg(&IndirComp, &AdrPart, &HSize, False))
    {
      case eIsReg:
      {
        if (!PPos)
        {
          H32 = 0;
          OK = True;
        }
        else
        {
          tStrComp DispComp;

          *PPos = Save;
          StrCompRefRight(&DispComp, &IndirComp, PPos - IndirComp.str.p_str + !!(Save == '+'));
          H32 = EvalStrIntExpression(&DispComp, SInt16, &OK);
        }
        if (OK)
          switch (HSize)
          {
            case eSymbolSize8Bit:
              if ((AdrPart>1) || (H32 != 0)) WrError(ErrNum_InvAddrMode);
              else
                AdrMode = ModIReg8;
              break;
            case eSymbolSize16Bit:
              if (H32 == 0)
              {
                AdrMode = ModIReg;
                AdrSize = 0;
              }
              else
              {
                AdrMode = ModInd;
                AdrSize = 0;
                AdrVals[1] = H32 & 0xff;
                AdrVals[0] = (H32 >> 8) & 0xff;
                AdrCnt = 2;
              }
              break;
            case eSymbolSize32Bit:
              if (H32 == 0)
              {
                AdrMode = ModIReg;
                AdrSize = 2;
              }
              else
              {
                AdrMode = ModInd;
                AdrSize = 2;
                AdrVals[1] = H32 & 0xff;
                AdrVals[0] = (H32 >> 8) & 0xff;
                AdrCnt = 2;
              }
              break;
            default:
              break;
          }
        break;
      }
      case eIsNoReg:
        WrStrErrorPos(ErrNum_InvReg, &IndirComp);
        break;
      case eRegAbort:
        /* will go to function end anyway after restoring separator */
        break;
    }
    if (PPos)
      *PPos = Save;
    goto chk;
  }

  FirstFlag = False;
  SegType = -1;
  pSegSepPos = QuotPos(pArg->str.p_str, ':');
  if (pSegSepPos)
  {
    StrCompSplitRef(&SegComp, &AddrComp, pArg, pSegSepPos);
    if (MomCPU < CPU80251)
    {
      WrError(ErrNum_InvAddrMode);
      return;
    }
    else
    {
      if (!as_strcasecmp(SegComp.str.p_str, "S"))
        SegType = -2;
      else
      {
        SegType = EvalStrIntExpressionWithResult(&SegComp, UInt8, &EvalResult);
        if (!EvalResult.OK)
          return;
        if (mFirstPassUnknown(EvalResult.Flags))
          FirstFlag = True;
      }
    }
    pAddrComp = &AddrComp;
  }
  else
    pAddrComp = pArg;

  switch (SegType)
  {
    case -2:
      H32 = EvalStrIntExpressionWithResult(pAddrComp, UInt9, &EvalResult);
      ChkSpace(SegIO, EvalResult.AddrSpaceMask);
      if (mFirstPassUnknown(EvalResult.Flags))
        H32 = (H32 & 0xff) | 0x80;
      break;
    case -1:
      H32 = EvalStrIntExpressionWithResult(pAddrComp, UInt24, &EvalResult);
      break;
    default:
      H32 = EvalStrIntExpressionWithResult(pAddrComp, UInt16, &EvalResult);
  }
  if (mFirstPassUnknown(EvalResult.Flags))
    FirstFlag = True;
  if (!EvalResult.OK)
    return;

  if ((SegType == -2) || ((SegType == -1) && (EvalResult.AddrSpaceMask & (1 << SegIO))))
  {
    if (ChkRange(H32, 0x80, 0xff))
    {
      SaveAdrRelocs(RelocTypeB8, 0);
      AdrMode = ModDir8;
      AdrVals[0] = H32 & 0xff;
      AdrCnt = 1;
    }
  }

  else
  {
    if (SegType >= 0)
      H32 += ((LongWord)SegType) << 16;
    if (FirstFlag)
      H32 &= ((MomCPU < CPU80251) || ((Mask & ModDir16) == 0)) ? 0xff : 0xffff;

    if (((H32 < 128) || ((H32 < 256) && (MomCPU < CPU80251))) && ((Mask & MModDir8) != 0))
    {
      if (MomCPU < CPU80251)
        ChkSpace(SegData, EvalResult.AddrSpaceMask);
      SaveAdrRelocs(RelocTypeB8, 0);
      AdrMode = ModDir8;
      AdrVals[0] = H32 &0xff;
      AdrCnt = 1;
    }
    else if ((MomCPU < CPU80251) || (H32 > 0xffff)) WrError(ErrNum_AdrOverflow);
    else
    {
      AdrMode = ModDir16;
      AdrCnt = 2;
      AdrVals[1] = H32 & 0xff;
      AdrVals[0] = (H32 >> 8) & 0xff;
    }
  }

chk:
  if ((AdrMode != ModNone) && ((Mask & (1 << AdrMode)) == 0))
  {
    if (ExtMask & (1 << AdrMode))
      (void)ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported);
    else
      WrError(ErrNum_InvAddrMode);
    AdrCnt = 0;
    AdrMode = ModNone;
  }
}

static void DissectBit_251(char *pDest, size_t DestSize, LargeWord Inp)
{
  as_snprintf(pDest, DestSize, "%~02.*u%s.%u",
              ListRadixBase, (unsigned)(Inp & 0xff), GetIntConstIntelSuffix(ListRadixBase),
              (unsigned)(Inp >> 24));
}

static ShortInt DecodeBitAdr(tStrComp *pArg, LongInt *Erg, Boolean MayShorten)
{
  tEvalResult EvalResult;
  char *pPos, Save = '\0';
  tStrComp RegPart, BitPart;

  pPos = RQuotPos(pArg->str.p_str, '.');
  if (pPos)
    Save = StrCompSplitRef(&RegPart, &BitPart, pArg, pPos);
  if (MomCPU < CPU80251)
  {
    if (!pPos)
    {
      *Erg = EvalStrIntExpressionWithResult(pArg, UInt8, &EvalResult);
      if (EvalResult.OK)
      {
        ChkSpace(SegBData, EvalResult.AddrSpaceMask);
        return ModBit51;
      }
      else
        return ModNone;
    }
    else
    {
      *Erg = EvalStrIntExpressionWithResult(&RegPart, UInt8, &EvalResult);
      if (mFirstPassUnknown(EvalResult.Flags))
        *Erg = 0x20;
      *pPos = Save;
      if (!EvalResult.OK) return ModNone;
      else
      {
        ChkSpace(SegData, EvalResult.AddrSpaceMask);
        Save = EvalStrIntExpressionWithResult(&BitPart, UInt3, &EvalResult);
        if (!EvalResult.OK) return ModNone;
        else
        {
          if (*Erg > 0x7f)
          {
            if ((*Erg) & 7)
              WrError(ErrNum_NotBitAddressable);
          }
          else
          {
            if (((*Erg) & 0xe0) != 0x20)
              WrError(ErrNum_NotBitAddressable);
            *Erg = (*Erg - 0x20) << 3;
          }
          *Erg += Save;
          return ModBit51;
        }
      }
    }
  }
  else
  {
    if (!pPos)
    {
      static const LongWord ValidBits = 0x070000fful;

      *Erg = EvalStrIntExpressionWithResult(pArg, Int32, &EvalResult);
      if (mFirstPassUnknown(EvalResult.Flags))
        *Erg &= ValidBits;
      if (*Erg & ~ValidBits)
      {
        WrError(ErrNum_InvBitPos);
        EvalResult.OK = False;
      }
    }
    else
    {
      DecodeAdr(&RegPart, MModDir8);
      *pPos = Save;
      if (AdrMode == ModNone)
        EvalResult.OK = False;
      else
      {
        *Erg = EvalStrIntExpressionWithResult(&BitPart, UInt3, &EvalResult) << 24;
        if (EvalResult.OK)
          (*Erg) += AdrVals[0];
      }
    }
    if (!EvalResult.OK)
      return ModNone;
    else if (MayShorten)
    {
      if (((*Erg) & 0x87) == 0x80)
      {
        *Erg = ((*Erg) & 0xf8) + ((*Erg) >> 24);
        return ModBit51;
      }
      else if (((*Erg) & 0xf0) == 0x20)
      {
        *Erg = (((*Erg) & 0x0f) << 3) + ((*Erg) >> 24);
        return ModBit51;
      }
      else
        return ModBit251;
    }
    else
      return ModBit251;
  }
}

static Boolean Chk504(LongInt Adr)
{
  return ((MomCPU == CPU80504) && ((Adr & 0x7ff) == 0x7fe));
}

static Boolean NeedsPrefix(Word Opcode)
{
  return (((Opcode&0x0f) >= 6) && ((SrcMode != 0) != ((Hi(Opcode) != 0) != 0)));
}

static void PutCode(Word Opcode)
{
  if (((Opcode&0x0f) < 6) || ((SrcMode != 0) != ((Hi(Opcode) == 0) != 0)))
  {
    BAsmCode[0] = Lo(Opcode);
    CodeLen = 1;
  }
  else
  {
    BAsmCode[0] = 0xa5;
    BAsmCode[1] = Lo(Opcode);
    CodeLen = 2;
  }
}

static Boolean IsCarry(const char *pArg)
{
  return (!as_strcasecmp(pArg, "C")) || (!as_strcasecmp(pArg, "CY"));
}

/*-------------------------------------------------------------------------*/
/* Einzelfaelle */

static void DecodeMOV(Word Index)
{
  LongInt AdrLong;
  Byte HSize, HReg;
  Integer AdrInt;
  UNUSED(Index);

  if (!ChkArgCnt(2, 2));
  else if (IsCarry(ArgStr[1].str.p_str))
  {
    switch (DecodeBitAdr(&ArgStr[2], &AdrLong, True))
    {
      case ModBit51:
        PutCode(0xa2);
        BAsmCode[CodeLen] = AdrLong & 0xff;
        CodeLen++;
        break;
      case ModBit251:
        PutCode(0x1a9);
        BAsmCode[CodeLen  ] = 0xa0 + (AdrLong >> 24);
        BAsmCode[CodeLen + 1] = AdrLong & 0xff;
        CodeLen+=2;
        break;
    }
  }
  else if ((!as_strcasecmp(ArgStr[2].str.p_str, "C")) || (!as_strcasecmp(ArgStr[2].str.p_str, "CY")))
  {
    switch (DecodeBitAdr(&ArgStr[1], &AdrLong, True))
    {
      case ModBit51:
        PutCode(0x92);
        BAsmCode[CodeLen] = AdrLong & 0xff;
        CodeLen++;
        break;
      case ModBit251:
        PutCode(0x1a9);
        BAsmCode[CodeLen] = 0x90 + (AdrLong >> 24);
        BAsmCode[CodeLen + 1] = AdrLong & 0xff;
        CodeLen+=2;
        break;
    }
  }
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "DPTR"))
  {
    SetOpSize((MomCPU == CPU80C390) ? 3 : 1);
    DecodeAdr(&ArgStr[2], MModImm);
    switch (AdrMode)
    {
      case ModImm:
        PutCode(0x90);
        memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
        TransferAdrRelocs(CodeLen);
        CodeLen += AdrCnt;
        break;
    }
  }
  else
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModIReg8 | MModIReg | MModInd | MModDir8 | MModDir16);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModIReg | MModInd | MModDir8 | MModDir16 | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            if ((AdrPart < 8) && (!SrcMode))
              PutCode(0xe8 + AdrPart);
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x17c);
              BAsmCode[CodeLen++] = (AccReg << 4) + AdrPart;
            }
            break;
          case ModIReg8:
            PutCode(0xe6 + AdrPart);
            break;
          case ModIReg:
            PutCode(0x17e);
            BAsmCode[CodeLen++] = (AdrPart << 4) + 0x09 + AdrSize;
            BAsmCode[CodeLen++] = (AccReg << 4);
            break;
          case ModInd:
            PutCode(0x109 + (AdrSize << 4));
            BAsmCode[CodeLen++] = (AccReg << 4) + AdrPart;
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModDir8:
            PutCode(0xe5);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModDir16:
            PutCode(0x17e);
            BAsmCode[CodeLen++] = (AccReg << 4) + 0x03;
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModImm:
            PutCode(0x74);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
      case ModReg:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModIReg | MModInd | MModDir8 | MModDir16 | MModImm | MModImmEx);
        switch (AdrMode)
        {
          case ModReg:
            if ((OpSize == 0) && (AdrPart == AccReg) && (HReg < 8))
              PutCode(0xf8 + HReg);
            else if ((OpSize == 0) && (HReg == AccReg) && (AdrPart < 8))
              PutCode(0xe8 + AdrPart);
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x17c + OpSize);
              if (OpSize == 2)
                BAsmCode[CodeLen - 1]++;
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            }
            break;
          case ModIReg8:
            if ((OpSize != 0) || (HReg != AccReg)) WrError(ErrNum_InvAddrMode);
            else
              PutCode(0xe6 + AdrPart);
            break;
          case ModIReg:
            if (OpSize == 0)
            {
              PutCode(0x17e);
              BAsmCode[CodeLen++] = (AdrPart << 4) + 0x09 + AdrSize;
              BAsmCode[CodeLen++] = HReg << 4;
            }
            else if (OpSize == 1)
            {
              PutCode(0x10b);
              BAsmCode[CodeLen++] = (AdrPart << 4) + 0x08 + AdrSize;
              BAsmCode[CodeLen++] = HReg << 4;
            }
            else
              WrError(ErrNum_InvAddrMode);
            break;
          case ModInd:
            if (OpSize == 2) WrError(ErrNum_InvAddrMode);
            else
            {
              PutCode(0x109 + (AdrSize << 4) + (OpSize << 6));
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
            }
            break;
          case ModDir8:
            if ((OpSize == 0) && (HReg == AccReg))
            {
              PutCode(0xe5);
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            else if ((OpSize == 0) && (HReg < 8) && (!SrcMode))
            {
              PutCode(0xa8 + HReg);
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x17e);
              BAsmCode[CodeLen++] = 0x01 + (HReg << 4) + (OpSize << 2);
              if (OpSize == 2)
                BAsmCode[CodeLen - 1] += 4;
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            break;
          case ModDir16:
            PutCode(0x17e);
            BAsmCode[CodeLen++] = 0x03 + (HReg << 4) + (OpSize << 2);
            if (OpSize == 2)
              BAsmCode[CodeLen - 1] += 4;
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModImm:
            if ((OpSize == 0) && (HReg == AccReg))
            {
              PutCode(0x74);
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            else if ((OpSize == 0) && (HReg < 8) && (!SrcMode))
            {
              PutCode(0x78 + HReg);
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x17e);
              BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2);
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
            }
            break;
          case ModImmEx:
            PutCode(0x17e);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = 0x0c + (HReg << 4);
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
        }
        break;
      case ModIReg8:
        SetOpSize(0); HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModAcc | MModDir8 | MModImm);
        switch (AdrMode)
        {
          case ModAcc:
            PutCode(0xf6 + HReg);
            break;
          case ModDir8:
            PutCode(0xa6 + HReg);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModImm:
            PutCode(0x76 + HReg);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
      case ModIReg:
        HReg = AdrPart; HSize = AdrSize;
        DecodeAdr(&ArgStr[2], MModReg);
        switch (AdrMode)
        {
          case ModReg:
            if (OpSize == 0)
            {
              PutCode(0x17a);
              BAsmCode[CodeLen++] = (HReg << 4) + 0x09 + HSize;
              BAsmCode[CodeLen++] = AdrPart << 4;
            }
            else if (OpSize == 1)
            {
              PutCode(0x11b);
              BAsmCode[CodeLen++] = (HReg << 4) + 0x08 + HSize;
              BAsmCode[CodeLen++] = AdrPart << 4;
            }
            else
              WrError(ErrNum_InvAddrMode);
        }
        break;
      case ModInd:
        HReg = AdrPart; HSize = AdrSize;
        AdrInt = (((Word)AdrVals[0]) << 8) + AdrVals[1];
        DecodeAdr(&ArgStr[2], MModReg);
        switch (AdrMode)
        {
          case ModReg:
            if (OpSize == 2) WrError(ErrNum_InvAddrMode);
            else
            {
              PutCode(0x119 + (HSize << 4) + (OpSize << 6));
              BAsmCode[CodeLen++] = (AdrPart << 4) + HReg;
              BAsmCode[CodeLen++] = Hi(AdrInt);
              BAsmCode[CodeLen++] = Lo(AdrInt);
            }
        }
        break;
      case ModDir8:
        MinOneIs0 = True;
        HReg = AdrVals[0];
        SaveBackupAdrRelocs();
        DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModDir8 | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            if ((OpSize == 0) && (AdrPart == AccReg))
            {
              PutCode(0xf5);
              TransferBackupAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = HReg;
            }
            else if ((OpSize == 0) && (AdrPart < 8) && (!SrcMode))
            {
              PutCode(0x88 + AdrPart);
              TransferBackupAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = HReg;
            }
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x17a);
              BAsmCode[CodeLen++] = 0x01 + (AdrPart << 4) + (OpSize << 2);
              if (OpSize == 2)
                BAsmCode[CodeLen - 1] += 4;
              BAsmCode[CodeLen++] = HReg;
            }
            break;
          case ModIReg8:
            PutCode(0x86 + AdrPart);
            TransferBackupAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = HReg;
            break;
          case ModDir8:
            PutCode(0x85);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            TransferBackupAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = HReg;
            break;
          case ModImm:
            PutCode(0x75);
            TransferBackupAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = HReg;
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
      case ModDir16:
        AdrInt = (((Word)AdrVals[0]) << 8) + AdrVals[1];
        DecodeAdr(&ArgStr[2], MModReg);
        switch (AdrMode)
        {
          case ModReg:
            PutCode(0x17a);
            BAsmCode[CodeLen++] = 0x03 + (AdrPart << 4) + (OpSize << 2);
            if (OpSize == 2) BAsmCode[CodeLen - 1] += 4;
            BAsmCode[CodeLen++] = Hi(AdrInt);
            BAsmCode[CodeLen++] = Lo(AdrInt);
            break;
        }
        break;
    }
  }
}

static void DecodeLogic(Word Index)
{
  Byte HReg;
  LongInt AdrLong;
  int z;

  /* Index: ORL=0 ANL=1 XRL=2 */

  if (!ChkArgCnt(2, 2));
  else if (IsCarry(ArgStr[1].str.p_str))
  {
    if (Index == 2) WrError(ErrNum_InvAddrMode);
    else
    {
      Boolean InvFlag;
      ShortInt Result;

      HReg = Index << 4;
      InvFlag = *ArgStr[2].str.p_str == '/';
      if (InvFlag)
      {
        tStrComp Comp;

        StrCompRefRight(&Comp, &ArgStr[2], 1);
        Result = DecodeBitAdr(&Comp, &AdrLong, True);
      }
      else
        Result = DecodeBitAdr(&ArgStr[2], &AdrLong, True);
      switch (Result)
      {
        case ModBit51:
          PutCode((InvFlag) ? 0xa0 + HReg : 0x72 + HReg);
          BAsmCode[CodeLen++] = AdrLong & 0xff;
          break;
        case ModBit251:
          PutCode(0x1a9);
          BAsmCode[CodeLen++] = ((InvFlag) ? 0xe0 : 0x70) + HReg + (AdrLong >> 24);
          BAsmCode[CodeLen++] = AdrLong & 0xff;
          break;
      }
    }
  }
  else
  {
    z = (Index << 4) + 0x40;
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModDir8);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModIReg | MModDir8 | MModDir16 | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            if ((AdrPart < 8) && (!SrcMode)) PutCode(z + 8 + AdrPart);
            else
            {
              PutCode(z + 0x10c);
              BAsmCode[CodeLen++] = AdrPart + (AccReg << 4);
            }
            break;
          case ModIReg8:
            PutCode(z + 6 + AdrPart);
            break;
          case ModIReg:
            PutCode(z + 0x10e);
            BAsmCode[CodeLen++] = 0x09 + AdrSize + (AdrPart << 4);
            BAsmCode[CodeLen++] = AccReg << 4;
            break;
          case ModDir8:
            PutCode(z + 0x05);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModDir16:
            PutCode(0x10e + z);
            BAsmCode[CodeLen++] = 0x03 + (AccReg << 4);
            memcpy(BAsmCode+CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModImm:
            PutCode(z + 0x04);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
      case ModReg:
        if (MomCPU < CPU80251) WrError(ErrNum_InvAddrMode);
        else
        {
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModIReg | MModDir8 | MModDir16 | MModImm);
          switch (AdrMode)
          {
            case ModReg:
              if (OpSize == 2) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(z + 0x10c + OpSize);
                BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              }
              break;
            case ModIReg8:
              if ((OpSize != 0) || (HReg != AccReg)) WrError(ErrNum_InvAddrMode);
              else
                PutCode(z + 0x06 + AdrPart);
              break;
            case ModIReg:
              if (OpSize != 0) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(0x10e + z);
                BAsmCode[CodeLen++] = 0x09 + AdrSize + (AdrPart << 4);
                BAsmCode[CodeLen++] = HReg << 4;
              }
              break;
            case ModDir8:
              if ((OpSize == 0) && (HReg == AccReg))
              {
                PutCode(0x05 + z);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
              }
              else if (OpSize == 2) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(0x10e + z);
                BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2) + 1;
                BAsmCode[CodeLen++] = AdrVals[0];
              }
              break;
            case ModDir16:
              if (OpSize == 2) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(0x10e + z);
                BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2) + 3;
                memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
                CodeLen += AdrCnt;
              }
              break;
            case ModImm:
              if ((OpSize == 0) && (HReg == AccReg))
              {
                PutCode(0x04 + z);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
              }
              else if (OpSize == 2) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(0x10e + z);
                BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2);
                TransferAdrRelocs(CodeLen);
                memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
                CodeLen += AdrCnt;
              }
              break;
          }
        }
        break;
      case ModDir8:
        HReg = AdrVals[0];
        SaveBackupAdrRelocs();
        SetOpSize(0);
        DecodeAdr(&ArgStr[2], MModAcc | MModImm);
        switch (AdrMode)
        {
          case ModAcc:
            PutCode(z + 0x02);
            TransferBackupAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = HReg;
            break;
          case ModImm:
            PutCode(z + 0x03);
            TransferBackupAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = HReg;
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc);
    switch (AdrMode)
    {
      case ModAcc:
        if (!as_strcasecmp(ArgStr[2].str.p_str, "@A+DPTR"))
          PutCode(0x93);
        else if (!as_strcasecmp(ArgStr[2].str.p_str, "@A+PC"))
          PutCode(0x83);
        else
          WrError(ErrNum_InvAddrMode);
        break;
    }
  }
}

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

  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80251))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        if (OpSize != 2) WrError(ErrNum_InvAddrMode);
        else
        {
          HReg = AdrPart;
          OpSize--;
          DecodeAdr(&ArgStr[2], MModImm);
          switch (AdrMode)
          {
            case ModImm:
              PutCode(0x17a);
              BAsmCode[CodeLen++] = 0x0c + (HReg << 4);
              TransferAdrRelocs(CodeLen);
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
              break;
          }
        }
        break;
    }
  }
}

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

  z = Ord(Memo("MOVS")) << 4;
  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80251))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        if (OpSize != 1) WrError(ErrNum_InvAddrMode);
        else
        {
          HReg = AdrPart;
          OpSize--;
          DecodeAdr(&ArgStr[2], MModReg);
          switch (AdrMode)
          {
            case ModReg:
             PutCode(0x10a + z);
             BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
             break;
          }
        }
        break;
    }
  }
}

static void DecodeMOVX(Word Index)
{
  int z;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    z = 0;
    if ((!as_strcasecmp(ArgStr[2].str.p_str, "A")) || ((MomCPU >= CPU80251) && (!as_strcasecmp(ArgStr[2].str.p_str, "R11"))))
    {
      z = 0x10;
      strcpy(ArgStr[2].str.p_str, ArgStr[1].str.p_str);
      strmaxcpy(ArgStr[1].str.p_str, "A", STRINGSIZE);
    }
    if ((as_strcasecmp(ArgStr[1].str.p_str, "A")) && ((MomCPU < CPU80251) || (!as_strcasecmp(ArgStr[2].str.p_str, "R11")))) WrError(ErrNum_InvAddrMode);
    else if (!as_strcasecmp(ArgStr[2].str.p_str, "@DPTR"))
      PutCode(0xe0 + z);
    else
    {
      DecodeAdr(&ArgStr[2], MModIReg8);
      switch (AdrMode)
      {
        case ModIReg8:
          PutCode(0xe2 + AdrPart + z);
          break;
      }
    }
  }
}

static void DecodeStack(Word Index)
{
  int z;

  /* Index: PUSH=0 POP=1 PUSHW=2 */

  z = (Index & 1) << 4;
  if (ChkArgCnt(1, 1))
  {
    if (*ArgStr[1].str.p_str == '#')
      SetOpSize(Ord(Index == 2));
    DecodeAdr(&ArgStr[1], MModDir8 | MModReg | ((z == 0x10) ? 0 : MModImm));
    switch (AdrMode)
    {
      case ModDir8:
        PutCode(0xc0 + z);
        TransferAdrRelocs(CodeLen);
        BAsmCode[CodeLen++] = AdrVals[0];
        break;
      case ModReg:
        if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
        {
          PutCode(0x1ca + z);
          BAsmCode[CodeLen++] = 0x08 + (AdrPart << 4) + OpSize + (Ord(OpSize == 2));
        }
        break;
      case ModImm:
        if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
        {
          PutCode(0x1ca);
          BAsmCode[CodeLen++] = 0x02 + (OpSize << 2);
          TransferAdrRelocs(CodeLen);
          memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
          CodeLen += AdrCnt;
        }
        break;
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModIReg8 | MModDir8);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModDir8);
        switch (AdrMode)
        {
          case ModReg:
            if (AdrPart > 7) WrError(ErrNum_InvAddrMode);
            else
              PutCode(0xc8 + AdrPart);
            break;
          case ModIReg8:
            PutCode(0xc6 + AdrPart);
            break;
          case ModDir8:
            PutCode(0xc5);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
      case ModReg:
        if ((OpSize != 0) || (AdrPart > 7)) WrError(ErrNum_InvAddrMode);
        else
        {
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModAcc);
          switch (AdrMode)
          {
            case ModAcc:
              PutCode(0xc8 + HReg);
              break;
          }
        }
        break;
      case ModIReg8:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModAcc);
        switch (AdrMode)
        {
          case ModAcc:
            PutCode(0xc6 + HReg);
            break;
        }
        break;
      case ModDir8:
        HReg = AdrVals[0]; SaveBackupAdrRelocs();
        DecodeAdr(&ArgStr[2], MModAcc);
        switch (AdrMode)
        {
          case ModAcc:
            PutCode(0xc5);
            TransferBackupAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = HReg;
            break;
        }
        break;
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModIReg8);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModIReg8);
        switch (AdrMode)
        {
          case ModIReg8:
            PutCode(0xd6 + AdrPart);
            break;
        }
        break;
      case ModIReg8:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModAcc);
        switch (AdrMode)
        {
          case ModAcc:
            PutCode(0xd6 + HReg);
            break;
        }
        break;
    }
  }
}

#define RelocTypeABranch11 (11 | RelocFlagBig | RelocFlagPage | (5 << 8) | (3 << 12)) | (0 << 16)
#define RelocTypeABranch19 (19 | RelocFlagBig | RelocFlagPage | (5 << 8) | (3 << 12)) | (0 << 16)

static void DecodeABranch(Word Index)
{
  /* Index: AJMP = 0 ACALL = 1 */

  if (ChkArgCnt(1, 1))
  {
    tEvalResult EvalResult;
    LongInt AdrLong = EvalStrIntExpressionWithResult(&ArgStr[1], Int24, &EvalResult);

    if (EvalResult.OK)
    {
      ChkSpace(SegCode, EvalResult.AddrSpaceMask);
      if (MomCPU == CPU80C390)
      {
        if (ChkSamePage(EProgCounter() + 3, AdrLong, 19, EvalResult.Flags))
        {
          PutCode(0x01 + (Index << 4) + (((AdrLong >> 16) & 7) << 5));
          BAsmCode[CodeLen++] = Hi(AdrLong);
          BAsmCode[CodeLen++] = Lo(AdrLong);
          TransferRelocs(ProgCounter() - 3, RelocTypeABranch19);
        }
      }
      else
      {
        if (!ChkSamePage(EProgCounter(), AdrLong, 11, EvalResult.Flags));
        else if (Chk504(EProgCounter())) WrError(ErrNum_NotOnThisAddress);
        else
        {
          PutCode(0x01 + (Index << 4) + ((Hi(AdrLong) & 7) << 5));
          BAsmCode[CodeLen++] = Lo(AdrLong);
          TransferRelocs(ProgCounter() - 2, RelocTypeABranch11);
        }
      }
    }
  }
}

static void DecodeLBranch(Word Index)
{
  /* Index: LJMP=0 LCALL=1 */

  if (!ChkArgCnt(1, 1));
  else if (!ChkMinCPU(CPU8051));
  else if (*ArgStr[1].str.p_str == '@')
  {
    DecodeAdr(&ArgStr[1], MModIReg);
    switch (AdrMode)
    {
      case ModIReg:
        if (AdrSize != 0) WrError(ErrNum_InvAddrMode);
        else
        {
          PutCode(0x189 + (Index << 4));
          BAsmCode[CodeLen++] = 0x04 + (AdrPart << 4);
        }
        break;
    }
  }
  else
  {
    tEvalResult EvalResult;
    LongInt AdrLong = EvalStrIntExpressionWithResult(&ArgStr[1], (MomCPU < CPU80C390) ? Int16 : Int24, &EvalResult);

    if (EvalResult.OK)
    {
      ChkSpace(SegCode, EvalResult.AddrSpaceMask);
      if (MomCPU == CPU80C390)
      {
        PutCode(0x02 + (Index << 4));
        BAsmCode[CodeLen++] = (AdrLong >> 16) & 0xff;
        BAsmCode[CodeLen++] = (AdrLong >> 8) & 0xff;
        BAsmCode[CodeLen++] = AdrLong & 0xff;
        TransferRelocs(ProgCounter() + 1, RelocTypeB24);
      }
      else
      {
        if ((MomCPU >= CPU80251) && !ChkSamePage(EProgCounter() + 3, AdrLong, 16, EvalResult.Flags));
        else
        {
          PutCode(0x02 + (Index << 4));
          BAsmCode[CodeLen++] = (AdrLong >> 8) & 0xff;
          BAsmCode[CodeLen++] = AdrLong & 0xff;
          TransferRelocs(ProgCounter() + 1, RelocTypeB16);
        }
      }
    }
  }
}

static void DecodeEBranch(Word Index)
{
  /* Index: AJMP=0 ACALL=1 */

  if (!ChkArgCnt(1, 1));
  else if (!ChkMinCPU(CPU80251));
  else if (*ArgStr[1].str.p_str == '@')
  {
    DecodeAdr(&ArgStr[1], MModIReg);
    switch (AdrMode)
    {
      case ModIReg:
        if (AdrSize != 2) WrError(ErrNum_InvAddrMode);
        else
        {
          PutCode(0x189 + (Index << 4));
          BAsmCode[CodeLen++] = 0x08 + (AdrPart << 4);
        }
        break;
    }
  }
  else
  {
    tEvalResult EvalResult;
    LongInt AdrLong = EvalStrIntExpressionWithResult(&ArgStr[1], UInt24, &EvalResult);

    if (EvalResult.OK)
    {
      ChkSpace(SegCode, EvalResult.AddrSpaceMask);
      PutCode(0x18a + (Index << 4));
      BAsmCode[CodeLen++] = (AdrLong >> 16) & 0xff;
      BAsmCode[CodeLen++] = (AdrLong >>  8) & 0xff;
      BAsmCode[CodeLen++] =  AdrLong        & 0xff;
    }
  }
}

static void DecodeJMP(Word Index)
{
  LongInt AdrLong, Dist;
  Boolean OK;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "@A+DPTR"))
    PutCode(0x73);
  else if (*ArgStr[1].str.p_str == '@')
  {
    DecodeAdr(&ArgStr[1], MModIReg);
    switch (AdrMode)
    {
      case ModIReg:
        PutCode(0x189);
        BAsmCode[CodeLen++] = 0x04 + (AdrSize << 1) + (AdrPart << 4);
        break;
    }
  }
  else
  {
    AdrLong = EvalStrIntExpression(&ArgStr[1], UInt24, &OK);
    if (OK)
    {
      Dist = AdrLong - (EProgCounter() + 2);
      if ((Dist<=127) && (Dist >= -128))
      {
        PutCode(0x80);
        BAsmCode[CodeLen++] = Dist & 0xff;
      }
      else if ((!Chk504(EProgCounter())) && ((AdrLong >> 11) == ((((long)EProgCounter()) + 2) >> 11)))
      {
        PutCode(0x01 + ((Hi(AdrLong) & 7) << 5));
        BAsmCode[CodeLen++] = Lo(AdrLong);
      }
      else if (MomCPU < CPU8051) WrError(ErrNum_JmpTargOnDiffPage);
      else if (((((long)EProgCounter()) + 3) >> 16) == (AdrLong >> 16))
      {
        PutCode(0x02);
        BAsmCode[CodeLen++] = Hi(AdrLong);
        BAsmCode[CodeLen++] = Lo(AdrLong);
      }
      else if (MomCPU < CPU80251) WrError(ErrNum_JmpTargOnDiffPage);
      else
      {
        PutCode(0x18a);
        BAsmCode[CodeLen++] = (AdrLong >> 16) & 0xff;
        BAsmCode[CodeLen++] = (AdrLong >>  8) & 0xff;
        BAsmCode[CodeLen++] =  AdrLong        & 0xff;
      }
    }
  }
}

static void DecodeCALL(Word Index)
{
  LongInt AdrLong;
  Boolean OK;
  tSymbolFlags Flags;

  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str == '@')
  {
    DecodeAdr(&ArgStr[1], MModIReg);
    switch (AdrMode)
    {
      case ModIReg:
        PutCode(0x199);
        BAsmCode[CodeLen++] = 0x04 + (AdrSize << 1) + (AdrPart << 4);
        break;
    }
  }
  else
  {
    AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt24, &OK, &Flags);
    if (OK)
    {
      if ((!Chk504(EProgCounter())) && ((AdrLong >> 11) == ((((long)EProgCounter()) + 2) >> 11)))
      {
        PutCode(0x11 + ((Hi(AdrLong) & 7) << 5));
        BAsmCode[CodeLen++] = Lo(AdrLong);
      }
      else if (MomCPU < CPU8051) WrError(ErrNum_JmpTargOnDiffPage);
      else if (ChkSamePage(AdrLong, EProgCounter() + 3, 16, Flags))
      {
        PutCode(0x12);
        BAsmCode[CodeLen++] = Hi(AdrLong);
        BAsmCode[CodeLen++] = Lo(AdrLong);
      }
    }
  }
}

static void DecodeDJNZ(Word Index)
{
  LongInt AdrLong;
  Boolean OK;
  tSymbolFlags Flags;

  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt24, &OK, &Flags);
    SubPCRefReloc();
    if (OK)
    {
      DecodeAdr(&ArgStr[1], MModReg | MModDir8);
      switch (AdrMode)
      {
        case ModReg:
          if ((OpSize != 0) || (AdrPart > 7)) WrError(ErrNum_InvAddrMode);
          else
          {
            AdrLong -= EProgCounter() + 2 + Ord(NeedsPrefix(0xd8 + AdrPart));
            if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
            else
            {
              PutCode(0xd8 + AdrPart);
              BAsmCode[CodeLen++] = AdrLong & 0xff;
            }
          }
          break;
        case ModDir8:
          AdrLong -= EProgCounter() + 3 + Ord(NeedsPrefix(0xd5));
          if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
          else
          {
            PutCode(0xd5);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            BAsmCode[CodeLen++] = Lo(AdrLong);
          }
          break;
      }
    }
  }
}

static void DecodeCJNE(Word Index)
{
  LongInt AdrLong;
  Boolean OK;
  tSymbolFlags Flags;
  Byte HReg;
  UNUSED(Index);

  if (ChkArgCnt(3, 3))
  {
    AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[3], UInt24, &OK, &Flags);
    SubPCRefReloc();
    if (OK)
    {
      DecodeAdr(&ArgStr[1], MModAcc | MModIReg8 | MModReg);
      switch (AdrMode)
      {
        case ModAcc:
          DecodeAdr(&ArgStr[2], MModDir8 | MModImm);
          switch (AdrMode)
          {
            case ModDir8:
              AdrLong -= EProgCounter() + 3 + Ord(NeedsPrefix(0xb5));
              if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
              else
              {
                PutCode(0xb5);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
                BAsmCode[CodeLen++] = AdrLong & 0xff;
              }
              break;
            case ModImm:
              AdrLong -= EProgCounter() + 3 + Ord(NeedsPrefix(0xb5));
              if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
              else
              {
                PutCode(0xb4);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
                BAsmCode[CodeLen++] = AdrLong & 0xff;
              }
              break;
          }
          break;
        case ModReg:
          if ((OpSize != 0) || (AdrPart > 7)) WrError(ErrNum_InvAddrMode);
          else
          {
            HReg = AdrPart;
            DecodeAdr(&ArgStr[2], MModImm);
            switch (AdrMode)
            {
              case ModImm:
                AdrLong -= EProgCounter() + 3 + Ord(NeedsPrefix(0xb8 + HReg));
                if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
                else
                {
                  PutCode(0xb8 + HReg);
                  TransferAdrRelocs(CodeLen);
                  BAsmCode[CodeLen++] = AdrVals[0];
                  BAsmCode[CodeLen++] = AdrLong & 0xff;
                }
                break;
            }
          }
          break;
        case ModIReg8:
          HReg = AdrPart; SetOpSize(0);
          DecodeAdr(&ArgStr[2], MModImm);
          switch (AdrMode)
          {
            case ModImm:
              AdrLong -= EProgCounter() + 3 + Ord(NeedsPrefix(0xb6 + HReg));
              if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
              else
              {
                PutCode(0xb6 + HReg);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
                BAsmCode[CodeLen++] = AdrLong & 0xff;
              }
              break;
          }
          break;
      }
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModReg);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModImm | MModDir8 | MModDir16 | MModIReg8 | MModIReg | MModReg);
        switch (AdrMode)
        {
          case ModImm:
            PutCode(0x24);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModDir8:
            PutCode(0x25);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModDir16:
            PutCode(0x12e);
            BAsmCode[CodeLen++] = (AccReg << 4) + 3;
            memcpy(BAsmCode + CodeLen, AdrVals, 2);
            CodeLen += 2;
            break;
          case ModIReg8:
            PutCode(0x26 + AdrPart);
            break;
          case ModIReg:
            PutCode(0x12e);
            BAsmCode[CodeLen++] = 0x09 + AdrSize + (AdrPart << 4);
            BAsmCode[CodeLen++] = AccReg << 4;
            break;
          case ModReg:
            if ((AdrPart < 8) && (!SrcMode)) PutCode(0x28 + AdrPart);
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x12c);
              BAsmCode[CodeLen++] = AdrPart + (AccReg << 4);
            }
            break;
        }
        break;
      case ModReg:
        if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
        {
          HReg = AdrPart;
          DecodeAdr(&ArgStr[2], MModImm | MModReg | MModDir8 | MModDir16 | MModIReg8 | MModIReg);
          switch (AdrMode)
          {
            case ModImm:
              if ((OpSize == 0) && (HReg == AccReg))
              {
                PutCode(0x24);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
              }
              else
              {
                PutCode(0x12e);
                BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2);
                memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
                CodeLen += AdrCnt;
              }
              break;
            case ModReg:
              PutCode(0x12c + OpSize);
              if (OpSize == 2) BAsmCode[CodeLen - 1]++;
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
              break;
            case ModDir8:
              if (OpSize == 2) WrError(ErrNum_InvAddrMode);
              else if ((OpSize == 0) && (HReg == AccReg))
              {
                PutCode(0x25);
                TransferAdrRelocs(CodeLen);
                BAsmCode[CodeLen++] = AdrVals[0];
              }
              else
              {
                PutCode(0x12e);
                BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2) + 1;
                BAsmCode[CodeLen++] = AdrVals[0];
              }
              break;
            case ModDir16:
              if (OpSize == 2) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(0x12e);
                BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2) + 3;
                memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
                CodeLen += AdrCnt;
              }
              break;
            case ModIReg8:
              if ((OpSize != 0) || (HReg != AccReg)) WrError(ErrNum_InvAddrMode);
              else PutCode(0x26 + AdrPart);
              break;
            case ModIReg:
              if (OpSize != 0) WrError(ErrNum_InvAddrMode);
              else
              {
                PutCode(0x12e);
                BAsmCode[CodeLen++] = 0x09 + AdrSize + (AdrPart << 4);
                BAsmCode[CodeLen++] = HReg << 4;
              }
              break;
          }
        }
        break;
    }
  }
}

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

  /* Index: SUB=0 CMP=1 */

  z = 0x90 + (Index << 5);
  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80251))
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModImm | MModReg | MModDir8 | MModDir16 | MModIReg | (Index ? MModImmEx : 0));
        switch (AdrMode)
        {
          case ModImm:
            PutCode(0x10e + z);
            BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2);
            TransferAdrRelocs(CodeLen);
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModImmEx:
            PutCode(0x10e + z);
            BAsmCode[CodeLen++] = (HReg << 4) + 0x0c;
            TransferAdrRelocs(CodeLen);
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModReg:
            PutCode(0x10c + z + OpSize);
            if (OpSize == 2)
              BAsmCode[CodeLen - 1]++;
            BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            break;
          case ModDir8:
            if (OpSize == 2) WrError(ErrNum_InvAddrMode);
            else
            {
              PutCode(0x10e + z);
              BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2) + 1;
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            break;
          case ModDir16:
            if (OpSize == 2) WrError(ErrNum_InvAddrMode);
            else
            {
              PutCode(0x10e + z);
              BAsmCode[CodeLen++] = (HReg << 4) + (OpSize << 2) + 3;
              memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
              CodeLen += AdrCnt;
            }
            break;
          case ModIReg:
            if (OpSize != 0) WrError(ErrNum_InvAddrMode);
            else
            {
              PutCode(0x10e + z);
              BAsmCode[CodeLen++] = 0x09 + AdrSize + (AdrPart << 4);
              BAsmCode[CodeLen++] = HReg << 4;
            }
            break;
        }
        break;
    }
  }
}

static void DecodeADDCSUBB(Word Index)
{
  Byte HReg;

  /* Index: ADDC=0 SUBB=1 */

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModAcc);
    switch (AdrMode)
    {
      case ModAcc:
        HReg = 0x30 + (Index*0x60);
        DecodeAdr(&ArgStr[2], MModReg | MModIReg8 | MModDir8 | MModImm);
        switch (AdrMode)
        {
          case ModReg:
            if (AdrPart > 7) WrError(ErrNum_InvAddrMode);
            else
              PutCode(HReg + 0x08 + AdrPart);
            break;
          case ModIReg8:
            PutCode(HReg + 0x06 + AdrPart);
            break;
          case ModDir8:
            PutCode(HReg + 0x05);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModImm:
            PutCode(HReg + 0x04);
            TransferAdrRelocs(CodeLen);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
        }
        break;
    }
  }
}

static void DecodeINCDEC(Word Index)
{
  Byte HReg;
  int z;
  Boolean OK;
  tSymbolFlags Flags;

  /* Index: INC=0 DEC=1 */

  z = Index << 4;
  if (!ChkArgCnt(1, 2));
  else if ((ArgCnt == 2) && (*ArgStr[2].str.p_str != '#')) WrError(ErrNum_InvAddrMode);
  else
  {
    if (1 == ArgCnt)
    {
      HReg = 1;
      OK = True;
      Flags = eSymbolFlag_None;
    }
    else
      HReg = EvalStrIntExpressionOffsWithFlags(&ArgStr[2], 1, UInt3, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      HReg = 1;
    if (OK)
    {
      OK = True;
      if (HReg == 1)
        HReg = 0;
      else if (HReg == 2)
        HReg = 1;
      else if (HReg == 4)
        HReg = 2;
      else
        OK = False;
      if (!OK) WrError(ErrNum_OverRange);
      else if (!as_strcasecmp(ArgStr[1].str.p_str, "DPTR"))
      {
        if (Index == 1) WrError(ErrNum_InvAddrMode);
        else if (HReg != 0) WrError(ErrNum_OverRange);
        else
          PutCode(0xa3);
      }
      else
      {
        DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModDir8 | MModIReg8);
        switch (AdrMode)
        {
          case ModAcc:
            if (HReg == 0)
              PutCode(0x04 + z);
            else if (MomCPU < CPU80251) WrError(ErrNum_OverRange);
            else
            {
              PutCode(0x10b + z);
              BAsmCode[CodeLen++] = (AccReg << 4) + HReg;
            }
            break;
          case ModReg:
            if ((OpSize == 0) && (AdrPart == AccReg) && (HReg == 0))
              PutCode(0x04 + z);
            else if ((AdrPart < 8) && (OpSize == 0) && (HReg == 0) && (!SrcMode))
              PutCode(0x08 + z + AdrPart);
            else if (ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported))
            {
              PutCode(0x10b + z);
              BAsmCode[CodeLen++] = (AdrPart << 4) + (OpSize << 2) + HReg;
              if (OpSize == 2)
                BAsmCode[CodeLen - 1] += 4;
            }
            break;
          case ModDir8:
            if (HReg != 0) WrError(ErrNum_OverRange);
            else
            {
              PutCode(0x05 + z);
              TransferAdrRelocs(CodeLen);
              BAsmCode[CodeLen++] = AdrVals[0];
            }
            break;
          case ModIReg8:
            if (HReg != 0) WrError(ErrNum_OverRange);
            else
              PutCode(0x06 + z + AdrPart);
            break;
        }
      }
    }
  }
}

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

  /* Index: DIV=0 MUL=1 */

  z = Index << 5;
  if (!ChkArgCnt(1, 2));
  else if (ArgCnt == 1)
  {
    if (as_strcasecmp(ArgStr[1].str.p_str, "AB")) WrError(ErrNum_InvAddrMode);
    else
      PutCode(0x84 + z);
  }
  else
  {
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        HReg = AdrPart;
        DecodeAdr(&ArgStr[2], MModReg);
        switch (AdrMode)
        {
          case ModReg:
            if (!ChkMinCPUExt(CPU80251, ErrNum_AddrModeNotSupported));
            else if (OpSize == 2) WrError(ErrNum_InvAddrMode);
            else
            {
              PutCode(0x18c + z + OpSize);
              BAsmCode[CodeLen++] = (HReg << 4) + AdrPart;
            }
            break;
        }
        break;
    }
  }
}

static void DecodeBits(Word Index)
{
  LongInt AdrLong;
  int z;

  /* Index: CPL=0 CLR=1 SETB=2 */

  z = Index << 4;
  if (!ChkArgCnt(1, 1));
  else if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
  {
    if (Memo("SETB")) WrError(ErrNum_InvAddrMode);
    else
      PutCode(0xf4 - z);
  }
  else if (IsCarry(ArgStr[1].str.p_str))
    PutCode(0xb3 + z);
  else
    switch (DecodeBitAdr(&ArgStr[1], &AdrLong, True))
    {
      case ModBit51:
        PutCode(0xb2 + z);
        BAsmCode[CodeLen++] = AdrLong & 0xff;
        break;
      case ModBit251:
        PutCode(0x1a9);
        BAsmCode[CodeLen++] = 0xb0 + z + (AdrLong >> 24);
        BAsmCode[CodeLen++] = AdrLong & 0xff;
        break;
    }
}

static void DecodeShift(Word Index)
{
  int z;

  /* Index: SRA=0 SRL=1 SLL=3 */

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU80251))
  {
    z = Index << 4;
    DecodeAdr(&ArgStr[1], MModReg);
    switch (AdrMode)
    {
      case ModReg:
        if (OpSize == 2) WrError(ErrNum_InvAddrMode);
        else
        {
          PutCode(0x10e + z);
          BAsmCode[CodeLen++] = (AdrPart << 4) + (OpSize << 2);
        }
        break;
    }
  }
}

static void DecodeCond(Word Index)
{
  FixedOrder *FixedZ = CondOrders + Index;

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(FixedZ->MinCPU))
  {
    tEvalResult EvalResult;
    LongInt AdrLong = EvalStrIntExpressionWithResult(&ArgStr[1], UInt24, &EvalResult);

    SubPCRefReloc();
    if (EvalResult.OK)
    {
      AdrLong -= EProgCounter() + 2 + Ord(NeedsPrefix(FixedZ->Code));
      if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(EvalResult.Flags)) WrError(ErrNum_JmpDistTooBig);
      else
      {
        ChkSpace(SegCode, EvalResult.AddrSpaceMask);
        PutCode(FixedZ->Code);
        BAsmCode[CodeLen++] = AdrLong & 0xff;
      }
    }
  }
}

static void DecodeBCond(Word Index)
{
  FixedOrder *FixedZ = BCondOrders + Index;
  LongInt AdrLong, BitLong;
  tEvalResult EvalResult;

  if (ChkArgCnt(2, 2))
  {
    AdrLong = EvalStrIntExpressionWithResult(&ArgStr[2], UInt24, &EvalResult);
    SubPCRefReloc();
    if (EvalResult.OK)
    {
      ChkSpace(SegCode, EvalResult.AddrSpaceMask);
      switch (DecodeBitAdr(&ArgStr[1], &BitLong, True))
      {
        case ModBit51:
          AdrLong -= EProgCounter() + 3 + Ord(NeedsPrefix(FixedZ->Code));
          if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(EvalResult.Flags)) WrError(ErrNum_JmpDistTooBig);
          else
          {
            PutCode(FixedZ->Code);
            BAsmCode[CodeLen++] = BitLong & 0xff;
            BAsmCode[CodeLen++] = AdrLong & 0xff;
          }
          break;
        case ModBit251:
          AdrLong -= EProgCounter() + 4 + Ord(NeedsPrefix(0x1a9));
          if (((AdrLong < -128) || (AdrLong > 127)) && !mSymbolQuestionable(EvalResult.Flags)) WrError(ErrNum_JmpDistTooBig);
          else
          {
            PutCode(0x1a9);
            BAsmCode[CodeLen++] = FixedZ->Code + (BitLong >> 24);
            BAsmCode[CodeLen++] = BitLong & 0xff;
            BAsmCode[CodeLen++] = AdrLong & 0xff;
          }
          break;
      }
    }
  }
}

static void DecodeAcc(Word Index)
{
  FixedOrder *FixedZ = AccOrders + Index;

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(FixedZ->MinCPU))
  {
    DecodeAdr(&ArgStr[1], MModAcc);
    switch (AdrMode)
    {
      case ModAcc:
        PutCode(FixedZ->Code);
        break;
    }
  }
}

static void DecodeFixed(Word Index)
{
  FixedOrder *FixedZ = FixedOrders + Index;

  if (ChkArgCnt(0, 0)
   && ChkMinCPU(FixedZ->MinCPU))
    PutCode(FixedZ->Code);
}


static void DecodeSFR(Word Index)
{
  Word AdrByte;
  Boolean OK;
  tSymbolFlags Flags;
  as_addrspace_t DSeg;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (Memo("SFRB") && !ChkMaxCPU(CPU80C390));
  else
  {
    AdrByte = EvalStrIntExpressionWithFlags(&ArgStr[1], (MomCPU >= CPU80251) ? UInt9 : UInt8, &OK, &Flags);
    if (OK && !mFirstPassUnknown(Flags))
    {
      PushLocHandle(-1);
      DSeg = (MomCPU >= CPU80251) ? SegIO : SegData;
      EnterIntSymbol(&LabPart, AdrByte, DSeg, False);
      if (MakeUseList)
      {
        if (AddChunk(SegChunks + DSeg, AdrByte, 1, False))
          WrError(ErrNum_Overlap);
      }
      if (Memo("SFRB"))
      {
        Byte BitStart;

        if (AdrByte > 0x7f)
        {
          if ((AdrByte & 7) != 0) WrError(ErrNum_NotBitAddressable);
          BitStart = AdrByte;
        }
        else
        {
          if ((AdrByte & 0xe0) != 0x20) WrError(ErrNum_NotBitAddressable);
          BitStart = (AdrByte - 0x20) << 3;
        }
        if (MakeUseList)
          if (AddChunk(SegChunks + SegBData, BitStart, 8, False)) WrError(ErrNum_Overlap);
        as_snprintf(ListLine, STRINGSIZE, "=%~02.*u%s-%~02.*u%s",
                    ListRadixBase, (unsigned)BitStart, GetIntConstIntelSuffix(ListRadixBase),
                    ListRadixBase, (unsigned)BitStart + 7, GetIntConstIntelSuffix(ListRadixBase));
      }
      else
        as_snprintf(ListLine, STRINGSIZE, "=%~02.*u%s",
                    ListRadixBase, (unsigned)AdrByte, GetIntConstIntelSuffix(ListRadixBase));
      PopLocHandle();
    }
  }
}

static void DecodeBIT(Word Index)
{
  LongInt AdrLong;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (MomCPU >= CPU80251)
  {
    if (DecodeBitAdr(&ArgStr[1], &AdrLong, False) == ModBit251)
    {
      PushLocHandle(-1);
      EnterIntSymbol(&LabPart, AdrLong, SegBData, False);
      PopLocHandle();
      *ListLine = '=';
      DissectBit_251(ListLine + 1, STRINGSIZE - 1, AdrLong);
    }
  }
  else
  {
    if (DecodeBitAdr(&ArgStr[1], &AdrLong, False) == ModBit51)
    {
      PushLocHandle(-1);
      EnterIntSymbol(&LabPart, AdrLong, SegBData, False);
      PopLocHandle();
      as_snprintf(ListLine, STRINGSIZE, "=%~02.*u%s",
                  ListRadixBase, (unsigned)AdrLong, GetIntConstIntelSuffix(ListRadixBase));
    }
  }
}

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

  if (ChkMinCPU(CPU80251))
    CodeEquate(SegIO, 0, 0x1ff);
}

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

static void AddFixed(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(FixedOrders, FixedOrder);
  FixedOrders[InstrZ].Code = NCode;
  FixedOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeFixed);
}

static void AddAcc(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(AccOrders, FixedOrder);
  AccOrders[InstrZ].Code = NCode;
  AccOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeAcc);
}

static void AddCond(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(CondOrders, FixedOrder);
  CondOrders[InstrZ].Code = NCode;
  CondOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeCond);
}

static void AddBCond(const char *NName, Word NCode, CPUVar NCPU)
{
  order_array_rsv_end(BCondOrders, FixedOrder);
  BCondOrders[InstrZ].Code = NCode;
  BCondOrders[InstrZ].MinCPU = NCPU;
  AddInstTable(InstTable, NName, InstrZ++, DecodeBCond);
}

static void InitFields(void)
{
  InstTable = CreateInstTable(203);
  AddInstTable(InstTable, "MOV"  , 0, DecodeMOV);
  AddInstTable(InstTable, "ANL"  , 1, DecodeLogic);
  AddInstTable(InstTable, "ORL"  , 0, DecodeLogic);
  AddInstTable(InstTable, "XRL"  , 2, DecodeLogic);
  AddInstTable(InstTable, "MOVC" , 0, DecodeMOVC);
  AddInstTable(InstTable, "MOVH" , 0, DecodeMOVH);
  AddInstTable(InstTable, "MOVZ" , 0, DecodeMOVZS);
  AddInstTable(InstTable, "MOVS" , 0, DecodeMOVZS);
  AddInstTable(InstTable, "MOVX" , 0, DecodeMOVX);
  AddInstTable(InstTable, "POP"  , 1, DecodeStack);
  AddInstTable(InstTable, "PUSH" , 0, DecodeStack);
  AddInstTable(InstTable, "PUSHW", 2, DecodeStack);
  AddInstTable(InstTable, "XCH"  , 0, DecodeXCH);
  AddInstTable(InstTable, "XCHD" , 0, DecodeXCHD);
  AddInstTable(InstTable, "AJMP" , 0, DecodeABranch);
  AddInstTable(InstTable, "ACALL", 1, DecodeABranch);
  AddInstTable(InstTable, "LJMP" , 0, DecodeLBranch);
  AddInstTable(InstTable, "LCALL", 1, DecodeLBranch);
  AddInstTable(InstTable, "EJMP" , 0, DecodeEBranch);
  AddInstTable(InstTable, "ECALL", 1, DecodeEBranch);
  AddInstTable(InstTable, "JMP"  , 0, DecodeJMP);
  AddInstTable(InstTable, "CALL" , 0, DecodeCALL);
  AddInstTable(InstTable, "DJNZ" , 0, DecodeDJNZ);
  AddInstTable(InstTable, "CJNE" , 0, DecodeCJNE);
  AddInstTable(InstTable, "ADD"  , 0, DecodeADD);
  AddInstTable(InstTable, "SUB"  , 0, DecodeSUBCMP);
  AddInstTable(InstTable, "CMP"  , 1, DecodeSUBCMP);
  AddInstTable(InstTable, "ADDC" , 0, DecodeADDCSUBB);
  AddInstTable(InstTable, "SUBB" , 1, DecodeADDCSUBB);
  AddInstTable(InstTable, "INC"  , 0, DecodeINCDEC);
  AddInstTable(InstTable, "DEC"  , 1, DecodeINCDEC);
  AddInstTable(InstTable, "MUL"  , 1, DecodeMULDIV);
  AddInstTable(InstTable, "DIV"  , 0, DecodeMULDIV);
  AddInstTable(InstTable, "CLR"  , 1, DecodeBits);
  AddInstTable(InstTable, "CPL"  , 0, DecodeBits);
  AddInstTable(InstTable, "SETB" , 2, DecodeBits);
  AddInstTable(InstTable, "SRA"  , 0, DecodeShift);
  AddInstTable(InstTable, "SRL"  , 1, DecodeShift);
  AddInstTable(InstTable, "SLL"  , 3, DecodeShift);
  AddInstTable(InstTable, "SFR"  , 0, DecodeSFR);
  AddInstTable(InstTable, "SFRB" , 1, DecodeSFR);
  AddInstTable(InstTable, "BIT"  , 0, DecodeBIT);
  AddInstTable(InstTable, "PORT" , 0, DecodePORT);

  InstrZ = 0;
  AddFixed("NOP" , 0x0000, CPU87C750);
  AddFixed("RET" , 0x0022, CPU87C750);
  AddFixed("RETI", 0x0032, CPU87C750);
  AddFixed("ERET", 0x01aa, CPU80251);
  AddFixed("TRAP", 0x01b9, CPU80251);

  InstrZ = 0;
  AddAcc("DA"  , 0x00d4, CPU87C750);
  AddAcc("RL"  , 0x0023, CPU87C750);
  AddAcc("RLC" , 0x0033, CPU87C750);
  AddAcc("RR"  , 0x0003, CPU87C750);
  AddAcc("RRC" , 0x0013, CPU87C750);
  AddAcc("SWAP", 0x00c4, CPU87C750);

  InstrZ = 0;
  AddCond("JC"  , 0x0040, CPU87C750);
  AddCond("JE"  , 0x0168, CPU80251);
  AddCond("JG"  , 0x0138, CPU80251);
  AddCond("JLE" , 0x0128, CPU80251);
  AddCond("JNC" , 0x0050, CPU87C750);
  AddCond("JNE" , 0x0178, CPU80251);
  AddCond("JNZ" , 0x0070, CPU87C750);
  AddCond("JSG" , 0x0118, CPU80251);
  AddCond("JSGE", 0x0158, CPU80251);
  AddCond("JSL" , 0x0148, CPU80251);
  AddCond("JSLE", 0x0108, CPU80251);
  AddCond("JZ"  , 0x0060, CPU87C750);
  AddCond("SJMP", 0x0080, CPU87C750);

  InstrZ = 0;
  AddBCond("JB" , 0x0020, CPU87C750);
  AddBCond("JBC", 0x0010, CPU87C750);
  AddBCond("JNB", 0x0030, CPU87C750);

  AddInstTable(InstTable, "REG"  , 0, CodeREG);
}

static void DeinitFields(void)
{
  DestroyInstTable(InstTable);
  order_array_free(FixedOrders);
  order_array_free(AccOrders);
  order_array_free(CondOrders);
  order_array_free(BCondOrders);
}

/*-------------------------------------------------------------------------*/
/* Instruktionsdecoder */

static void MakeCode_51(void)
{
  CodeLen = 0;
  DontPrint = False;
  OpSize = -1;
  MinOneIs0 = False;

  /* zu ignorierendes */

  if (*OpPart.str.p_str == '\0') return;

  /* Pseudoanweisungen */

  if (DecodeIntelPseudo(TargetBigEndian))
    return;

  /* suchen */

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

static Boolean IsDef_51(void)
{
  switch (*OpPart.str.p_str)
  {
    case 'B':
      return Memo("BIT");
    case 'S':
      if (Memo("SFR")) return True;
      if (MomCPU >= CPU80251) return False;
      return Memo("SFRB");
    case 'P':
      return (MomCPU >= CPU80251) ? Memo("PORT") : False;
    case 'R':
      return Memo("REG");
    default:
      return False;
  }
}

/*!------------------------------------------------------------------------
 * \fn     InternSymbol_51(char *pArg, TempResult *pResult)
 * \brief  handle built-in symbols on 80x51
 * \param  pArg source argument
 * \param  pResult destination buffer
 * ------------------------------------------------------------------------ */


static void InternSymbol_51(char *pArg, TempResult *pResult)
{
  tRegInt Erg;
  tSymbolSize Size;

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

static void SwitchTo_51(void)
{
  TurnWords = False;
  SetIntConstMode(eIntConstModeIntel);

  PCSymbol = "$";
  HeaderID = 0x31;
  NOPCode = 0x00;
  DivideChars = ",";
  HasAttrs = False;

  /* C251 is entirely different... */

  if (MomCPU >= CPU80251)
  {
    ValidSegs = (1 << SegCode) | (1 << SegIO);
    Grans[SegCode ] = 1; ListGrans[SegCode ] = 1; SegInits[SegCode ] = 0;
    SegLimits[SegCode ] = 0xffffffl;
    Grans[SegIO   ] = 1; ListGrans[SegIO   ] = 1; SegInits[SegIO   ] = 0;
    SegLimits[SegIO   ] = 0x1ff;
    DissectBit = DissectBit_251;
  }

  /* rest of the pack... */

  else
  {
    ValidSegs=(1 << SegCode) | (1 << SegData) | (1 << SegIData) | (1 << SegXData) | (1 << SegBData);

    Grans[SegCode ] = 1; ListGrans[SegCode ] = 1; SegInits[SegCode ] = 0;
    if (MomCPU == CPU80C390)
      SegLimits[SegCode ] = 0xffffff;
    else if (MomCPU == CPU87C750)
      SegLimits[SegCode ] = 0x7ff;
    else
      SegLimits[SegCode ] = 0xffff;


    Grans[SegXData] = 1; ListGrans[SegXData] = 1; SegInits[SegXData] = 0;
    if (MomCPU == CPU80C390)
      SegLimits[SegXData] = 0xffffff;
    else
      SegLimits[SegXData] = 0xffff;

    Grans[SegData ] = 1; ListGrans[SegData ] = 1; SegInits[SegData ] = 0x30;
    SegLimits[SegData ] = 0xff;
    Grans[SegIData] = 1; ListGrans[SegIData] = 1; SegInits[SegIData] = 0x80;
    SegLimits[SegIData] = 0xff;
    Grans[SegBData] = 1; ListGrans[SegBData] = 1; SegInits[SegBData] = 0;
    SegLimits[SegBData] = 0xff;
  }

  MakeCode = MakeCode_51;
  IsDef = IsDef_51;
  InternSymbol = InternSymbol_51;
  DissectReg = DissectReg_51;

  InitFields();
  SwitchFrom = DeinitFields;
  if (!onoff_test_and_set(e_onoff_reg_srcmode))
    SetFlag(&SrcMode, SrcModeSymName, False);
  AddONOFF(SrcModeCmdName, &SrcMode, SrcModeSymName, False);
  onoff_bigendian_add();
}

void code51_init(void)
{
  CPU87C750 = AddCPU("87C750", SwitchTo_51);
  CPU8051   = AddCPU("8051"  , SwitchTo_51);
  CPU8052   = AddCPU("8052"  , SwitchTo_51);
  CPU80C320 = AddCPU("80C320", SwitchTo_51);
  CPU80501  = AddCPU("80C501", SwitchTo_51);
  CPU80502  = AddCPU("80C502", SwitchTo_51);
  CPU80504  = AddCPU("80C504", SwitchTo_51);
  CPU80515  = AddCPU("80515" , SwitchTo_51);
  CPU80517  = AddCPU("80517" , SwitchTo_51);
  CPU80C390 = AddCPU("80C390", SwitchTo_51);
  CPU80251  = AddCPU("80C251", SwitchTo_51);
  CPU80251T = AddCPU("80C251T", SwitchTo_51);
}