/* codem16.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator Mitsubishi M16                                              */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"

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

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

#include "codem16.h"

#define REG_SP 15
#define REG_FP 14

#define ModNone      (-1)
#define ModReg       0
#define MModReg      (1 << ModReg)
#define ModIReg      1
#define MModIReg     (1 << ModIReg)
#define ModDisp16    2
#define MModDisp16   (1 << ModDisp16)
#define ModDisp32    3
#define MModDisp32   (1 << ModDisp32)
#define ModImm       4
#define MModImm      (1 << ModImm)
#define ModAbs16     5
#define MModAbs16    (1 << ModAbs16)
#define ModAbs32     6
#define MModAbs32    (1 << ModAbs32)
#define ModPCRel16   7
#define MModPCRel16  (1 << ModPCRel16)
#define ModPCRel32   8
#define MModPCRel32  (1 << ModPCRel32)
#define ModPop       9
#define MModPop      (1 << ModPop)
#define ModPush      10
#define MModPush     (1 << ModPush)
#define ModRegChain  11
#define MModRegChain (1 << ModRegChain)
#define ModPCChain   12
#define MModPCChain  (1 << ModPCChain)
#define ModAbsChain  13
#define MModAbsChain (1 << ModAbsChain)

#define Mask_RegOnly    (MModReg)
#define Mask_AllShort   (MModReg | MModIReg | MModDisp16 | MModImm | MModAbs16 | MModAbs32 | MModPCRel16 | MModPCRel32 | MModPop | MModPush | MModPCChain | MModAbsChain)
#define Mask_AllGen     (Mask_AllShort | MModDisp32 | MModRegChain)
#define Mask_NoImmShort (Mask_AllShort & ~MModImm)
#define Mask_NoImmGen   (Mask_AllGen & ~MModImm)
#define Mask_MemShort   (Mask_NoImmShort & ~MModReg)
#define Mask_MemGen     (Mask_NoImmGen & ~MModReg)

#define Mask_Source     (Mask_AllGen & ~MModPush)
#define Mask_Dest       (Mask_NoImmGen & ~MModPop)
#define Mask_PureDest   (Mask_NoImmGen & ~(MModPush | MModPop))
#define Mask_PureMem    (Mask_MemGen & ~(MModPush | MModPop))

typedef struct
{
  Word Mask;
  Byte OpMask;
  Word Code;
} OneOrder;

typedef struct
{
  Word Mask1,Mask2;
  Word SMask1,SMask2;
  Word Code;
  Boolean Signed;
} GE2Order;

typedef struct
{
  char *Name;
  Boolean MustByte;
  Word Code1,Code2;
} BitOrder;

typedef struct
{
  const char *p_name;
} condition_t;

static CPUVar CPUM16;

static char *Format;
static Byte FormatCode;
static ShortInt DOpSize, OpSize[5];
static Word AdrMode[5];
static ShortInt AdrType[5];
static Byte AdrCnt1[5], AdrCnt2[5];
static Word AdrVals[5][8];

static Byte OptionCnt;
static char Options[2][10];

static BitOrder *FixedLongOrders;
static OneOrder *OneOrders;
static GE2Order *GE2Orders;
static BitOrder *BitOrders;
static condition_t *Conditions;

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

typedef enum
{
  DispSizeNone,
  DispSize4,
  DispSize4Eps,
  DispSize16,
  DispSize32
} DispSize;

typedef struct _TChainRec
{
  struct _TChainRec *Next;
  Byte RegCnt;
  Word Regs[5],Scales[5];
  LongInt DispAcc;
  Boolean HasDisp;
  DispSize DSize;
} *PChainRec, TChainRec;
static Boolean ErrFlag;

static Boolean IsD4(LongInt inp)
{
  return ((inp >= -32) && (inp <= 28));
}

static Boolean IsD16(LongInt inp)
{
  return ((inp >= -32768) && (inp <= 32767));
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRegCore(const char *pArg, Word *pResult)
 * \brief  check whether argument is a CPU register
 * \param  pArg argument to check
 * \param  pResult numeric register value if yes
 * \return True if yes
 * ------------------------------------------------------------------------ */

static Boolean DecodeRegCore(const char *pArg, Word *pResult)
{
  if (!as_strcasecmp(pArg, "SP"))
    *pResult = REG_SP | REGSYM_FLAG_ALIAS;
  else if (!as_strcasecmp(pArg, "FP"))
    *pResult = REG_FP | REGSYM_FLAG_ALIAS;
  else if ((strlen(pArg) > 1) && (as_toupper(*pArg) == 'R'))
  {
    char *p_end;

    *pResult = strtoul(pArg + 1, &p_end, 10);
    return !*p_end && (*pResult <= 15);
  }
  else
    return False;

  return True;
}

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

static void DissectReg_M16(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
{
  if (InpSize == eSymbolSize32Bit)
  {
    switch (Value)
    {
      case REGSYM_FLAG_ALIAS | REG_SP:
        as_snprintf(pDest, DestSize, "SP");
        break;
      case REGSYM_FLAG_ALIAS | REG_FP:
        as_snprintf(pDest, DestSize, "FP");
        break;
      default:
        as_snprintf(pDest, DestSize, "R%u", (unsigned)(Value & 15));
    }
  }
  else
    as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
}

/*!------------------------------------------------------------------------
 * \fn     DecodeReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
 * \brief  parse for register, including register aliases
 * \param  pArg source argument
 * \param  pResult result buffer
 * \param  MustBeReg True if register is expected
 * \return tRegEvalResult
 * ------------------------------------------------------------------------ */

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

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

  RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize32Bit, MustBeReg);
  *pResult = RegDescr.Reg & ~REGSYM_FLAG_ALIAS;
  return RegEvalResult;
}

static void SplitSize(tStrComp *pArg, DispSize *Erg)
{
  int ArgLen = strlen(pArg->str.p_str);

  if ((ArgLen > 2) && (!strcmp(pArg->str.p_str + (ArgLen - 2), ":4")))
  {
    *Erg = DispSize4;
    StrCompShorten(pArg, 2);
  }
  else if ((ArgLen > 3) && (!strcmp(pArg->str.p_str + (ArgLen - 3), ":16")))
  {
    *Erg = DispSize16;
    StrCompShorten(pArg, 3);
  }
  else if ((ArgLen > 3) && (!strcmp(pArg->str.p_str + (ArgLen - 3), ":32")))
  {
    *Erg = DispSize32;
    StrCompShorten(pArg, 3);
  }
}

static void DecideAbs(LongInt Disp, DispSize Size, Word Mask, int Index)
{
  switch (Size)
  {
    case DispSize4:
      Size = DispSize16;
      break;
    case DispSizeNone:
      Size = ((IsD16(Disp)) && (Mask & MModAbs16)) ? DispSize16 : DispSize32;
      break;
    default:
      break;
  }

  switch (Size)
  {
    case DispSize16:
      if (ChkRange(Disp, -32768, 32767))
      {
        AdrType[Index] = ModAbs16;
        AdrMode[Index] = 0x09;
        AdrVals[Index][0] = Disp & 0xffff;
        AdrCnt1[Index] = 2;
      }
      break;
    case DispSize32:
      AdrType[Index] = ModAbs32;
      AdrMode[Index] = 0x0a;
      AdrVals[Index][0] = Disp >> 16;
      AdrVals[Index][1] = Disp & 0xffff;
      AdrCnt1[Index] = 4;
      break;
    default:
      WrError(ErrNum_InternalError);
  }
}

static void SetError(tErrorNum Code)
{
  WrError(Code);
  ErrFlag = True;
}

static PChainRec DecodeChain(tStrComp *pArg)
{
  PChainRec Rec;
  int z;
  char *pCompSplit, *pScaleSplit;
  String SRegStr;
  tStrComp Arg, Remainder, ScaleArg, SReg;
  Boolean OK;
  Byte Scale;
  tRegEvalResult RegEvalResult;

  ChkStack();
  Rec = (PChainRec) malloc(sizeof(TChainRec));
  Rec->Next = NULL;
  Rec->RegCnt = 0;
  Rec->DispAcc = 0;
  Rec->HasDisp = False;
  Rec->DSize = DispSizeNone;

  StrCompMkTemp(&SReg, SRegStr, sizeof(SRegStr));
  Arg = *pArg;
  do
  {
    /* eine Komponente abspalten */

    pCompSplit = QuotPos(Arg.str.p_str, ',');
    if (pCompSplit)
      StrCompSplitRef(&Arg, &Remainder, &Arg, pCompSplit);

    StrCompCopy(&SReg, &Arg);
    pScaleSplit = RQuotPos(SReg.str.p_str, '*');
    if (pScaleSplit)
      StrCompSplitRef(&SReg, &ScaleArg, &SReg, pScaleSplit);

    /* weitere Indirektion ? */

    if (*Arg.str.p_str == '@')
    {
      if (Rec->Next) SetError(ErrNum_InvAddrMode);
      else
      {
        StrCompIncRefLeft(&Arg, 1);
        if (IsIndirect(Arg.str.p_str))
        {
          StrCompIncRefLeft(&Arg, 1);
          StrCompShorten(&Arg, 1);
        }
        Rec->Next = DecodeChain(&Arg);
      }
    }

    /* Register, mit Skalierungsfaktor ? */

    else if ((RegEvalResult = DecodeReg(&SReg, Rec->Regs + Rec->RegCnt, False)) != eIsNoReg)
    {
      if (RegEvalResult == eRegAbort)
        ErrFlag = True;
      else if (Rec->RegCnt >= 5) SetError(ErrNum_InvAddrMode);
      else
      {
        tSymbolFlags Flags;

        if (pScaleSplit)
          Scale = EvalStrIntExpressionWithFlags(&ScaleArg, UInt4, &OK, &Flags);
        else
        {
          OK = True;
          Scale = 1;
           Flags= eSymbolFlag_None;
        }
        if (mFirstPassUnknown(Flags))
          Scale = 1;
        if (!OK) ErrFlag = True;
        else if ((Scale != 1) && (Scale != 2) && (Scale != 4) && (Scale != 8)) SetError(ErrNum_InvAddrMode);
        else
        {
          Rec->Scales[Rec->RegCnt] = 0;
          while (Scale > 1)
          {
            Rec->Scales[Rec->RegCnt]++;
            Scale = Scale >> 1;
          }
          Rec->RegCnt++;
        }
      }
    }

    /* PC, mit Skalierungsfaktor ? */

    else if (!as_strcasecmp(SReg.str.p_str, "PC"))
    {
      if (Rec->RegCnt >= 5) SetError(ErrNum_InvAddrMode);
      else
      {
        tSymbolFlags Flags;

        if (pScaleSplit)
          Scale = EvalStrIntExpressionWithFlags(&ScaleArg, UInt4, &OK, &Flags);
        else
        {
          OK = True;
          Scale = 1;
          Flags = eSymbolFlag_None;
        }
        if (mFirstPassUnknown(Flags))
          Scale = 1;
        if (!OK) ErrFlag = True;
        else if ((Scale != 1) && (Scale != 2) && (Scale != 4) && (Scale != 8)) SetError(ErrNum_InvAddrMode);
        else
        {
          for (z = Rec->RegCnt - 1; z >= 0; z--)
          {
            Rec->Regs[z + 1] = Rec->Regs[z];
            Rec->Scales[z + 1] = Rec->Scales[z];
          }
          Rec->Scales[0] = 0;
          while (Scale > 1)
          {
            Rec->Scales[0]++;
            Scale = Scale >> 1;
          }
          Rec->Regs[0] = 16;
          Rec->RegCnt++;
        }
      }
    }

    /* ansonsten Displacement */

    else
    {
      SplitSize(&Arg, &(Rec->DSize));
      Rec->DispAcc += EvalStrIntExpression(&Arg, Int32, &OK);
      if (!OK) ErrFlag = True;
      Rec->HasDisp = True;
    }

    if (pCompSplit)
      Arg = Remainder;
  }
  while (pCompSplit && !ErrFlag);

  if (ErrFlag)
  {
    free(Rec);
    return NULL;
  }
  else return Rec;
}

static Boolean ChkAdr(Word Mask, int Index)
{
  AdrCnt2[Index]=AdrCnt1[Index] >> 1;
  if ((AdrType[Index] != -1) && ((Mask & (1 << AdrType[Index])) == 0))
  {
    char Str[30];

    AdrCnt1[Index] = AdrCnt2[Index] = 0;
    AdrType[Index] = ModNone;
    as_snprintf(Str, sizeof(Str), "%d", Index);
    WrXError(ErrNum_InvAddrMode, Str);
    return False;
  }
  else
    return (AdrType[Index] != ModNone);
}

static Boolean DecodeAdr(const tStrComp *pArg, int Index, Word Mask)
{
  LongInt AdrLong, MinReserve, MaxReserve;
  int z, z2, LastChain;
  Boolean OK, Error;
  PChainRec RootChain, RunChain, PrevChain;
  DispSize DSize;
  tStrComp Arg;

  AdrCnt1[Index] = 0;
  AdrType[Index] = ModNone;

  /* Register ? */

  switch (DecodeReg(pArg, AdrMode + Index, False))
  {
    case eIsReg:
      AdrType[Index] = ModReg;
      AdrMode[Index] += 0x10;
      return ChkAdr(Mask, Index);
    case eIsNoReg:
      break;
    default:
      return False;
  }

  /* immediate ? */

  if (*pArg->str.p_str == '#')
  {
    switch (OpSize[Index])
    {
      case -1:
        WrError(ErrNum_UndefOpSizes);
        OK = False;
        break;
      case 0:
        AdrVals[Index][0] = EvalStrIntExpressionOffs(pArg, 1, Int8, &OK) & 0xff;
        if (OK)
          AdrCnt1[Index] = 2;
        break;
      case 1:
        AdrVals[Index][0] = EvalStrIntExpressionOffs(pArg, 1, Int16, &OK);
        if (OK)
          AdrCnt1[Index] = 2;
        break;
      case 2:
        AdrLong = EvalStrIntExpressionOffs(pArg, 1, Int32, &OK);
        if (OK)
        {
          AdrVals[Index][0] = AdrLong >> 16;
          AdrVals[Index][1] = AdrLong & 0xffff;
          AdrCnt1[Index] = 4;
        }
        break;
    }
    if (OK)
    {
      AdrType[Index] = ModImm;
      AdrMode[Index] = 0x0c;
    }
    return ChkAdr(Mask, Index);
  }

  /* indirekt ? */

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

    StrCompRefRight(&IArg,pArg, 1);
    if (IsIndirect(IArg.str.p_str))
    {
      StrCompIncRefLeft(&IArg, 1);
      StrCompShorten(&IArg, 1);
    }

    /* Stack Push ? */

    if ((!as_strcasecmp(IArg.str.p_str, "-R15")) || (!as_strcasecmp(IArg.str.p_str, "-SP")))
    {
      AdrType[Index] = ModPush;
      AdrMode[Index] = 0x05;
      return ChkAdr(Mask, Index);
    }

    /* Stack Pop ? */

    if ((!as_strcasecmp(IArg.str.p_str, "R15+")) || (!as_strcasecmp(IArg.str.p_str, "SP+")))
    {
      AdrType[Index] = ModPop;
      AdrMode[Index] = 0x04;
      return ChkAdr(Mask, Index);
    }

    /* Register einfach indirekt ? */

    switch (DecodeReg(&IArg, AdrMode + Index, False))
    {
      case eIsReg:
        AdrType[Index] = ModIReg;
        AdrMode[Index] += 0x30;
        return ChkAdr(Mask, Index);
      case eIsNoReg:
        break;
      case eRegAbort:
        return False;
    }

    /* zusammengesetzt indirekt ? */

    ErrFlag = False;
    RootChain = DecodeChain(&IArg);

    if (ErrFlag);

    else if (!RootChain);

    /* absolut ? */

    else if ((!RootChain->Next) && (RootChain->RegCnt == 0))
    {
      if (!RootChain->HasDisp)
        RootChain->DispAcc = 0;
      DecideAbs(RootChain->DispAcc, RootChain->DSize, Mask, Index);
      free(RootChain);
    }

    /* einfaches Register/PC mit Displacement ? */

    else if ((!RootChain->Next) && (RootChain->RegCnt == 1) && (RootChain->Scales[0] == 0))
    {
      if (RootChain->Regs[0] == 16)
        RootChain->DispAcc -= EProgCounter();

      /* Displacement-Groesse entscheiden */

      if (RootChain->DSize == DispSizeNone)
      {
        if ((RootChain->DispAcc == 0) && (RootChain->Regs[0] < 16));
        else
         RootChain->DSize = (IsD16(RootChain->DispAcc)) ? DispSize16 : DispSize32;
      }

      switch (RootChain->DSize)
      {
        /* kein Displacement mit Register */

        case DispSizeNone:
          if (ChkRange(RootChain->DispAcc, 0, 0))
          {
            if (RootChain->Regs[0] >= 16) WrError(ErrNum_InvAddrMode);
            else
            {
              AdrType[Index] = ModIReg;
              AdrMode[Index] = 0x30 + RootChain->Regs[0];
            }
          }
          break;

        /* 16-Bit-Displacement */

        case DispSize4:
        case DispSize16:
          if (ChkRange(RootChain->DispAcc, -32768, 32767))
          {
            AdrVals[Index][0] = RootChain->DispAcc & 0xffff;
            AdrCnt1[Index] = 2;
            if (RootChain->Regs[0] == 16)
            {
              AdrType[Index] = ModPCRel16;
              AdrMode[Index] = 0x0d;
            }
            else
            {
              AdrType[Index] = ModDisp16;
              AdrMode[Index] = 0x20 + RootChain->Regs[0];
            }
          }
          break;

        /* 32-Bit-Displacement */

        default:
         AdrVals[Index][1] = RootChain->DispAcc & 0xffff;
         AdrVals[Index][0] = RootChain->DispAcc >> 16;
         AdrCnt1[Index] = 4;
         if (RootChain->Regs[0] == 16)
         {
           AdrType[Index] = ModPCRel32;
           AdrMode[Index] = 0x0e;
         }
         else
         {
           AdrType[Index] = ModDisp32;
           AdrMode[Index] = 0x40 + RootChain->Regs[0];
         }
      }

      free(RootChain);
    }

    /* komplex: dann chained iterieren */

    else
    {
      /* bis zum innersten Element der Indirektion als Basis laufen */

      RunChain = RootChain;
      while (RunChain->Next)
        RunChain = RunChain->Next;

      /* Entscheidung des Basismodus: die Basis darf nicht skaliert
         sein, und wenn ein Modus nicht erlaubt ist, muessen wir mit
         Base-none anfangen... */

      z = 0;
      while ((z < RunChain->RegCnt) && (RunChain->Scales[z] != 0))
        z++;
      if (z >= RunChain->RegCnt)
      {
        AdrType[Index] = ModAbsChain;
        AdrMode[Index] = 0x0b;
      }
      else
      {
        if (RunChain->Regs[z] == 16)
        {
          AdrType[Index] = ModPCChain;
          AdrMode[Index] = 0x0f;
          RunChain->DispAcc -= EProgCounter();
        }
        else
        {
          AdrType[Index] = ModRegChain;
          AdrMode[Index] = 0x60 + RunChain->Regs[z];
        }
        for (z2 = z; z2 <= RunChain->RegCnt - 2; z2++)
        {
          RunChain->Regs[z2] = RunChain->Regs[z2 + 1];
          RunChain->Scales[z2] = RunChain->Scales[z2 + 1];
        }
        RunChain->RegCnt--;
      }

      /* Jetzt ueber die einzelnen Komponenten iterieren */

      LastChain = 0;
      Error = False;
      while ((RootChain) && (!Error))
      {
        RunChain = RootChain;
        PrevChain = NULL;
        while (RunChain->Next)
        {
          PrevChain = RunChain;
          RunChain = RunChain->Next;
        }

        /* noch etwas abzulegen ? */

        if ((RunChain->RegCnt != 0) || (RunChain->HasDisp))
        {
          LastChain = AdrCnt1[Index] >> 1;

          /* Register ablegen */

          if (RunChain->RegCnt != 0)
          {
            AdrVals[Index][LastChain] =
              (RunChain->Regs[0] == 16) ? 0x0600 : RunChain->Regs[0] << 10;
            AdrVals[Index][LastChain] += RunChain->Scales[0] << 5;
            for (z2 = 0; z2 <= RunChain->RegCnt - 2; z2++)
            {
              RunChain->Regs[z2] = RunChain->Regs[z2 + 1];
              RunChain->Scales[z2] = RunChain->Scales[z2 + 1];
            }
            RunChain->RegCnt--;
          }
          else
            AdrVals[Index][LastChain] = 0x0200;
          AdrCnt1[Index] += 2;

          /* Displacement ablegen */

          if (RunChain->HasDisp)
          {
            if ((AdrVals[Index][LastChain] & 0x3e00) == 0x0600)
              RunChain->DispAcc -= EProgCounter();

            if (RunChain->DSize == DispSizeNone)
            {
              MinReserve = 32 * RunChain->RegCnt;
              MaxReserve = 28 * RunChain->RegCnt;
              if (IsD4(RunChain->DispAcc))
                DSize = ((RunChain->DispAcc & 3) == 0) ? DispSize4 : DispSize16;
              else if ((RunChain->DispAcc >= -32 - MinReserve)
                    && (RunChain->DispAcc <= 28 + MaxReserve))
                DSize = DispSize4Eps;
              else if (IsD16(RunChain->DispAcc))
                DSize = DispSize16;
              else if ((RunChain->DispAcc >= -32768 - MinReserve)
                    && (RunChain->DispAcc <= 32767 + MaxReserve))
                DSize = DispSize4Eps;
              else
                DSize = DispSize32;
            }
            else
              DSize = RunChain->DSize;
            RunChain->DSize = DispSizeNone;

            switch (DSize)
            {
              /* Fall 1: passt komplett in 4er-Displacement */

              case DispSize4:
                if (ChkRange(RunChain->DispAcc, -32, 28))
                {
                  if (RunChain->DispAcc & 3)
                  {
                    WrError(ErrNum_NotAligned);
                    Error = True;
                  }
                  else
                  {
                    AdrVals[Index][LastChain] += (RunChain->DispAcc >> 2) & 0x000f;
                    RunChain->HasDisp = False;
                  }
                }
                break;

              /* Fall 2: passt nicht mehr in naechstkleineres Displacement, aber wir
                 koennen hier schon einen Teil ablegen, um im naechsten Iterations-
                 schritt ein kuerzeres Displacement zu bekommen */

              case DispSize4Eps:
                if (RunChain->DispAcc > 0)
                {
                  AdrVals[Index][LastChain] += 0x0007;
                  RunChain->DispAcc -= 28;
                }
                else
                {
                  AdrVals[Index][LastChain] += 0x0008;
                  RunChain->DispAcc += 32;
                }
                break;

              /* Fall 3: 16 Bit */

              case DispSize16:
                if (ChkRange(RunChain->DispAcc, -32768, 32767))
                {
                  AdrVals[Index][LastChain] += 0x0011;
                  AdrVals[Index][LastChain + 1] = RunChain->DispAcc & 0xffff;
                  AdrCnt1[Index] += 2;
                  RunChain->HasDisp = False;
                }
                else
                  Error = True;
                break;

              /* Fall 4: 32 Bit */

              case DispSize32:
                AdrVals[Index][LastChain] += 0x0012;
                AdrVals[Index][LastChain+1] = RunChain->DispAcc >> 16;
                AdrVals[Index][LastChain+2] = RunChain->DispAcc & 0xffff;
                AdrCnt1[Index] += 4;
                RunChain->HasDisp = False;
                break;

              default:
                WrError(ErrNum_InternalError);
                Error = True;
            }
          }
        }

        /* nichts mehr drin: dann ein leeres Steuerwort erzeugen.  Tritt
           auf, falls alles schon im Basisadressierungsbyte verschwunden */

        else if (RunChain != RootChain)
        {
          LastChain = AdrCnt1[Index] >> 1;
          AdrVals[Index][LastChain] = 0x0200;
          AdrCnt1[Index] += 2;
        }

        /* nichts mehr drin: wegwerfen
           wenn wir noch nicht ganz vorne angekommen sind, dann ein
           Indirektionsflag setzen */

        if ((RunChain->RegCnt == 0) && (!RunChain->HasDisp))
        {
          if (RunChain != RootChain)
            AdrVals[Index][LastChain] += 0x4000;
          if (!PrevChain)
            RootChain = NULL;
          else
            PrevChain->Next=NULL;
          free(RunChain);
        }
      }

      /* Ende-Kennung fuer letztes Glied */

      AdrVals[Index][LastChain] += 0x8000;
    }

    return ChkAdr(Mask, Index);
  }

  /* ansonsten absolut */

  DSize = DispSizeNone;
  Arg = *pArg;
  SplitSize(&Arg, &DSize);
  AdrLong = EvalStrIntExpression(&Arg, Int32, &OK);
  if (OK)
    DecideAbs(AdrLong, DSize, Mask, Index);

  return ChkAdr(Mask, Index);
}

static LongInt ImmVal(int Index)
{
  switch (OpSize[Index])
  {
    case 0:
      return (ShortInt) (AdrVals[Index][0] & 0xff);
    case 1:
      return (Integer) (AdrVals[Index][0]);
    case 2:
      return (((LongInt)AdrVals[Index][0]) << 16)
            + ((Integer)AdrVals[Index][1]);
    default:
      WrError(ErrNum_InternalError);
      return 0;
  }
}

static Boolean IsShort(int Index)
{
  return (!(AdrMode[Index] & 0xc0));
}

static void AdaptImm(int Index, Byte NSize, Boolean Signed)
{
  switch (OpSize[Index])
  {
    case 0:
      if (NSize!=0)
      {
        if (((AdrVals[Index][0] & 0x80) == 0x80) && (Signed))
          AdrVals[Index][0] |= 0xff00;
        else
          AdrVals[Index][0] &= 0xff;
        if (NSize == 2)
        {
          if (((AdrVals[Index][0] & 0x8000) == 0x8000) && (Signed))
            AdrVals[Index][1] = 0xffff;
          else
            AdrVals[Index][1] = 0;
          AdrCnt1[Index] += 2;
          AdrCnt2[Index]++;
        }
      }
      break;
    case 1:
      if (NSize == 0)
        AdrVals[Index][0] &= 0xff;
      else if (NSize == 2)
      {
        if (((AdrVals[Index][0] & 0x8000) == 0x8000) && (Signed))
          AdrVals[Index][1] = 0xffff;
        else AdrVals[Index][1] = 0;
        AdrCnt1[Index] += 2;
        AdrCnt2[Index]++;
      }
      break;
    case 2:
      if (NSize != 2)
      {
        AdrCnt1[Index] -= 2;
        AdrCnt2[Index]--;
        if (NSize == 0)
          AdrVals[Index][0] &= 0xff;
      }
      break;
  }
  OpSize[Index] = NSize;
}

static ShortInt DefSize(Byte Mask)
{
  ShortInt z;

  z = 2;
  while ((z >= 0) && (!(Mask & 4)))
  {
    Mask = (Mask << 1) & 7;
    z--;
  }
  return z;
}

static Word RMask(Word No, Boolean Turn)
{
  return (Turn) ? (0x8000 >> No) : (1 << No);
}

static Boolean DecodeRegList(const tStrComp *pArg, Word *pResult, Boolean Turn)
{
  String ArgStr;
  tStrComp Arg, Remainder, From, To;
  char *p, *p1, *p2, *p3;
  Word r1, r2, z;

  StrCompMkTemp(&Arg, ArgStr, sizeof(ArgStr));
  StrCompCopy(&Arg, pArg);
  if (IsIndirect(Arg.str.p_str))
  {
    StrCompShorten(&Arg, 1);
    StrCompIncRefLeft(&Arg, 1);
  }

  *pResult = 0;
  do
  {
    p1 = strchr(Arg.str.p_str, ',');
    p2 = strchr(Arg.str.p_str, '/');
    p = (p1 && (p1 < p2)) ? p1 : p2;
    if (p)
      StrCompSplitRef(&Arg, &Remainder, &Arg, p);
    p3 = strchr(Arg.str.p_str, '-');
    if (!p3)
    {
      if (!DecodeReg(&Arg, &r1, True))
        return False;
      *pResult |= RMask(r1, Turn);
    }
    else
    {
      StrCompSplitRef(&From, &To, &Arg, p3);
      if (!DecodeReg(&From, &r1, True)
       || !DecodeReg(&To, &r2, True))
        return False;
      if (r1 <= r2)
      {
        for (z = r1; z <= r2; z++)
          *pResult |= RMask(z, Turn);
      }
      else
      {
        for (z = r2; z <= 15; z++)
          *pResult |= RMask(z, Turn);
        for (z = 0; z <= r1; z++)
          *pResult |= RMask(z,Turn);
      }
    }
    if (p)
      Arg = Remainder;
  }
  while (p);
  return True;
}

static Boolean DecodeCondition(const char *Asc, Word *Erg)
{
  int z;

  for (z = 0; Conditions[z].p_name; z++)
    if (!as_strcasecmp(Asc, Conditions[z].p_name))
    {
      *Erg = z;
      return True;
    }
  return False;
}

static Boolean DecodeStringCondition(const char *Asc, Word *pErg)
{
  Boolean OK = TRUE;

  if (!as_strcasecmp(Asc, "LTU"))
    *pErg = 0;
  else if (!as_strcasecmp(Asc, "GEU"))
    *pErg = 1;
  else if (!as_strcasecmp(Asc, "N"))
    *pErg = 6;
  else
    OK = (DecodeCondition(Asc, pErg) && (*pErg > 1) && (*pErg < 6));

  return OK;
}

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

static Boolean CheckFormat(const char *FSet)
{
  const char *p;

  if (!strcmp(Format, " "))
    FormatCode = 0;
  else
  {
    p = strchr(FSet, *Format);
    if (p)
      FormatCode = p - FSet + 1;
    else
      WrError(ErrNum_InvFormat);
    return (p != NULL);
  }
  return True;
}

static Boolean CheckBFieldFormat(void)
{
  if ((!strcmp(Format, "G:R")) || (!strcmp(Format, "R:G")))
    FormatCode = 1;
  else if ((!strcmp(Format, "G:I")) || (!strcmp(Format, "I:G")))
    FormatCode = 2;
  else if ((!strcmp(Format, "E:R")) || (!strcmp(Format, "R:E")))
    FormatCode = 3;
  else if ((!strcmp(Format, "E:I")) || (!strcmp(Format, "I:E")))
    FormatCode = 4;
  else
  {
    WrError(ErrNum_InvFormat);
    return False;
  }
  return True;
}

static Boolean GetOpSize(tStrComp *pArg, Byte Index)
{
  char *p;
  int ArgLen = strlen(pArg->str.p_str);

  p = RQuotPos(pArg->str.p_str, '.');
  if (!p)
  {
    OpSize[Index] = DOpSize;
    return True;
  }
  else if (p == pArg->str.p_str + ArgLen - 2)
  {
    switch (as_toupper(p[1]))
    {
      case 'B':
        OpSize[Index] = 0;
        break;
      case 'H':
        OpSize[Index] = 1;
        break;
      case 'W':
        OpSize[Index] = 2;
        break;
      default:
        WrXError(ErrNum_UndefAttr, p);
        return False;
    }
    StrCompShorten(pArg, 2);
    return True;
  }
  else
  {
    WrError(ErrNum_UndefAttr);
    return False;
  }
}

static void SplitOptions(void)
{
  char *pSplit, *pSrc;

  pSrc = OpPart.str.p_str;
  *Options[0] = *Options[1] = '\0';
  for (OptionCnt = 0; OptionCnt < 2; OptionCnt++)
  {
    pSplit = QuotPos(pSrc, '/');
    if (!pSplit)
      break;
    strmaxcpy(Options[OptionCnt], pSplit + 1, sizeof(Options[OptionCnt]));
    if (OptionCnt)
      *pSplit = '\0';
    else
      pSplit[1] = '\0';
    pSrc = Options[OptionCnt];
  }
}

static void DecideBranch(LongInt Adr, Byte Index)
{
  LongInt Dist = Adr - EProgCounter();

  if (FormatCode == 0)
  {
    /* Groessenangabe erzwingt G-Format */
    if (OpSize[Index] != -1)
      FormatCode = 1;
    /* gerade 9-Bit-Zahl kurz darstellbar */
    else if (((Dist & 1) == 0) && (Dist <= 254) && (Dist >= -256))
      FormatCode = 2;
    /* ansonsten allgemein */
    else
      FormatCode = 1;
  }
  if ((FormatCode == 1) && (OpSize[Index] == -1))
  {
    if ((Dist <= 127) && (Dist >= -128))
      OpSize[Index] = 0;
    else if ((Dist <= 32767) && (Dist >= -32768))
      OpSize[Index] = 1;
    else
      OpSize[Index] = 2;
  }
}

static Boolean DecideBranchLength(LongInt *Addr, tSymbolFlags Flags, int Index)
{
  *Addr -= EProgCounter();
  if (OpSize[Index] == -1)
  {
    if ((*Addr >= -128) && (*Addr <= 127))
      OpSize[Index] = 0;
    else if ((*Addr >= -32768) && (*Addr <= 32767))
      OpSize[Index] = 1;
    else OpSize[Index]=2;
  }

  if (!mSymbolQuestionable(Flags) &&
      (((OpSize[Index] == 0) && ((*Addr < -128) || (*Addr > 127)))
    || ((OpSize[Index] == 1) && ((*Addr < -32768) || (*Addr > 32767)))))
  {
    WrError(ErrNum_JmpDistTooBig);
    return False;
  }
  else
    return True;
}

static void Make_G(Word Code)
{
  WAsmCode[0] = 0xd000 + (OpSize[1] << 8) + AdrMode[1];
  memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
  WAsmCode[1 + AdrCnt2[1]] = Code + (OpSize[2] << 8) + AdrMode[2];
  memcpy(WAsmCode + 2 + AdrCnt2[1], AdrVals[2], AdrCnt1[2]);
  CodeLen = 4 + AdrCnt1[1] + AdrCnt1[2];
}

static void Make_E(Word Code, Boolean Signed)
{
  LongInt HVal, Min, Max;

  Min = 128 * (-Ord(Signed));
  Max = Min + 255;
  if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
  else
  {
    HVal = ImmVal(1);
    if (ChkRange(HVal, Min, Max))
    {
      WAsmCode[0] = 0xbf00 + (HVal & 0xff);
      WAsmCode[1] = Code + (OpSize[2] << 8) + AdrMode[2];
      memcpy(WAsmCode + 2, AdrVals[2], AdrCnt1[2]);
      CodeLen = 4 + AdrCnt1[2];
    }
  }
}

static void Make_I(Word Code, Boolean Signed)
{
  if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
  else
  {
    AdaptImm(1, OpSize[2], Signed);
    WAsmCode[0] = Code + (OpSize[2] << 8) + AdrMode[2];
    memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
    memcpy(WAsmCode + 1 + AdrCnt2[2], AdrVals[1], AdrCnt1[1]);
    CodeLen = 2 + AdrCnt1[1] + AdrCnt1[2];
  }
}

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

static void DecodeFixed(Word Code)
{
  if (!ChkArgCnt(0, 0));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (strcmp(Format, " ")) WrError(ErrNum_InvFormat);
  else
  {
    CodeLen = 2;
    WAsmCode[0] = Code;
  }
}

static void DecodeACB_SCB(Word IsSCB)
{
  if (ChkArgCnt(4, 4)
   && CheckFormat("GEQR"))
  {
    if (GetOpSize(&ArgStr[2], 3))
    if (GetOpSize(&ArgStr[4], 4))
    if (GetOpSize(&ArgStr[1], 1))
    if (GetOpSize(&ArgStr[3], 2))
    {
      Word HReg;

      if ((OpSize[3] == -1) && (OpSize[2] == -1)) OpSize[3] = 2;
      if ((OpSize[3] == -1) && (OpSize[2] != -1)) OpSize[3] = OpSize[2];
      else if ((OpSize[3] != -1) && (OpSize[2] == -1)) OpSize[2] = OpSize[3];
      if (OpSize[1] == -1) OpSize[1] = OpSize[2];
      if (OpSize[3] != OpSize[2]) WrError(ErrNum_ConfOpSizes);
      else if (DecodeReg(&ArgStr[2], &HReg, True))
      {
        Boolean OK;
        tSymbolFlags Flags;
        LongInt AdrLong, HVal;

        AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[4], Int32, &OK, &Flags);
        if (OK)
        {
          if (DecodeAdr(&ArgStr[1], 1, Mask_Source))
          {
            if (DecodeAdr(&ArgStr[3], 2, Mask_Source))
            {
              if (FormatCode == 0)
              {
                if (AdrType[1] != ModImm) FormatCode = 1;
                else
                {
                  HVal = ImmVal(1);
                  if ((HVal == 1) && (AdrType[2] == ModReg))
                    FormatCode = 4;
                  else if ((HVal == 1) && (AdrType[2] == ModImm))
                  {
                    HVal = ImmVal(2);
                    if ((HVal >= 1 - IsSCB) && (HVal <= 64 - IsSCB))
                      FormatCode = 3;
                    else
                      FormatCode = 2;
                  }
                  else if ((HVal >= -128) && (HVal <= 127))
                    FormatCode = 2;
                  else
                    FormatCode = 1;
                }
              }
              switch (FormatCode)
              {
                case 1:
                  if (DecideBranchLength(&AdrLong, Flags, 4))  /* ??? */
                  {
                    WAsmCode[0] = 0xd000 + (OpSize[1] << 8) + AdrMode[1];
                    memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
                    WAsmCode[1 + AdrCnt2[1]] = 0xf000 + (IsSCB << 11) + (OpSize[2] << 8) + AdrMode[2];
                    memcpy(WAsmCode + 2 + AdrCnt2[1], AdrVals[2], AdrCnt1[2]);
                    WAsmCode[2 + AdrCnt2[1] + AdrCnt2[2]] = (HReg << 10) + (OpSize[4] << 8);
                    CodeLen = 6 + AdrCnt1[1] + AdrCnt1[2];
                  }
                  break;
                case 2:
                  if (DecideBranchLength(&AdrLong, Flags, 4))  /* ??? */
                  {
                    if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
                    else
                    {
                      HVal = ImmVal(1);
                      if (ChkRange(HVal, -128, 127))
                      {
                        WAsmCode[0] = 0xbf00 + (HVal & 0xff);
                        WAsmCode[1] = 0xf000 + (IsSCB << 11) + (OpSize[2] << 8) + AdrMode[2];
                        memcpy(WAsmCode + 2, AdrVals[2], AdrCnt1[2]);
                        WAsmCode[2 + AdrCnt2[2]] = (HReg << 10) + (OpSize[4] << 8);
                        CodeLen = 6 + AdrCnt1[2];
                      }
                    }
                  }
                  break;
                case 3:
                  if (DecideBranchLength(&AdrLong, Flags, 4))  /* ??? */
                  {
                    if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
                    else if (ImmVal(1) != 1) WrError(ErrNum_Only1);
                    else if (AdrType[2] != ModImm) WrError(ErrNum_InvAddrMode);
                    else
                    {
                      HVal = ImmVal(2);
                      if (ChkRange(HVal, 1 - IsSCB, 64 - IsSCB))
                      {
                        WAsmCode[0] = 0x03d1 + (HReg << 10) + (IsSCB << 1);
                        WAsmCode[1] = ((HVal & 0x3f) << 10) + (OpSize[4] << 8);
                        CodeLen = 4;
                      }
                    }
                  }
                  break;
                case 4:
                  if (DecideBranchLength(&AdrLong, Flags, 4))  /* ??? */
                  {
                    if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
                    else if (ImmVal(1) != 1) WrError(ErrNum_Only1);
                    else if (OpSize[2] != 2) WrError(ErrNum_InvOpSize);
                    else if (AdrType[2] != ModReg) WrError(ErrNum_InvAddrMode);
                    else
                    {
                      WAsmCode[0] = 0x03d0 + (HReg << 10) + (IsSCB << 1);
                      WAsmCode[1] = ((AdrMode[2] & 15) << 10) + (OpSize[4] << 8);
                      CodeLen = 4;
                    }
                  }
                  break;
              }
              if (CodeLen>0)
              {
                switch (OpSize[4])
                {
                  case 0:
                    WAsmCode[(CodeLen >> 1) - 1] += AdrLong & 0xff;
                    break;
                  case 1:
                    WAsmCode[CodeLen >> 1] = AdrLong & 0xffff;
                    CodeLen += 2;
                    break;
                  case 2:
                    WAsmCode[ CodeLen >> 1     ] = AdrLong >> 16;
                    WAsmCode[(CodeLen >> 1) + 1] = AdrLong & 0xffff;
                    CodeLen += 4;
                    break;
                }
              }
            }
          }
        }
      }
    }
  }
}

static void DecodeFixedLong(Word Index)
{
  BitOrder *pOrder = FixedLongOrders + Index;

  if (!ChkArgCnt(0, 0));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (strcmp(Format, " ")) WrError(ErrNum_InvFormat);
  else
  {
    CodeLen = 10;
    WAsmCode[0] = 0xd20c;
    WAsmCode[1] = pOrder->Code1;
    WAsmCode[2] = pOrder->Code2;
    WAsmCode[3] = 0x9e09;
    WAsmCode[4] = 0x0700;
  }
}

static void DecodeMOV(Word Code)
{
  LongInt HVal;

  UNUSED(Code);

  if (ChkArgCnt(2, 2)
   && CheckFormat("GELSZQI"))
  {
    if ((GetOpSize(&ArgStr[1], 1)) && (GetOpSize(&ArgStr[2], 2)))
    {
      if (OpSize[2] == -1)
        OpSize[2] = 2;
      if (OpSize[1] == -1)
        OpSize[1] = OpSize[2];
      if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
       && (DecodeAdr(&ArgStr[2], 2, Mask_AllGen-MModPop)))
      {
        if (FormatCode == 0)
        {
          if (AdrType[1] == ModImm)
          {
            HVal = ImmVal(1);
            if (HVal == 0)
              FormatCode = 5;
            else if ((HVal >= 1) && (HVal <= 8) && (IsShort(2)))
              FormatCode = 6;
            else if ((HVal >= -128) && (HVal <= 127))
              FormatCode = 2;
            else if (IsShort(2))
              FormatCode = 7;
            else
              FormatCode = 1;
          }
          else if ((AdrType[1] == ModReg) && (OpSize[1] == 2) && (IsShort(2)))
            FormatCode = 4;
          else if ((AdrType[2] == ModReg) && (OpSize[2] == 2) && (IsShort(1)))
            FormatCode = 3;
          else
            FormatCode = 1;
        }
        switch (FormatCode)
        {
          case 1:
            Make_G(0x8800);
            break;
          case 2:
            Make_E(0x8800, True);
            break;
          case 3:
            if ((!IsShort(1)) || (AdrType[2] != ModReg)) WrError(ErrNum_InvAddrMode);
            else if (OpSize[2] != 2) WrError(ErrNum_InvOpSize);
            else
            {
              WAsmCode[0] = 0x0040 + ((AdrMode[2] & 15) << 10) + (OpSize[1] << 8) + AdrMode[1];
              memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
              CodeLen = 2 + AdrCnt1[1];
            }
            break;
          case 4:
            if ((!IsShort(2)) || (AdrType[1] != ModReg)) WrError(ErrNum_InvAddrMode);
            else if (OpSize[1] != 2) WrError(ErrNum_InvOpSize);
            else
            {
              WAsmCode[0] = 0x0080 + ((AdrMode[1] & 15) << 10) + (OpSize[2] << 8) + AdrMode[2];
              memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
              CodeLen = 2 + AdrCnt1[2];
            }
            break;
          case 5:
            if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
            else
            {
              HVal = ImmVal(1);
              if (ChkRange(HVal, 0, 0))
              {
                WAsmCode[0] = 0xc400 + (OpSize[2] << 8) + AdrMode[2];
                memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
                CodeLen = 2 + AdrCnt1[2];
              }
            }
            break;
          case 6:
            if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
            else
            {
              HVal = ImmVal(1);
              if (ChkRange(HVal, 1, 8))
              {
                WAsmCode[0] = 0x6000 + ((HVal & 7) << 10) + (OpSize[2] << 8) + AdrMode[2];
                memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
                CodeLen = 2 + AdrCnt1[2];
              }
            }
            break;
          case 7:
            Make_I(0x48c0, True);
            break;
        }
      }
    }
  }
}

static void DecodeOne(Word Index)
{
  OneOrder *pOrder = OneOrders + Index;

  if (ChkArgCnt(1, 1)
   && CheckFormat("G"))
  {
    if (GetOpSize(&ArgStr[1], 1))
    {
      if ((OpSize[1] == -1) && (pOrder->OpMask != 0))
        OpSize[1] = DefSize(pOrder->OpMask);
      if ((OpSize[1] != -1) && (((1 << OpSize[1]) & pOrder->OpMask) == 0)) WrError(ErrNum_InvOpSize);
      else
      {
        if (DecodeAdr(&ArgStr[1], 1, pOrder->Mask))
        {
          /* da nur G, Format ignorieren */
          WAsmCode[0] = pOrder->Code + AdrMode[1];
          if (pOrder->OpMask != 0)
            WAsmCode[0] += OpSize[1] << 8;
          memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
          CodeLen = 2 + AdrCnt1[1];
        }
      }
    }
  }
}

static void DecodeADD_SUB(Word IsSUB)
{
  if (ChkArgCnt(2, 2)
   && CheckFormat("GELQI"))
  {
    if ((GetOpSize(&ArgStr[2], 2)) && (GetOpSize(&ArgStr[1], 1)))
    {
      if (OpSize[2] == -1) OpSize[2] = 2;
      if (OpSize[1] == -1) OpSize[1] = OpSize[2];
      if ((DecodeAdr(&ArgStr[1], 1, Mask_Source)) && (DecodeAdr(&ArgStr[2], 2, Mask_PureDest)))
      {
        if (FormatCode==0)
        {
          if (AdrType[1] == ModImm)
          {
            LongInt HVal = ImmVal(1);

            if (IsShort(2))
            {
              if ((HVal >= 1) && (HVal <= 8))
                FormatCode = 4;
              else
                FormatCode = 5;
            }
            else if ((HVal >= -128) && (HVal < 127))
              FormatCode = 2;
            else
              FormatCode = 1;
          }
          else if (IsShort(1) && (AdrType[2] == ModReg) && (OpSize[1] == 2) && (OpSize[2] == 2))
            FormatCode = 3;
          else
            FormatCode = 1;
        }
        switch (FormatCode)
        {
          case 1:
            Make_G(IsSUB << 11);
            break;
          case 2:
            Make_E(IsSUB << 11, True);
            break;
          case 3:
            if ((!IsShort(1)) || (AdrType[2] != ModReg)) WrError(ErrNum_InvAddrMode);
            else if ((OpSize[1] != 2) || (OpSize[2] != 2)) WrError(ErrNum_InvOpSize);
            else
            {
              WAsmCode[0] = 0x8100 + (IsSUB << 6) + ((AdrMode[2] & 15) << 10) + AdrMode[1];
              memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
              CodeLen = 2 + AdrCnt1[1];
              if ((AdrMode[1] == 0x04) & (AdrMode[2] == 15))
                WrError(ErrNum_Unpredictable);
            }
            break;
          case 4:
            if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
            else
            {
              LongInt HVal = ImmVal(1);
              if (ChkRange(HVal, 1, 8))
              {
                WAsmCode[0] = 0x4040 + (IsSUB << 13) + ((HVal & 7) << 10) + (OpSize[2] << 8) + AdrMode[2];
                memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
                CodeLen = 2 + AdrCnt1[2];
              }
            }
            break;
          case 5:
            Make_I(0x44c0 + (IsSUB << 11), True);
            break;
        }
      }
    }
  }
}

static void DecodeCMP(Word Code)
{
  LongInt HVal;

  UNUSED(Code);

  if (ChkArgCnt(2, 2)
   && CheckFormat("GELZQI")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[2] == -1) OpSize[2] = 2;
    if (OpSize[1] == -1) OpSize[1] = OpSize[2];
    if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
     && (DecodeAdr(&ArgStr[2], 2, Mask_NoImmGen-MModPush)))
    {
      if (FormatCode == 0)
      {
        if (AdrType[1] == ModImm)
        {
          HVal = ImmVal(1);
          if (HVal == 0)
            FormatCode = 4;
          else if ((HVal >= 1) && (HVal <= 8) && (IsShort(2)))
            FormatCode = 5;
          else if ((HVal >= -128) && (HVal <= 127))
            FormatCode = 2;
          else if (AdrType[2] == ModReg)
            FormatCode = 3;
          else if (IsShort(2))
            FormatCode = 5;
          else
            FormatCode = 1;
        }
        else if ((IsShort(1)) && (AdrType[2] == ModReg))
          FormatCode = 3;
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          Make_G(0x8000);
          break;
        case 2:
          Make_E(0x8000, True);
          break;
        case 3:
          if ((!IsShort(1)) || (AdrType[2] != ModReg)) WrError(ErrNum_InvAddrMode);
          else if (OpSize[2] != 2) WrError(ErrNum_InvOpSize);
          else
          {
            WAsmCode[0] = ((AdrMode[2] & 15) << 10) + (OpSize[1] << 8) + AdrMode[1];
            memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
            CodeLen = 2 + AdrCnt1[1];
          }
          break;
        case 4:
          if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
          else
          {
            HVal = ImmVal(1);
            if (ChkRange(HVal, 0, 0))
            {
              WAsmCode[0] = 0xc000 + (OpSize[2] << 8) + AdrMode[2];
              memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
              CodeLen = 2 + AdrCnt1[2];
            }
          }
          break;
        case 5:
          if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
          else
          {
            HVal = ImmVal(1);
            if (ChkRange(HVal, 1, 8))
            {
              WAsmCode[0] = 0x4000 + (OpSize[2] << 8) + AdrMode[2] + ((HVal & 7) << 10);
              memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
              CodeLen = 2 + AdrCnt1[2];
            }
          }
          break;
        case 6:
          Make_I(0x40c0, True);
          break;
      }
    }
  }
}

static void DecodeGE2(Word Index)
{
  GE2Order *pOrder = GE2Orders + Index;

  if (ChkArgCnt(2, 2)
   && CheckFormat("GE")
   && GetOpSize(&ArgStr[2], 2)
   && GetOpSize(&ArgStr[1], 1))
  {
    if (OpSize[2] == -1)
      OpSize[2] = DefSize(pOrder->SMask2);
    if (OpSize[1] == -1)
      OpSize[1] = DefSize(pOrder->SMask1);
    if (((pOrder->SMask1 & (1 << OpSize[1])) == 0)
     || ((pOrder->SMask2 & (1 << OpSize[2])) == 0)) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, pOrder->Mask1))
          && (DecodeAdr(&ArgStr[2], 2, pOrder->Mask2)))
    {
      if (FormatCode==0)
      {
        if (AdrType[1] == ModImm)
        {
          LongInt HVal = ImmVal(1);

          if ((pOrder->Signed) && (HVal >= -128) && (HVal <= 127))
            FormatCode = 2;
          else if ((!pOrder->Signed) && (HVal >= 0) && (HVal <= 255))
            FormatCode = 2;
          else
            FormatCode = 1;
        }
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          Make_G(pOrder->Code);
          break;
        case 2:
          Make_E(pOrder->Code, pOrder->Signed);
          break;
      }
    }
  }
}

static void DecodeLog(Word Index)
{
  if (ChkArgCnt(2, 2)
   && CheckFormat("GERI")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[2] == -1)
      OpSize[2] = 2;
    if (OpSize[1] == -1)
      OpSize[1] = OpSize[2];
    if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
     && (DecodeAdr(&ArgStr[2], 2, Mask_Dest - MModPush)))
    {
      if (FormatCode == 0)
      {
        if (AdrType[1] == ModImm)
        {
          LongInt HVal = ImmVal(1);

          if ((HVal >= 0) && (HVal <= 255))
            FormatCode = 2;
          else if (IsShort(2))
            FormatCode = 4;
          else
            FormatCode = 1;
        }
        else if ((AdrType[1] == ModReg) && (AdrType[2] == ModReg) && (OpSize[1] == 2) && (OpSize[2] == 2))
          FormatCode = 3;
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          Make_G(0x2000 + (Index << 10));
          break;
        case 2:
          Make_E(0x2000 + (Index << 10), False);
          break;
        case 3:
          if ((AdrType[1] != ModReg) || (AdrType[2] != ModReg)) WrError(ErrNum_InvAddrMode);
          else if ((OpSize[1] != 2) || (OpSize[2] != 2)) WrError(ErrNum_InvOpSize);
          else
          {
            WAsmCode[0] = 0x00c0 + (Index << 8) + (AdrMode[1] & 15) + ((AdrMode[2] & 15) << 10);
            CodeLen = 2;
          }
          break;
        case 4:
          if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
          else
          {
            WAsmCode[0] = 0x50c0 + (OpSize[2] << 8) + (Index << 10) + AdrMode[2];
            memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
            AdaptImm(1, OpSize[2], False);
            memcpy(WAsmCode + 1 + AdrCnt2[2], AdrVals[1], AdrCnt1[1]);
            CodeLen = 2 + AdrCnt1[1] + AdrCnt1[2];
          }
          break;
      }
      if (OpSize[1] > OpSize[2])
        WrError(ErrNum_Unpredictable);
    }
  }
}

static void DecodeMul(Word Index)
{
  Boolean Unsigned = Index & 1;

  if (ChkArgCnt(2,  2)
   && CheckFormat(Unsigned ? "GE" : "GER")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[2] == -1)
      OpSize[2] = 2;
    if (OpSize[1] == -1)
      OpSize[1] = OpSize[2];
    if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
     && (DecodeAdr(&ArgStr[2], 2, Mask_PureDest)))
    {
      if (FormatCode == 0)
      {
        if (AdrType[1] == ModImm)
        {
          LongInt HVal = ImmVal(1);
          if ((HVal >= -128 + (Unsigned << 7))
           && (HVal <= 127 + (Unsigned << 7)))
            FormatCode = 2;
          else
            FormatCode = 1;
        }
        else if ((!Unsigned)
              && (AdrType[1] == ModReg) && (OpSize[1] == 2)
              && (AdrType[2] == ModReg) && (OpSize[2] == 2))
          FormatCode = 3;
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          Make_G(0x4000 + (Index << 10));
          break;
        case 2:
          Make_E(0x4000 + (Index << 10), !Unsigned);
          break;
        case 3:
          if ((AdrType[1] != ModReg) || (AdrType[2] != ModReg)) WrError(ErrNum_InvAddrMode);
          else if ((OpSize[1] != 2) || (OpSize[2] != 2)) WrError(ErrNum_InvOpSize);
          else
          {
            WAsmCode[0] = 0x00d0
                        + ((AdrMode[2] & 15) << 10)
                        + (Index << 7)
                        + (AdrMode[1] & 15);
            CodeLen = 2;
          }
      }
    }
  }
}

static void DecodeGetPut(Word Code)
{
  Word AdrWord, Mask, Mask2;

  if (Code & 0x80)
  {
    Mask = Mask_Source; Mask2 = MModReg; AdrWord = 1;
  }
  else
  {
    Mask = MModReg; Mask2 = Mask_Dest; AdrWord = 2;
  }
  if (ChkArgCnt(2, 2)
   && CheckFormat("G")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[AdrWord] == -1) OpSize[AdrWord] = Code & 3;
    if (OpSize[3 - AdrWord] == -1) OpSize[3 - AdrWord] = 2;
    if ((OpSize[AdrWord] != (Code & 3)) || (OpSize[3 - AdrWord] != 2)) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask))
          && (DecodeAdr(&ArgStr[2], 2, Mask2)))
    {
      Make_G(Code & 0xff00);
      WAsmCode[0] += 0x0400;
    }
  }
}

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

  if (ChkArgCnt(2, 2)
   && CheckFormat("GR")
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[2] == -1)
      OpSize[2] = 2;
    OpSize[1] = 0;
    if (OpSize[2] != 2) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask_PureMem))
          && (DecodeAdr(&ArgStr[2], 2, Mask_Dest)))
    {
      if (FormatCode == 0)
      {
        if ((AdrType[1] == ModDisp16) && (AdrType[2] == ModReg))
          FormatCode = 2;
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          Make_G(0xb400);
          WAsmCode[0] += 0x800;
          break;
        case 2:
          if ((AdrType[1] != ModDisp16) || (AdrType[2] != ModReg)) WrError(ErrNum_InvAddrMode);
          else
          {
            WAsmCode[0] = 0x03c0 + ((AdrMode[2] & 15) << 10) + (AdrMode[1] & 15);
            WAsmCode[1] = AdrVals[1][0];
            CodeLen = 4;
          }
          break;
      }
    }
  }
}

static void DecodeQINS_QDEL(Word IsQINS)
{
  if (ChkArgCnt(2, 2)
   && CheckFormat("G")
   && (IsQINS || GetOpSize(&ArgStr[2], 2)))
  {
    if (OpSize[2] == -1)
      OpSize[2] = 2;
    OpSize[1] = 0;
    if (OpSize[2] != 2) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask_PureMem))
          && (DecodeAdr(&ArgStr[2], 2, Mask_PureMem | (IsQINS ? 0 : MModReg))))
    {
      Make_G(0xb000 + IsQINS);
      WAsmCode[0] += 0x800;
    }
  }
}

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

  if (ChkArgCnt(2, 2)
   && CheckFormat("G")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[2] == -1)
      OpSize[2] = 2;
    if (OpSize[1] == -1)
      OpSize[1] = OpSize[2];
    if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
     && (DecodeAdr(&ArgStr[2], 2, Mask_Dest)))
    {
      Make_G(0x4000);
      WAsmCode[0] += 0x400;
    }
  }
}

static void DecodeSHL_SHA(Word IsSHA)
{
  if (ChkArgCnt(2, 2)
   && CheckFormat("GEQ")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[1] == -1)
      OpSize[1] = 0;
    if (OpSize[2] == -1)
      OpSize[2] = 2;
    if (OpSize[1] != 0)
      WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
          && (DecodeAdr(&ArgStr[2], 2, Mask_PureDest)))
    {
      if (FormatCode == 0)
      {
        if (AdrType[1] == ModImm)
        {
          LongInt HVal = ImmVal(1);
          if ((IsShort(2)) && (abs(HVal) >= 1) && (abs(HVal) <= 8) && ((IsSHA == 0) || (HVal < 0)))
            FormatCode = 3;
          else if ((HVal >= -128) && (HVal <= 127))
            FormatCode = 2;
          else
            FormatCode = 1;
        }
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          Make_G(0x3000 + (IsSHA << 10));
          break;
        case 2:
          Make_E(0x3000 + (IsSHA << 10), True);
          break;
        case 3:
          if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
          else
          {
            LongInt HVal = ImmVal(1);
            if (ChkRange(HVal, -8, (1 - IsSHA) << 3))
            {
              if (HVal == 0) WrError(ErrNum_InvShiftArg);
              else
              {
                if (HVal < 0)
                  HVal += 16;
                else HVal &= 7;
                WAsmCode[0] = 0x4080 + (HVal << 10) + (IsSHA << 6) + (OpSize[2] << 8) + AdrMode[2];
                memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
                CodeLen = 2 + AdrCnt1[2];
              }
            }
          }
          break;
      }
    }
  }
}

static void DecodeSHXL_SHXR(Word Code)
{
  if (ChkArgCnt(1, 1)
   && CheckFormat("G")
   && GetOpSize(&ArgStr[1], 1))
  {
    if (OpSize[1] == -1)
      OpSize[1] = 2;
    if (OpSize[1] != 2) WrError(ErrNum_InvOpSize);
    else if (DecodeAdr(&ArgStr[1], 1, Mask_PureDest))
    {
      WAsmCode[0] = 0x02f7;
      WAsmCode[1] = Code + AdrMode[1];
      memcpy(WAsmCode + 1, AdrVals, AdrCnt1[1]);
      CodeLen = 4 + AdrCnt1[1];
    }
  }
}

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

  if (OptionCnt > 1) WrError(ErrNum_WrongOptCnt);
  else if (ChkArgCnt(3, 3)
        && CheckFormat("G")
        && GetOpSize(&ArgStr[1], 2)
        && GetOpSize(&ArgStr[2], 1)
        && GetOpSize(&ArgStr[3], 3))
  {
    Boolean OptOK;
    Word IsSigned;

    if ((OptionCnt == 0)
     || (!as_strcasecmp(Options[0], "N")))
    {
      OptOK = True;
      IsSigned = 0;
    }
    else if (!as_strcasecmp(Options[0], "S"))
    {
      OptOK = True;
      IsSigned = 1;
    }
    else
    {
      OptOK = False;
      IsSigned = 0;
    }

    if (OpSize[3] == -1) OpSize[3] = 2;
    if (OpSize[2] == -1) OpSize[2] = OpSize[3];
    if (OpSize[1] == -1) OpSize[1] = OpSize[3];
    if ((OpSize[1] != OpSize[2]) || (OpSize[2] != OpSize[3])) WrError(ErrNum_ConfOpSizes);
    else if (!OptOK) WrXError(ErrNum_UndefCond, Options[0]);
    else if ((DecodeAdr(&ArgStr[1], 2, Mask_MemGen-MModPop-MModPush))
          && (DecodeAdr(&ArgStr[2], 1, Mask_Source))
          && (DecodeAdr(&ArgStr[3], 3, MModReg)))
    {
      OpSize[2] = 2 + IsSigned;
      Make_G((AdrMode[3] & 15) << 10);
      WAsmCode[0] += 0x400;
    }
  }
}

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

  if (ChkArgCnt(3, 3)
   && CheckFormat("G")
   && GetOpSize(&ArgStr[1], 3)
   && GetOpSize(&ArgStr[2], 1)
   && GetOpSize(&ArgStr[3], 2))
  {
    if (OpSize[3] == -1) OpSize[3] = 2;
    if (OpSize[2] == -1) OpSize[2] = OpSize[3];
    if (OpSize[1] == -1) OpSize[1] = OpSize[2];
    if ((OpSize[1] != OpSize[2]) || (OpSize[2] != OpSize[3])) WrError(ErrNum_ConfOpSizes);
    else if ((DecodeAdr(&ArgStr[1], 3, MModReg))
          && (DecodeAdr(&ArgStr[2], 1, Mask_Source))
          && (DecodeAdr(&ArgStr[3], 2, Mask_PureMem)))
    {
      OpSize[2] = 0;
      Make_G((AdrMode[3] & 15) << 10);
      WAsmCode[0] += 0x400;
    }
  }
}

static void DecodeDIVX_MULX(Word Code)
{
  if (ChkArgCnt(3, 3)
   && CheckFormat("G")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2)
   && GetOpSize(&ArgStr[3], 3))
  {
    if (OpSize[3] == -1) OpSize[3] = 2;
    if (OpSize[2] == -1) OpSize[2] = OpSize[3];
    if (OpSize[1] == -1) OpSize[1] = OpSize[2];
    if ((OpSize[1] != 2) || (OpSize[2] != 2) || (OpSize[3] != 2)) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
          && (DecodeAdr(&ArgStr[2], 2, Mask_PureDest))
          && (DecodeAdr(&ArgStr[3], 3, MModReg)))
    {
      OpSize[2] = 0;
      Make_G(Code + ((AdrMode[3] & 15) << 10));
      WAsmCode[0] += 0x400;
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (strcmp(Format, " ")) WrError(ErrNum_InvFormat);
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_InvAddrMode);
  else
  {
    Boolean OK;

    WAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt3, &OK);
    if (OK)
    {
      WAsmCode[0] = 0x0fd6;
      CodeLen = 4;
    }
  }
}

static void DecodeBit(Word Index)
{
  const BitOrder *pOrder = BitOrders + Index;

  if (ChkArgCnt(2, 2)
   && CheckFormat(pOrder->Code2 ? "GEQ" : "GE")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[1] == -1)
      OpSize[1] = 2;
    if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
     && (DecodeAdr(&ArgStr[2], 2, Mask_PureDest)))
    {
      if (OpSize[2] == -1)
        OpSize[2] = ((AdrType[2] == ModReg) && (!pOrder->MustByte)) ? 2 : 0;

      if (((AdrType[2] != ModReg) || (pOrder->MustByte)) && (OpSize[2] != 0)) WrError(ErrNum_InvOpSize);
      else
      {
        if (FormatCode == 0)
        {
          if (AdrType[1] == ModImm)
          {
            LongInt HVal = ImmVal(1);

            if ((HVal >= 0) && (HVal <= 7) && (IsShort(2)) && (pOrder->Code2 != 0) && (OpSize[2] == 0))
              FormatCode = 3;
            else if ((HVal >= -128) && (HVal < 127))
              FormatCode = 2;
            else
              FormatCode = 1;
          }
          else
            FormatCode = 1;
        }
        switch (FormatCode)
        {
          case 1:
            Make_G(pOrder->Code1);
            break;
          case 2:
            Make_E(pOrder->Code1, True);
            break;
          case 3:
            if ((AdrType[1] != ModImm) || (!IsShort(2))) WrError(ErrNum_InvAddrMode);
            else if (OpSize[2] != 0) WrError(ErrNum_InvOpSize);
            else
            {
              LongInt HVal = ImmVal(1);
              if (ChkRange(HVal, 0, 7))
              {
                WAsmCode[0] = pOrder->Code2 + ((HVal & 7) << 10) + AdrMode[2];
                memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
                CodeLen = 2 + AdrCnt1[2];
              }
            }
            break;
        }
      }
    }
  }
}

static void DecodeBField(Word Code)
{
  if (ChkArgCnt(4, 4)
   && CheckBFieldFormat()
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2)
   && GetOpSize(&ArgStr[3], 3)
   && GetOpSize(&ArgStr[4], 4))
  {
    if (OpSize[1] == -1) OpSize[1] = 2;
    if (OpSize[2] == -1) OpSize[2] = 2;
    if (OpSize[3] == -1) OpSize[3] = 2;
    if (OpSize[4] == -1) OpSize[4] = 2;
    if ((DecodeAdr(&ArgStr[1], 1, MModReg | MModImm))
     && (DecodeAdr(&ArgStr[3], 3, MModReg | MModImm))
     && (DecodeAdr(&ArgStr[2], 2, Mask_Source))
     && (DecodeAdr(&ArgStr[4], 4, Mask_PureMem)))
    {
      if (FormatCode == 0)
      {
        if (AdrType[3] == ModReg)
          FormatCode = (AdrType[1] == ModReg) ? 1 : 2;
        else
          FormatCode = (AdrType[1] == ModReg) ? 3 : 4;
      }
      switch (FormatCode)
      {
        case 1:
          if ((AdrType[1] != ModReg) || (AdrType[3] != ModReg)) WrError(ErrNum_InvAddrMode);
          else if ((OpSize[1] != 2) || (OpSize[3] != 2) || (OpSize[4] != 2)) WrError(ErrNum_InvOpSize);
          else
          {
            WAsmCode[0] = 0xd000 + (OpSize[2] << 8) + AdrMode[2];
            memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
            WAsmCode[1 + AdrCnt2[2]] = 0xc200 + (Code << 10) + AdrMode[4];
            memcpy(WAsmCode + 2 + AdrCnt2[2], AdrVals[4], AdrCnt1[4]);
            WAsmCode[2 + AdrCnt2[2] + AdrCnt2[4]] = ((AdrMode[3] & 15) << 10) + (AdrMode[1] & 15);
            CodeLen = 6 + AdrCnt1[2] + AdrCnt1[4];
          }
          break;
        case 2:
          if ((AdrType[1] != ModImm) || (AdrType[3] != ModReg)) WrError(ErrNum_InvAddrMode);
          else if ((OpSize[3] != 2) || (OpSize[4] != 2)) WrError(ErrNum_InvOpSize);
          else
          {
            WAsmCode[0] = 0xd000 + (OpSize[2] << 8) + AdrMode[2];
            memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
            WAsmCode[1 + AdrCnt2[2]] = 0xd200 + (Code << 10) + AdrMode[4];
            memcpy(WAsmCode + 2 + AdrCnt2[2], AdrVals[4], AdrCnt1[4]);
            WAsmCode[2 + AdrCnt2[2] + AdrCnt2[4]] = ((AdrMode[3] & 15) << 10) + (OpSize[1] << 8);
            CodeLen = 6 + AdrCnt1[2] + AdrCnt1[4];
            if (OpSize[1] == 0)
              WAsmCode[(CodeLen-2) >> 1] += AdrVals[1][0] & 0xff;
            else
            {
              memcpy(WAsmCode + (CodeLen >> 1), AdrVals[1], AdrCnt1[1]);
              CodeLen += AdrCnt1[1];
            }
          }
          break;
        case 3:
          if ((AdrType[1] != ModReg) || (AdrType[2] != ModImm) || (AdrType[3] != ModImm)) WrError(ErrNum_InvAddrMode);
          else if ((OpSize[1] != 2) || (OpSize[4] != 2)) WrError(ErrNum_InvOpSize);
          else
          {
            LongInt Offset = ImmVal(2);
            if (ChkRange(Offset, -128, 127))
            {
              LongInt Width = ImmVal(3);
              if (ChkRange(Width, 1, 32))
              {
                WAsmCode[0] = 0xbf00 + (Offset & 0xff);
                WAsmCode[1] = 0xc200 + (Code << 10) + AdrMode[4];
                memcpy(WAsmCode + 2, AdrVals[4], AdrCnt1[4]);
                WAsmCode[2 + AdrCnt2[4]] = ((Width & 31) << 10) + (AdrMode[1] & 15);
                CodeLen =6 + AdrCnt1[4];
              }
            }
          }
          break;
        case 4:
          if ((AdrType[1] != ModImm) || (AdrType[2] != ModImm) || (AdrType[3] != ModImm)) WrError(ErrNum_InvAddrMode);
          else if (OpSize[4] != 2) WrError(ErrNum_InvOpSize);
          else
          {
            LongInt Offset = ImmVal(2);
            if (ChkRange(Offset, -128, 127))
            {
              LongInt Width = ImmVal(3);
              if (ChkRange(Offset, 1, 32))
              {
                WAsmCode[0] = 0xbf00 + (Offset & 0xff);
                WAsmCode[1] = 0xd200 + (Code << 10) + AdrMode[4];
                memcpy(WAsmCode + 2, AdrVals[4], AdrCnt1[4]);
                WAsmCode[2 + AdrCnt2[4]] = ((Width & 31) << 10) + (OpSize[1] << 8);
                CodeLen = 6 + AdrCnt1[4];
                if (OpSize[1] == 0)
                  WAsmCode[(CodeLen - 1) >> 1] += AdrVals[1][0] & 0xff;
                else
                {
                  memcpy(WAsmCode + (CodeLen >> 1), AdrVals[1], AdrCnt1[1]);
                  CodeLen += AdrCnt1[1];
                }
              }
            }
          }
          break;
      }
    }
  }
}

static void DecodeBFEXT_BFEXTU(Word IsEXTU)
{
  if (ChkArgCnt(4, 4)
   && CheckFormat("GE")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2)
   && GetOpSize(&ArgStr[3], 3)
   && GetOpSize(&ArgStr[4], 4))
  {
    if (OpSize[1] == -1) OpSize[1] = 2;
    if (OpSize[2] == -1) OpSize[2] = 2;
    if (OpSize[3] == -1) OpSize[3] = 2;
    if (OpSize[4] == -1) OpSize[4] = 2;
    if ((DecodeAdr(&ArgStr[4], 4, MModReg))
     && (DecodeAdr(&ArgStr[3], 3, Mask_MemGen & ~(MModPop | MModPush)))
     && (DecodeAdr(&ArgStr[2], 2, MModReg | MModImm)))
    {
      if (DecodeAdr(&ArgStr[1], 1, (AdrType[2] == ModReg) ? Mask_Source : MModImm))
      {
        if (FormatCode == 0)
          FormatCode =  (AdrType[2]== ModReg) ? 1 : 2;
        switch (FormatCode)
        {
          case 1:
            if ((OpSize[2] != 2) || (OpSize[3] != 2) || (OpSize[4] != 2)) WrError(ErrNum_InvOpSize);
            else
            {
              WAsmCode[0] = 0xd000 + (OpSize[1] << 8) + AdrMode[1];
              memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
              WAsmCode[1 + AdrCnt2[1]] = 0xea00 + (IsEXTU << 10) + AdrMode[3];
              memcpy(WAsmCode + 2 + AdrCnt2[1], AdrVals[3], AdrCnt1[3]);
              WAsmCode[2 + AdrCnt2[1] + AdrCnt2[3]] = ((AdrMode[2] & 15) << 10) + (AdrMode[4] & 15);
              CodeLen = 6 + AdrCnt1[1] + AdrCnt1[3];
            }
            break;
          case 2:
            if ((AdrType[1] != ModImm) || (AdrType[2] != ModImm)) WrError(ErrNum_InvAddrMode);
            else if ((OpSize[3] != 2) || (OpSize[4] != 2)) WrError(ErrNum_InvAddrMode);
            else
            {
              LongInt Offset = ImmVal(1);
              if (ChkRange(Offset, -128, 127))
              {
                LongInt Width = ImmVal(2);
                if (ChkRange(Width, 1, 32))
                {
                  WAsmCode[0] = 0xbf00 + (Offset & 0xff);
                  WAsmCode[1] = 0xea00 + (IsEXTU << 10) + AdrMode[3];
                  memcpy(WAsmCode + 2, AdrVals[3], AdrCnt1[3]);
                  WAsmCode[2 + AdrCnt2[3]] = ((Width & 31) << 10) + (AdrMode[4] & 15);
                  CodeLen = 6 + AdrCnt1[3];
                }
              }
            }
            break;
        }
      }
    }
  }
}

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

  if (!ChkArgCnt(2, 2));
  else if (OptionCnt != 1) WrError(ErrNum_WrongOptCnt);
  else if ((strcmp(Options[0], "0")) && (strcmp(Options[0], "1"))) WrXError(ErrNum_UndefCond, Options[0]);
  else if ((CheckFormat("G"))
        && (GetOpSize(&ArgStr[1], 1))
        && (GetOpSize(&ArgStr[2], 2)))
  {
    if (OpSize[1] == -1) OpSize[1] = 2;
    if (OpSize[2] == -1) OpSize[2] = 2;
    if (OpSize[1] != 2) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask_Source))
          && (DecodeAdr(&ArgStr[2], 2, Mask_PureDest)))
    {
      /* immer G-Format */
      WAsmCode[0] = 0xd600 + AdrMode[1];
      memcpy(WAsmCode + 1, AdrVals[1], AdrCnt1[1]);
      WAsmCode[1 + AdrCnt2[1]] = Code + ((Options[0][0] - '0') << 10)+ (OpSize[2] << 8) + AdrMode[2];
      memcpy(WAsmCode + 2 + AdrCnt2[1], AdrVals[2], AdrCnt1[2]);
      CodeLen = 4 + AdrCnt1[1] + AdrCnt1[2];
    }
  }
}

static void DecodeBSR_BRA(Word IsBSR)
{
  if (ChkArgCnt(1, 1)
   && CheckFormat("GD")
   && GetOpSize(&ArgStr[1], 1))
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &OK, &Flags);
    if (OK)
    {
      DecideBranch(AdrLong, 1);
      switch (FormatCode)
      {
        case 2:
          if (OpSize[1] != -1) WrError(ErrNum_UseLessAttr);
          else
          {
            AdrLong -= EProgCounter();
            if (!mSymbolQuestionable(Flags) && ((AdrLong < -256) || (AdrLong > 254))) WrError(ErrNum_JmpDistTooBig);
            else if (Odd(AdrLong)) WrError(ErrNum_DistIsOdd);
            else
            {
              CodeLen = 2;
              WAsmCode[0] = 0xae00 + (IsBSR << 8) + Lo(AdrLong >> 1);
            }
          }
          break;
        case 1:
          WAsmCode[0] = 0x20f7 + (IsBSR << 11) + (((Word)OpSize[1]) << 8);
          AdrLong -= EProgCounter();
          switch (OpSize[1])
          {
            case 0:
              if (!mSymbolQuestionable(Flags) && ((AdrLong < -128) || (AdrLong > 127))) WrError(ErrNum_JmpDistTooBig);
              else
              {
                CodeLen = 4;
                WAsmCode[1] = Lo(AdrLong);
              }
              break;
            case 1:
              if (!mSymbolQuestionable(Flags) && ((AdrLong < -32768) || (AdrLong > 32767))) WrError(ErrNum_JmpDistTooBig);
              else
              {
                CodeLen = 4;
                WAsmCode[1] = AdrLong & 0xffff;
              }
              break;
            case 2:
              CodeLen = 6;
              WAsmCode[1] = AdrLong >> 16;
              WAsmCode[2] = AdrLong & 0xffff;
              break;
          }
          break;
      }
    }
  }
}

static void DecodeBcc(Word Code)
{
  if (ChkArgCnt(1, 1)
   && CheckFormat("GD")
   && GetOpSize(&ArgStr[1], 1))
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrLong = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &OK, &Flags);
    if (OK)
    {
      DecideBranch(AdrLong, 1);
      switch (FormatCode)
      {
        case 2:
          if (OpSize[1] != -1) WrError(ErrNum_UseLessAttr);
          else
          {
            AdrLong -= EProgCounter();
            if (!mSymbolQuestionable(Flags) && ((AdrLong < -256) || (AdrLong > 254))) WrError(ErrNum_JmpDistTooBig);
            else if (Odd(AdrLong)) WrError(ErrNum_DistIsOdd);
            else
            {
              CodeLen = 2;
              WAsmCode[0] = 0x8000 + Code + Lo(AdrLong >> 1);
            }
          }
          break;
        case 1:
          WAsmCode[0] = 0x00f6 + Code + (((Word)OpSize[1]) << 8);
          AdrLong -= EProgCounter();
          switch (OpSize[1])
          {
            case 0:
              if ((AdrLong < -128) || (AdrLong > 127)) WrError(ErrNum_JmpDistTooBig);
              else
              {
                CodeLen = 4;
                WAsmCode[1] = Lo(AdrLong);
              }
              break;
            case 1:
              if ((AdrLong < -32768) || (AdrLong > 32767)) WrError(ErrNum_JmpDistTooBig);
              else
              {
                CodeLen = 4;
                WAsmCode[1] = AdrLong & 0xffff;
              }
              break;
            case 2:
              CodeLen = 6;
              WAsmCode[1] = AdrLong >> 16;
              WAsmCode[2] = AdrLong & 0xffff;
              break;
          }
          break;
      }
    }
  }
}

static void DecodeTRAP(Word Code)
{
  Word Condition;

  UNUSED(Code);

  if (!ChkArgCnt(0, 0));
  else if (OptionCnt != 1) WrError(ErrNum_WrongOptCnt);
  else if (!DecodeCondition(Options[0], &Condition)) WrXError(ErrNum_UndefCond, Options[0]);
  else
  {
    CodeLen = 2;
    WAsmCode[0] = 0x03d4 | (Condition << 10);
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str) WrError(ErrNum_UseLessAttr);
  else if (strcmp(Format, " ")) WrError(ErrNum_InvFormat);
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_InvAddrMode);
  else
  {
    Word AdrWord;
    Boolean OK;

    AdrWord = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt4, &OK);
    if (OK)
    {
      CodeLen = 2;
      WAsmCode[0] = 0x03d5 + (AdrWord << 10);
    }
  }
}

static void DecodeENTER_EXITD(Word IsEXITD)
{
  if (ChkArgCnt(2, 2))
  {
    tStrComp *pRegList = IsEXITD ? &ArgStr[1] : &ArgStr[2],
             *pSizeArg = IsEXITD ? &ArgStr[2] : &ArgStr[1];

    if ((CheckFormat("GE"))
     && (GetOpSize(pSizeArg, 1))
     && (GetOpSize(pRegList, 2)))
    {
      Word RegList;

      if (OpSize[1] == -1) OpSize[1] = 2;
      if (OpSize[2] == -1) OpSize[2] = 2;
      if (OpSize[2] != 2) WrError(ErrNum_InvOpSize);
      else if ((DecodeAdr(pSizeArg, 1, MModReg | MModImm))
            && (DecodeRegList(pRegList, &RegList, IsEXITD)))
      {
        if ((RegList & 0xc000) != 0) WrXError(ErrNum_InvRegList,"SP/FP");
        else
        {
          if (FormatCode == 0)
          {
            if (AdrType[1] == ModImm)
            {
              LongInt HVal = ImmVal(1);
              if ((HVal >= -128) && (HVal <= 127))
                FormatCode = 2;
              else
                FormatCode = 1;
            }
            else
              FormatCode = 1;
          }
          switch (FormatCode)
          {
            case 1:
              WAsmCode[0] = 0x02f7;
              WAsmCode[1] = 0x8c00 + (IsEXITD << 12) + (OpSize[1] << 8) + AdrMode[1];
              memcpy(WAsmCode + 2, AdrVals[1], AdrCnt1[1]);
              WAsmCode[2 + AdrCnt2[1]] = RegList;
              CodeLen = 6 + AdrCnt1[1];
              break;
            case 2:
              if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
              else
              {
                LongInt HVal = ImmVal(1);
                if (ChkRange(HVal, -128, 127))
                {
                  WAsmCode[0] = 0x8e00 + (IsEXITD << 12) + (HVal & 0xff);
                  WAsmCode[1] = RegList;
                  CodeLen = 4;
                }
              }
              break;
          }
        }
      }
    }
  }
}

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

  if (DOpSize == -1) DOpSize = 2;
  if (!ChkArgCnt(0, 0));
  else if (OptionCnt > 1) WrError(ErrNum_WrongOptCnt);
  else
  {
    Boolean OK = True;
    Word Condition = 6;

    if (OptionCnt == 1)
      OK = DecodeStringCondition(Options[0], &Condition);

    if (!OK) WrXError(ErrNum_UndefCond, Options[0]);
    else
    {
      WAsmCode[0] = 0x00e0 + (DOpSize << 8) + (Condition << 10);
      CodeLen = 2;
    }
  }
}

static void DecodeSMOV_SSCH(Word Code)
{
  if (DOpSize == -1) DOpSize = 2;
  if (ChkArgCnt(0, 0))
  {
    int z;
    Word Condition = 6, Mask = 0;
    Boolean OK = True;

    for (z = 0; z < OptionCnt; z++)
    {
      if (!as_strcasecmp(Options[z], "F"))
        Mask = 0;
      else if (!as_strcasecmp(Options[z], "B"))
        Mask = 1;
      else
        OK = DecodeStringCondition(Options[z], &Condition);
      if (!OK)
        break;
    }
    if (!OK) WrXError(ErrNum_UndefCond, Options[z]);
    else
    {
      WAsmCode[0] = 0x00e4 + (DOpSize << 8) + (Condition << 10) + Mask + Code;
      CodeLen = 2;
    }
  }
}

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

  if (DOpSize == -1) DOpSize = 2;
  if (ChkArgCnt(0, 0))
  {
    WAsmCode[0] = 0x24f7 + (DOpSize << 8);
    CodeLen = 2;
  }
}

static void DecodeLDM_STM(Word Code)
{
  if (ChkArgCnt(2, 2)
   && CheckFormat("G"))
  {
    Word Mask = MModIReg | MModDisp16 | MModDisp32 | MModAbs16 | MModAbs32 | MModPCRel16 | MModPCRel32;
    tStrComp *pRegList, *pMemArg;
    Word RegList;

    if (Code)
    {
      Mask |= MModPop;
      pRegList = &ArgStr[2];
      pMemArg = &ArgStr[1];
    }
    else
    {
      Mask |= MModPush;
      pRegList = &ArgStr[1];
      pMemArg = &ArgStr[2];
    }
    if ((GetOpSize(pRegList, 1))
     && (GetOpSize(pMemArg, 2)))
    {
      if (OpSize[1] == -1) OpSize[1] = 2;
      if (OpSize[2] == -1) OpSize[2] = 2;
      if ((OpSize[1] != 2) || (OpSize[2] != 2)) WrError(ErrNum_InvOpSize);
      else if ((DecodeAdr(pMemArg, 2, Mask))
            && (DecodeRegList(pRegList, &RegList, AdrType[2] != ModPush)))
       {
         WAsmCode[0] = 0x8a00 + Code + AdrMode[2];
         memcpy(WAsmCode + 1, AdrVals[2], AdrCnt1[2]);
         WAsmCode[1 + AdrCnt2[2]] = RegList;
         CodeLen = 4 + AdrCnt1[2];
       }
    }
  }
}

static void DecodeSTC_STP(Word Code)
{
  if (ChkArgCnt(2, 2)
   && CheckFormat("G")
   && GetOpSize(&ArgStr[1], 1)
   && GetOpSize(&ArgStr[2], 2))
  {
    if (OpSize[2] == -1) OpSize[2] = 2;
    if (OpSize[1] == -1) OpSize[1] = OpSize[1];
    if (OpSize[1] != OpSize[2]) WrError(ErrNum_UndefOpSizes);
    else if ((!Code) && (OpSize[2] != 2)) WrError(ErrNum_InvOpSize);
    else if ((DecodeAdr(&ArgStr[1], 1, Mask_PureMem))
          && (DecodeAdr(&ArgStr[2], 2, Mask_Dest)))
    {
      OpSize[1] = 0;
      Make_G(0xa800 + Code);
      WAsmCode[0] += 0x800;
    }
  }
}

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

  if (ChkArgCnt(1, 1)
   && CheckFormat("GE")
   && GetOpSize(&ArgStr[1], 1))
  {
    if (OpSize[1] == -1) OpSize[1] = 1;
    if (OpSize[1] != 1) WrError(ErrNum_InvOpSize);
    else if (DecodeAdr(&ArgStr[1], 1, MModReg | MModImm))
    {
      if (FormatCode == 0)
      {
        if (AdrType[1] == ModImm)
        {
          LongInt HVal = ImmVal(1);
          if ((HVal >= 0) && (HVal <= 255))
            FormatCode = 2;
          else
            FormatCode = 1;
        }
        else
          FormatCode = 1;
      }
      switch (FormatCode)
      {
        case 1:
          WAsmCode[0] = 0xba00 + AdrMode[1];
          memcpy(WAsmCode + 1 , AdrVals[1], AdrCnt1[1]);
          CodeLen = 2 + AdrCnt1[1];
          break;
        case 2:
          if (AdrType[1] != ModImm) WrError(ErrNum_InvAddrMode);
          else
          {
            LongInt HVal = ImmVal(1);
            if (ChkRange(HVal, 0, 255))
            {
              WAsmCode[0] = 0xbe00 + (HVal & 0xff);
              CodeLen = 2;
            }
          }
          break;
      }
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     check_no_options(Word index)
 * \brief  check that pseudo ops have no options
 * ------------------------------------------------------------------------ */

static void check_no_options(Word index)
{
  UNUSED(index);

  if (OptionCnt > 0) WrError(ErrNum_WrongOptCnt);
}

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

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

static void AddFixedLong(const char *NName, Word NCode1, Word NCode2)
{
  order_array_rsv_end(FixedLongOrders, BitOrder);
  FixedLongOrders[InstrZ].Code1 = NCode1;
  FixedLongOrders[InstrZ].Code2 = NCode2;
  AddInstTable(InstTable, NName, InstrZ++, DecodeFixedLong);
}

static void AddOne(const char *NName, Byte NOpMask, Word NMask, Word NCode)
{
  order_array_rsv_end(OneOrders, OneOrder);
  OneOrders[InstrZ].Code = NCode;
  OneOrders[InstrZ].Mask = NMask;
  OneOrders[InstrZ].OpMask = NOpMask;
  AddInstTable(InstTable, NName, InstrZ++, DecodeOne);
}

static void AddGE2(const char *NName, Word NMask1, Word NMask2,
                   Byte NSMask1, Byte NSMask2, Word NCode,
                   Boolean NSigned)
{
  order_array_rsv_end(GE2Orders, GE2Order);
  GE2Orders[InstrZ].Mask1 = NMask1;
  GE2Orders[InstrZ].Mask2 = NMask2;
  GE2Orders[InstrZ].SMask1 = NSMask1;
  GE2Orders[InstrZ].SMask2 = NSMask2;
  GE2Orders[InstrZ].Code = NCode;
  GE2Orders[InstrZ].Signed = NSigned;
  AddInstTable(InstTable, NName, InstrZ++, DecodeGE2);
}

static void AddBit(const char *NName, Boolean NMust, Word NCode1, Word NCode2)
{
  order_array_rsv_end(BitOrders, BitOrder);
  BitOrders[InstrZ].Code1 = NCode1;
  BitOrders[InstrZ].Code2 = NCode2;
  BitOrders[InstrZ].MustByte = NMust;
  AddInstTable(InstTable, NName, InstrZ++, DecodeBit);
}

static void AddGetPut(const char *NName, Byte NSize, Word NCode, Boolean NTurn)
{
  AddInstTable(InstTable, NName, NCode | NSize | (NTurn << 7), DecodeGetPut);
}

static void Addcc(const char *p_branch_name)
{
  order_array_rsv_end(Conditions, condition_t);
  Conditions[InstrZ].p_name = p_branch_name + 1;
  if (p_branch_name)
    AddInstTable(InstTable, p_branch_name, InstrZ << 10, DecodeBcc);
  InstrZ++;
}

static void InitFields(void)
{
  Format = (char*)malloc(sizeof(char) * STRINGSIZE);

  InstTable = CreateInstTable(301);

  add_null_pseudo(InstTable);

  AddInstTable(InstTable, "MOV", 0, DecodeMOV);
  AddInstTable(InstTable, "ADD", 0, DecodeADD_SUB);
  AddInstTable(InstTable, "SUB", 1, DecodeADD_SUB);
  AddInstTable(InstTable, "ACB", 0, DecodeACB_SCB);
  AddInstTable(InstTable, "SCB", 1, DecodeACB_SCB);
  AddInstTable(InstTable, "CMP", 0, DecodeCMP);
  AddInstTable(InstTable, "MOVA", 0, DecodeMOVA);
  AddInstTable(InstTable, "QINS", 1 << 11, DecodeQINS_QDEL);
  AddInstTable(InstTable, "QDEL", 0 << 11, DecodeQINS_QDEL);
  AddInstTable(InstTable, "RVBY", 0, DecodeRVBY);
  AddInstTable(InstTable, "SHL", 0, DecodeSHL_SHA);
  AddInstTable(InstTable, "SHA", 1, DecodeSHL_SHA);
  AddInstTable(InstTable, "SHXL", 0x8a00, DecodeSHXL_SHXR);
  AddInstTable(InstTable, "SHXR", 0x9a00, DecodeSHXL_SHXR);
  AddInstTable(InstTable, "CHK", 0, DecodeCHK);
  AddInstTable(InstTable, "CHK/", 0, DecodeCHK);
  AddInstTable(InstTable, "CSI", 0, DecodeCSI);
  AddInstTable(InstTable, "DIVX", 0x8300, DecodeDIVX_MULX);
  AddInstTable(InstTable, "MULX", 0x8200, DecodeDIVX_MULX);
  AddInstTable(InstTable, "WAIT", 0, DecodeWAIT);
  AddInstTable(InstTable, "BFEXT", 0, DecodeBFEXT_BFEXTU);
  AddInstTable(InstTable, "BFEXTU", 1, DecodeBFEXT_BFEXTU);
  AddInstTable(InstTable, "BSCH/", 0x5000, DecodeBSCH);
  AddInstTable(InstTable, "BSR", 1, DecodeBSR_BRA);
  AddInstTable(InstTable, "BRA", 0, DecodeBSR_BRA);
  AddInstTable(InstTable, "TRAPA", 0, DecodeTRAPA);
  AddInstTable(InstTable, "TRAP/", 0, DecodeTRAP);
  AddInstTable(InstTable, "ENTER", 0, DecodeENTER_EXITD);
  AddInstTable(InstTable, "EXITD", 1, DecodeENTER_EXITD);
  AddInstTable(InstTable, "SCMP", 0, DecodeSCMP);
  AddInstTable(InstTable, "SCMP/", 0, DecodeSCMP);
  AddInstTable(InstTable, "SMOV", 0, DecodeSMOV_SSCH);
  AddInstTable(InstTable, "SMOV/", 0, DecodeSMOV_SSCH);
  AddInstTable(InstTable, "SSCH", 16, DecodeSMOV_SSCH);
  AddInstTable(InstTable, "SSCH/", 16, DecodeSMOV_SSCH);
  AddInstTable(InstTable, "SSTR", 0, DecodeSSTR);
  AddInstTable(InstTable, "LDM", 0x1000, DecodeLDM_STM);
  AddInstTable(InstTable, "STM", 0x0000, DecodeLDM_STM);
  AddInstTable(InstTable, "STC", 0x0000, DecodeSTC_STP);
  AddInstTable(InstTable, "STP", 0x0400, DecodeSTC_STP);
  AddInstTable(InstTable, "JRNG", 0, DecodeJRNG);

  AddFixed("NOP"  , 0x1bd6); AddFixed("PIB"  , 0x0bd6);
  AddFixed("RIE"  , 0x08f7); AddFixed("RRNG" , 0x3bd6);
  AddFixed("RTS"  , 0x2bd6); AddFixed("STCTX", 0x07d6);
  AddFixed("REIT" , 0x2fd6);

  InstrZ = 0;
  AddFixedLong("STOP", 0x5374, 0x6f70);
  AddFixedLong("SLEEP", 0x5761, 0x6974);

  InstrZ = 0;
  AddOne("ACS"   , 0x00, Mask_PureMem,                    0x8300);
  AddOne("NEG"   , 0x07, Mask_PureDest,                   0xc800);
  AddOne("NOT"   , 0x07, Mask_PureDest,                   0xcc00);
  AddOne("JMP"   , 0x00, Mask_PureMem,                    0x8200);
  AddOne("JSR"   , 0x00, Mask_PureMem,                    0xaa00);
  AddOne("LDCTX" , 0x00, MModIReg | MModDisp16 | MModDisp32 |
                         MModAbs16 | MModAbs32 | MModPCRel16 | MModPCRel32, 0x8600);
  AddOne("LDPSB" , 0x02, Mask_Source,                     0xdb00);
  AddOne("LDPSM" , 0x02, Mask_Source,                     0xdc00);
  AddOne("POP"   , 0x04, Mask_PureDest,                   0x9000);
  AddOne("PUSH"  , 0x04, Mask_Source-MModPop,             0xb000);
  AddOne("PUSHA" , 0x00, Mask_PureMem,                    0xa200);
  AddOne("STPSB" , 0x02, Mask_Dest,                       0xdd00);
  AddOne("STPSM" , 0x02, Mask_Dest,                       0xde00);

  InstrZ = 0;
  AddGE2("ADDU" , Mask_Source, Mask_PureDest, 7, 7, 0x0400, False);
  AddGE2("ADDX" , Mask_Source, Mask_PureDest, 7, 7, 0x1000, True );
  AddGE2("SUBU" , Mask_Source, Mask_PureDest, 7, 7, 0x0c00, False);
  AddGE2("SUBX" , Mask_Source, Mask_PureDest, 7, 7, 0x1800, True );
  AddGE2("CMPU" , Mask_Source, Mask_PureDest|MModPop, 7, 7, 0x8400, False);
  AddGE2("LDC"  , Mask_Source, Mask_PureDest, 7, 4, 0x9800, True );
  AddGE2("LDP"  , Mask_Source, Mask_PureMem , 7, 7, 0x9c00, True );
  AddGE2("MOVU" , Mask_Source, Mask_Dest    , 7, 7, 0x8c00, True );
  AddGE2("REM"  , Mask_Source, Mask_PureDest, 7, 7, 0x5800, True );
  AddGE2("REMU" , Mask_Source, Mask_PureDest, 7, 7, 0x5c00, True );
  AddGE2("ROT"  , Mask_Source, Mask_PureDest, 1, 7, 0x3800, True );

  InstrZ = 0;
  AddBit("BCLR" , False, 0xb400, 0xa180);
  AddBit("BCLRI", True , 0xa400, 0x0000);
  AddBit("BNOT" , False, 0xb800, 0x0000);
  AddBit("BSET" , False, 0xb000, 0x8180);
  AddBit("BSETI", True , 0xa000, 0x81c0);
  AddBit("BTST" , False, 0xbc00, 0xa1c0);

  AddGetPut("GETB0", 0, 0xc000, False);
  AddGetPut("GETB1", 0, 0xc400, False);
  AddGetPut("GETB2", 0, 0xc800, False);
  AddGetPut("GETH0", 1, 0xcc00, False);
  AddGetPut("PUTB0", 0, 0xd000, True );
  AddGetPut("PUTB1", 0, 0xd400, True );
  AddGetPut("PUTB2", 0, 0xd800, True );
  AddGetPut("PUTH0", 1, 0xdc00, True );

  InstrZ = 0;
  AddInstTable(InstTable, "BFCMP" , InstrZ++, DecodeBField);
  AddInstTable(InstTable, "BFCMPU", InstrZ++, DecodeBField);
  AddInstTable(InstTable, "BFINS" , InstrZ++, DecodeBField);
  AddInstTable(InstTable, "BFINSU", InstrZ++, DecodeBField);

  InstrZ = 0;
  AddInstTable(InstTable, "MUL" , InstrZ++, DecodeMul);
  AddInstTable(InstTable, "MULU", InstrZ++, DecodeMul);
  AddInstTable(InstTable, "DIV" , InstrZ++, DecodeMul);
  AddInstTable(InstTable, "DIVU", InstrZ++, DecodeMul);

  InstrZ = 0;
  Addcc("BXS");
  Addcc("BXC");
  Addcc("BEQ");
  Addcc("BNE");
  Addcc("BLT");
  Addcc("BGE");
  Addcc("BLE");
  Addcc("BGT");
  Addcc("BVS");
  Addcc("BVC");
  Addcc("BMS");
  Addcc("BMC");
  Addcc("BFS");
  Addcc("BFC");
  Addcc(NULL);

  InstrZ = 0;
  AddInstTable(InstTable, "AND", InstrZ++, DecodeLog);
  AddInstTable(InstTable, "OR" , InstrZ++, DecodeLog);
  AddInstTable(InstTable, "XOR", InstrZ++, DecodeLog);

  inst_table_set_prefix_proc(InstTable, check_no_options, 0);
  AddInstTable(InstTable, "REG", 0, CodeREG);
  AddIntelPseudo(InstTable, eIntPseudoFlag_LittleEndian);
}

static void DeinitFields(void)
{
  order_array_free(Conditions);
  order_array_free(Format);
  order_array_free(FixedLongOrders);
  order_array_free(OneOrders);
  order_array_free(GE2Orders);
  order_array_free(BitOrders);
  DestroyInstTable(InstTable);
}

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

static Boolean DecodeAttrPart_M16(void)
{
  char *p;

  switch (AttrSplit)
  {
    case '.':
      p = strchr(AttrPart.str.p_str, ':');
      if (p)
      {
        if (p < AttrPart.str.p_str + strlen(AttrPart.str.p_str) - 1)
          strmaxcpy(Format, p + 1, STRINGSIZE);
        else
          strcpy(Format, " ");
        *p = '\0';
      }
      else
        strcpy(Format, " ");
      break;
    case ':':
      p = strchr(AttrPart.str.p_str, '.');
      if (!p)
      {
        strmaxcpy(Format, AttrPart.str.p_str, STRINGSIZE);
        *AttrPart.str.p_str = '\0';
      }
      else
      {
        *p = '\0';
        if (p == AttrPart.str.p_str)
          strcpy(Format, " ");
        else
          strmaxcpy(Format, AttrPart.str.p_str, STRINGSIZE);
      }
      break;
    default:
      strcpy(Format," ");
  }
  NLS_UpString(Format);

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

static void MakeCode_M16(void)
{
  int z;

  DOpSize = AttrPartOpSize[0];
  for (z = 1; z <= ArgCnt; OpSize[z++] = eSymbolSizeUnknown);

  SplitOptions();

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

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

/*!------------------------------------------------------------------------
 * \fn     InternSymbol_M16(char *pArg, TempResult *pResult)
 * \brief  handle built-in (register) symbols for M16
 * \param  pArg source argument
 * \param  pResult result buffer
 * ------------------------------------------------------------------------ */

static void InternSymbol_M16(char *pArg, TempResult *pResult)
{
  Word RegNum;

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

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

static void SwitchTo_M16(void)
{
  const TFamilyDescr *p_descr = FindFamilyByName("M16");

  TurnWords = True;
  SetIntConstMode(eIntConstModeIntel);

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

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

  DecodeAttrPart = DecodeAttrPart_M16;
  MakeCode = MakeCode_M16;
  IsDef = IsDef_M16;
  DissectReg = DissectReg_M16;
  InternSymbol = InternSymbol_M16;
  SwitchFrom = SwitchFrom_M16;
  InitFields();
}

void codem16_init(void)
{
  CPUM16 = AddCPU("M16", SwitchTo_M16);
}
