/* codefmc16.c */
/****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS, C-Version                                                            */
/*                                                                          */
/* Codegenerator fuer Fujitsu-F2MC16L-Prozessoren                           */
/*                                                                          */
/****************************************************************************/

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

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

#include "codefmc16.h"

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

#define AccOrderCnt 2
#define MulDivOrderCnt 8

typedef struct
{
  Byte Code;
  Word AccCode;
} MulDivOrder;

#define ModNone (-1)
#define ModAcc 0
#define MModAcc (1 << ModAcc)
#define ModReg 1
#define MModReg (1 << ModReg)
#define ModMem 2
#define MModMem (1 << ModMem)
#define ModDir 3
#define MModDir (1 << ModDir)
#define ModImm 4
#define MModImm (1 << ModImm)
#define ModCCR 5
#define MModCCR (1 << ModCCR)
#define ModIO 6
#define MModIO (1 << ModIO)
#define ModSeg 7
#define MModSeg (1 << ModSeg)
#define ModIAcc 8
#define MModIAcc (1 << ModIAcc)
#define ModRDisp 9
#define MModRDisp (1 << ModRDisp)
#define ModSpec 10
#define MModSpec (1 << ModSpec)
#define ModRP 11
#define MModRP (1 << ModRP)
#define ModILM 12
#define MModILM (1 << ModILM)
#define ModSP 13
#define MModSP (1 << ModSP)

#define ABSMODE 0x1f

static CPUVar CPU90500;

static MulDivOrder *MulDivOrders;

static const char BankNames[4][4] =
{
  "PCB", "DTB", "ADB", "SPB"
};

static Byte AdrVals[5], AdrPart, NextDataSeg;
static LongWord CurrBank;
static ShortInt AdrMode, OpSize;

static LongInt Reg_PCB, Reg_DTB, Reg_ADB, Reg_USB, Reg_SSB, Reg_DPR;

static as_assume_rec_t ASSUMEF2MC16s[] =
{
  { "PCB"    , &Reg_PCB,     0x00, 0xff, 0x100, NULL },
  { "DTB"    , &Reg_DTB,     0x00, 0xff, 0x100, NULL },
  { "ADB"    , &Reg_ADB,     0x00, 0xff, 0x100, NULL },
  { "USB"    , &Reg_USB,     0x00, 0xff, 0x100, NULL },
  { "SSB"    , &Reg_SSB,     0x00, 0xff, 0x100, NULL },
  { "DPR"    , &Reg_DPR,     0x00, 0xff, 0x100, NULL }
};

/*--------------------------------------------------------------------------*/
/* Adressdekoder */

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

static Boolean DecodeAdr(const tStrComp *pArg, int Mask)
{
  Integer AdrVal;
  LongWord ImmVal;
  Boolean OK;
  unsigned Index;
  static const char SpecNames[7][4] = {"DTB", "ADB", "SSB", "USB", "DPR", "\a", "PCB"};

  AdrMode = ModNone; AdrCnt = 0;

  /* 1. Sonderregister: */

  if (!as_strcasecmp(pArg->str.p_str, "A"))
  {
    AdrMode = ModAcc;
    goto found;
  }

  if (!as_strcasecmp(pArg->str.p_str, "CCR"))
  {
    AdrMode = ModCCR;
    goto found;
  }

  if (!as_strcasecmp(pArg->str.p_str, "ILM"))
  {
    AdrMode = ModILM;
    goto found;
  }

  if (!as_strcasecmp(pArg->str.p_str, "RP"))
  {
    AdrMode = ModRP;
    goto found;
  }

  if (!as_strcasecmp(pArg->str.p_str, "SP"))
  {
    AdrMode = ModSP;
    goto found;
  }

  if (Mask & MModSeg)
  {
    for (Index = 0; Index < sizeof(BankNames) / sizeof(BankNames[0]); Index++)
      if (!as_strcasecmp(pArg->str.p_str, BankNames[Index]))
      {
        AdrMode = ModSeg;
        AdrPart = Index;
        goto found;
      }
  }

  if (Mask & MModSpec)
  {
    for (Index = 0; Index < sizeof(SpecNames) / sizeof(SpecNames[0]); Index++)
      if (as_strcasecmp(pArg->str.p_str, SpecNames[Index]) == 0)
      {
        AdrMode = ModSpec;
        AdrPart = Index;
        goto found;
      }
  }

  /* 2. Register: */

  if (as_toupper(*pArg->str.p_str) == 'R')
  {
    switch(as_toupper(pArg->str.p_str[1]))
    {
      case 'W':
        if ((pArg->str.p_str[3] == '\0') && (pArg->str.p_str[2] >= '0') && (pArg->str.p_str[2] <= '7'))
        {
          AdrPart = pArg->str.p_str[2] - '0';
          AdrMode = ModReg;
          SetOpSize(1);
          goto found;
        }
        break;
      case 'L':
        if ((pArg->str.p_str[3] == '\0') && (pArg->str.p_str[2] >= '0') && (pArg->str.p_str[2] <= '3'))
        {
          AdrPart = (pArg->str.p_str[2] - '0') << 1;
          AdrMode = ModReg;
          SetOpSize(2);
          goto found;
        }
        break;
      case '0': case '1': case '2': case '3':
      case '4': case '5': case '6': case '7':
        if (pArg->str.p_str[2] == '\0')
        {
          AdrPart = pArg->str.p_str[1] - '0';
          AdrMode = ModReg;
          SetOpSize(0);
          goto found;
        }
    }
  }

  /* 3. 32-Bit-Register indirekt: */

  if ((*pArg->str.p_str == '(')
   && (as_toupper(pArg->str.p_str[1]) == 'R')
   && (as_toupper(pArg->str.p_str[2]) == 'L')
   && (pArg->str.p_str[3] >= '0') && (pArg->str.p_str[3] <= '3')
   && (pArg->str.p_str[4] == ')')
   && (pArg->str.p_str[5] == '\0'))
  {
    AdrPart = ((pArg->str.p_str[3] - '0') << 1) + 1;
    AdrMode = ModMem;
    goto found;
  }

  /* 4. immediate: */

  else if (*pArg->str.p_str == '#')
  {
    if (OpSize == -1) WrError(ErrNum_UndefOpSizes);
    else
    {
      ImmVal = EvalStrIntExpressionOffs(pArg, 1, (OpSize == 2) ? Int32 : ((OpSize == 1) ? Int16 : Int8), &OK);
      if (OK)
      {
        AdrMode = ModImm;
        AdrVals[AdrCnt++] = ImmVal & 0xff;
        if (OpSize >= 1)
          AdrVals[AdrCnt++] = (ImmVal >> 8) & 0xff;
        if (OpSize >= 2)
        {
          AdrVals[AdrCnt++] = (ImmVal >> 16) & 0xff;
          AdrVals[AdrCnt++] = (ImmVal >> 24) & 0xff;
        }
      }
    }

    goto found;
  }

  /* 5. indirekt: */

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

    StrCompRefRight(&Arg, pArg, 1);

    /* Akku-indirekt: */

    if (!as_strcasecmp(Arg.str.p_str, "A"))
    {
      AdrMode = ModIAcc;
    }

    /* PC-relativ: */

    else if (as_strncasecmp(Arg.str.p_str, "PC", 2) == 0)
    {
      tStrComp RegComp;

      StrCompRefRight(&RegComp, &Arg, 2);
      AdrPart = 0x1e;
      if ((*RegComp.str.p_str == '+') || (*RegComp.str.p_str == '-') || (as_isspace(*RegComp.str.p_str)))
      {
        AdrVal = EvalStrIntExpression(&RegComp, SInt16, &OK);
        if (OK)
        {
          AdrVals[0] = AdrVal & 0xff;
          AdrVals[1] = (AdrVal >> 8) & 0xff;
          AdrCnt = 2;
          AdrMode = ModMem;
        }
      }
      else if (*RegComp.str.p_str == '\0')
      {
        AdrVals[0] = AdrVals[1] = 0;
        AdrCnt = 2;
        AdrMode = ModMem;
      }
      else
        WrStrErrorPos(ErrNum_InvReg, &Arg);
    }

    /* base register, 32 bit: */

    else if ((as_toupper(*Arg.str.p_str) == 'R')
          && (as_toupper(Arg.str.p_str[1]) == 'L')
          && (Arg.str.p_str[2] >= '0') && (Arg.str.p_str[2] <= '3'))
    {
      AdrVal = EvalStrIntExpressionOffs(&Arg, 3, SInt8, &OK);
      if (OK)
      {
        AdrVals[0] = AdrVal & 0xff;
        AdrCnt = 1;
        AdrPart = Arg.str.p_str[2] - '0';
        AdrMode = ModRDisp;
      }
    }

    /* base register, 16 bit: */

    else if ((as_toupper(*Arg.str.p_str) == 'R') && (as_toupper(Arg.str.p_str[1]) == 'W') &&
             (Arg.str.p_str[2] >= '0') && (Arg.str.p_str[2] <= '7'))
    {
      tStrComp IComp;

      AdrPart = Arg.str.p_str[2] - '0';
      StrCompRefRight(&IComp, &Arg, 3);
      switch (*IComp.str.p_str)
      {
        case '\0':                          /* no displacement             */
          if (AdrPart < 4)                  /* RW0..RW3 directly available */
          {
            AdrPart += 8;
            AdrMode = ModMem;
          }
          else                              /* dummy disp for RW4..RW7     */
          {
            AdrPart += 0x10;
            AdrVals[0] = 0; AdrCnt = 1;
            AdrMode = ModMem;
          }
          break;
        case '+':
          if (IComp.str.p_str[1] == '\0')          /* postincrement               */
          {
            if (AdrPart > 3) WrError(ErrNum_InvReg);  /* only allowed for RW0..RW3   */
            else
            {
              AdrPart += 0x0c;
              AdrMode = ModMem;
            }
            break;
          }                               /* run into disp part otherwise*/
          /* else fall-through */
        case ' ':
        case '\t':
        case '-':
          while (as_isspace(*IComp.str.p_str))  /* skip leading spaces         */
            StrCompIncRefLeft(&IComp, 1);
          if (!as_strcasecmp(IComp.str.p_str, "+RW7"))  /* base + RW7 as index         */
          {
            if (AdrPart > 1) WrError(ErrNum_InvReg);
            else
            {
              AdrPart += 0x1c;
              AdrMode = ModMem;
            }
          }
          else                               /* numeric index               */
          {
            AdrVal =                         /* max length depends on base  */
              EvalStrIntExpression(&IComp, (AdrPart > 3) ? SInt8 : SInt16, &OK);
            if (OK)
            {                           /* optimize length             */
              AdrVals[0] = AdrVal & 0xff;
              AdrCnt = 1;
              AdrMode = ModMem;
              AdrPart |= 0x10;
              if ((AdrVal < -0x80) || (AdrVal > 0x7f))
              {
                AdrVals[AdrCnt++] = (AdrVal >> 8) & 0xff;
                AdrPart |= 0x08;
              }
            }
          }
          break;
        default:
          WrError(ErrNum_InvAddrMode);
      }
    }

    else
      WrStrErrorPos(ErrNum_InvReg, &Arg);

    goto found;
  }

  /* 6. dann direkt: */

  ImmVal = EvalStrIntExpression(pArg, UInt24, &OK);
  if (OK)
  {
    AdrVals[AdrCnt++] = ImmVal & 0xff;
    if (((ImmVal >> 8) == 0) && (Mask & MModIO))
      AdrMode = ModIO;
    else if ((Lo(ImmVal >> 8) == Reg_DPR) && ((ImmVal & 0xffff0000) == CurrBank) && (Mask & MModDir))
      AdrMode = ModDir;
    else
    {
      AdrVals[AdrCnt++] = (ImmVal >> 8) & 0xff;
      AdrPart = ABSMODE;
      AdrMode = ModMem;
      if ((ImmVal & 0xffff0000) != CurrBank) WrError(ErrNum_InAccPage);
    }
  }

found:
  if ((AdrMode != ModNone) && ((Mask & (1 << AdrMode)) == 0))
  {
    WrError(ErrNum_InvAddrMode);
    AdrMode = ModNone; AdrCnt = 0;
  }

  return (AdrMode != ModNone);
}

static Boolean SplitBit(tStrComp *pArg, Byte *Result)
{
  char *pos;
  Boolean Res = FALSE;

  pos = RQuotPos(pArg->str.p_str, ':');
  if (pos == NULL)
  {
    *Result = 0;
    WrError(ErrNum_InvBitPos);
  }
  else
  {
    tStrComp BitArg;

    StrCompSplitRef(pArg, &BitArg, pArg, pos);
    *Result = EvalStrIntExpression(&BitArg, UInt3, &Res);
  }

  return Res;
}

static void CopyVals(int Offset)
{
  memcpy(BAsmCode + Offset, AdrVals, AdrCnt);
  CodeLen = Offset + AdrCnt;
}

/*--------------------------------------------------------------------------*/
/* Dekoder fuer einzelne Instruktionen */

static void DecodeFixed(Word Code)
{
  if (ChkArgCnt(0, 0))
  {
    BAsmCode[0] = Code;
    CodeLen = 1;
  }
}

static void DecodeALU8(Word Code)
{
  int HCnt;

  if (ChkArgCnt(2, 2))
  {
    SetOpSize(0);
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModReg | MModMem | MModImm | MModDir);
        switch (AdrMode)
        {
          case ModImm:
           BAsmCode[0] = 0x30 + Code;
           BAsmCode[1] = AdrVals[0];
           CodeLen = 2;
           break;
          case ModDir:
           BAsmCode[0] = 0x20 + Code;
           BAsmCode[1] = AdrVals[0];
           CodeLen = 2;
           break;
          case ModReg:
          case ModMem:
          {
            BAsmCode[0] = 0x74;
            BAsmCode[1] = (Code << 5) | AdrPart;
            memcpy(BAsmCode + 2, AdrVals, AdrCnt);
            CodeLen = 2 + AdrCnt;
          }
        }
        break;
      case ModReg:
      case ModMem:
        HCnt = AdrCnt;
        BAsmCode[1] = (Code << 5) | AdrPart;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        if (DecodeAdr(&ArgStr[2], MModAcc))
        {
          BAsmCode[0] = 0x75;
          CodeLen = 2 + HCnt;
        }
        break;
    }
  }
}

static void DecodeLog8(Word Code)
{
  int HCnt;

  if (ChkArgCnt(2, 2))
  {
    SetOpSize(0);
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModMem | ((Code < 6) ? MModCCR : 0));
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModReg | MModMem | MModImm);
        switch (AdrMode)
        {
          case ModImm:
           BAsmCode[0] = 0x30 + Code;
           BAsmCode[1] = AdrVals[0];
           CodeLen = 2;
           break;
          case ModReg:
          case ModMem:
          {
            BAsmCode[0] = 0x74;
            BAsmCode[1] = (Code << 5) | AdrPart;
            memcpy(BAsmCode + 2, AdrVals, AdrCnt);
            CodeLen = 2 + AdrCnt;
          }
        }
        break;
      case ModReg:
      case ModMem:
        HCnt = AdrCnt;
        BAsmCode[1] = (Code << 5) | AdrPart;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        if (DecodeAdr(&ArgStr[2], MModAcc))
        {
          BAsmCode[0] = 0x75;
          CodeLen = 2 + HCnt;
        }
        break;
      case ModCCR:
        if (DecodeAdr(&ArgStr[2], MModImm))
        {
          BAsmCode[0] = 0x20 + Code;
          BAsmCode[1] = AdrVals[0];
          CodeLen = 2;
        }
        break;
    }
  }
}

static void DecodeCarry8(Word Index)
{
  if (ChkArgCnt(1, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    if (ArgCnt == 1)
    {
      BAsmCode[0] = 0x22 + (Index << 4);
      CodeLen = 1;
    }
    else if (DecodeAdr(&ArgStr[2], MModReg | MModMem))
    {
      BAsmCode[0] = 0x74 + Index;
      BAsmCode[1] = AdrPart | 0x40;
      memcpy(BAsmCode + 2, AdrVals, AdrCnt);
      CodeLen = 2 + AdrCnt;
    }
  }
}

static void DecodeCarry16(Word Index)
{
  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc)
   && DecodeAdr(&ArgStr[2], MModReg | MModMem))
  {
    BAsmCode[0] = 0x76 + Index;
    BAsmCode[1] = AdrPart | 0x40;
    memcpy(BAsmCode + 2, AdrVals, AdrCnt);
    CodeLen = 2 + AdrCnt;
  }
}

static void DecodeAcc(Word Code)
{
  if (ChkArgCnt(1, 1)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    BAsmCode[0] = Code;
    CodeLen = 1;
  }
}

static void DecodeShift(Word Code)
{
  if (ChkArgCnt(Hi(Code) ? 1 : 2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    if (ArgCnt == 1)
    {
      BAsmCode[0] = Lo(Code);
      CodeLen = 1;
    }
    else
    {
      SetOpSize(0);
      if (DecodeAdr(&ArgStr[2], MModReg))
      {
        if (AdrPart != 0) WrStrErrorPos(ErrNum_InvReg, &ArgStr[2]);
        else
        {
          BAsmCode[0] = 0x6f;
          BAsmCode[1] = Lo(Code);
          CodeLen = 2;
        }
      }
    }
  }
}

static void DecodeAdd32(Word Index)
{
  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    SetOpSize(2);
    if (DecodeAdr(&ArgStr[2], MModImm | MModMem | MModReg))
    {
      switch (AdrMode)
      {
        case ModImm:
          BAsmCode[0] = 0x18 + Index;
          memcpy(BAsmCode + 1, AdrVals, AdrCnt);
          CodeLen = 1 + AdrCnt;
          break;
        case ModReg:
        case ModMem:
          BAsmCode[0] = 0x70;
          BAsmCode[1] = AdrPart | (Index << 5);
          memcpy(BAsmCode + 2, AdrVals, AdrCnt);
          CodeLen = 2 + AdrCnt;
          break;
      }
    }
  }
}

static void DecodeLog32(Word Index)
{
  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    if (DecodeAdr(&ArgStr[2], MModMem | MModReg))
    {
      BAsmCode[0] = 0x70;
      BAsmCode[1] = AdrPart | (Index << 5);
      memcpy(BAsmCode + 2, AdrVals, AdrCnt);
      CodeLen = 2 + AdrCnt;
    }
  }
}

static void DecodeADDSP(Word Index)
{
  Integer Val;
  Boolean OK;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_OnlyImmAddr);
  else
  {
    Val = EvalStrIntExpressionOffs(&ArgStr[1], 1, Int16, &OK);
    if (OK)
    {
      BAsmCode[CodeLen++] = 0x17;
      BAsmCode[CodeLen++] = Val & 0xff;
      if ((Val > 127) || (Val < -128))
      {
        BAsmCode[CodeLen++] = (Val >> 8) & 0xff;
        BAsmCode[0] |= 8;
      }
    }
  }
}

static void DecodeAdd16(Word Index)
{
  int HCnt;

  if (!ChkArgCnt(1, 2));
  else if (ArgCnt == 1)
  {
    if (DecodeAdr(&ArgStr[1], MModAcc))
    {
      BAsmCode[0] = 0x28 | Index;
      CodeLen = 1;
    }
  }
  else
  {
    SetOpSize(1);
    DecodeAdr(&ArgStr[1], MModAcc | ((Index != 3) ? (MModMem | MModReg) : 0));
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModImm | MModMem | MModReg);
        switch (AdrMode)
        {
          case ModImm:
            BAsmCode[0] = 0x38 | Index;
            memcpy(BAsmCode + 1, AdrVals, AdrCnt);
            CodeLen = 1 + AdrCnt;
            break;
          case ModMem:
          case ModReg:
            BAsmCode[0] = 0x76;
            BAsmCode[1] = AdrPart | (Index << 5);
            memcpy(BAsmCode + 2, AdrVals, AdrCnt);
            CodeLen = 2 + AdrCnt;
            break;
        }
        break;
      case ModMem:
      case ModReg:
        BAsmCode[0] = 0x77;
        BAsmCode[1] = AdrPart | (Index << 5);
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        HCnt = 2 + AdrCnt;
        if (DecodeAdr(&ArgStr[2], MModAcc))
          CodeLen = HCnt;
        break;
    }
  }
}

static void DecodeBBcc(Word Index)
{
  Byte BitPos, HLen;
  LongInt Addr;
  Boolean OK;

  if ((ChkArgCnt(2, 2))
   && (SplitBit(&ArgStr[1], &BitPos)))
  {
    HLen = 0;
    DecodeAdr(&ArgStr[1], MModMem | MModDir | MModIO);
    if (AdrMode != ModNone)
    {
      BAsmCode[HLen++] = 0x6c;
      switch (AdrMode)
      {
        case ModDir:
          BAsmCode[HLen++] = Index + 8 + BitPos;
          BAsmCode[HLen++] = AdrVals[0];
          break;
        case ModIO:
          BAsmCode[HLen++] = Index + BitPos;
          BAsmCode[HLen++] = AdrVals[0];
          break;
        case ModMem:
          if (AdrPart != ABSMODE) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[HLen++] = Index + 16 + BitPos;
            memcpy(BAsmCode + HLen, AdrVals, AdrCnt);
            HLen += AdrCnt;
          }
          break;
      }
      if (HLen > 1)
      {
        tSymbolFlags Flags;

        Addr = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt24, &OK, &Flags) - (EProgCounter() + HLen + 1);
        if (OK)
        {
          if (!mSymbolQuestionable(Flags) && ((Addr < -128) || (Addr > 127))) WrError(ErrNum_JmpDistTooBig);
          else
          {
            BAsmCode[HLen++] = Addr & 0xff;
            CodeLen = HLen;
          }
        }
      }
    }
  }
}

static void DecodeBranch(Word Code)
{
  LongInt Addr;
  Boolean OK;

  if (ChkArgCnt(1, 1))
  {
    tSymbolFlags Flags;

    Addr = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt24, &OK, &Flags) - (EProgCounter() + 2);
    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && ((Addr < -128) || (Addr > 127))) WrError(ErrNum_JmpDistTooBig);
      else
      {
        BAsmCode[0] = Code;
        BAsmCode[1] = Addr & 0xff;
        CodeLen = 2;
      }
    }
  }
}

static void DecodeJmp16(Word Index)
{
  LongWord Addr;
  Boolean OK;

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str == '@')
  {
    tStrComp Arg1;

    SetOpSize(1);
    StrCompRefRight(&Arg1, &ArgStr[1], 1);
    DecodeAdr(&Arg1, MModReg | ((Index == 0) ? MModAcc : 0) | MModMem);
    switch (AdrMode)
    {
      case ModAcc:
        BAsmCode[0] = 0x61;
        CodeLen = 1;
        break;
      case ModReg:
      case ModMem:
        BAsmCode[0] = 0x73;
        BAsmCode[1] = (Index << 4) | AdrPart;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        CodeLen = 2 + AdrCnt;
        break;
    }
  }
  else
  {
    Addr = EvalStrIntExpression(&ArgStr[1], UInt24, &OK);
    if (OK)
    {
      BAsmCode[0] = 0x62 + Index;
      BAsmCode[1] = Addr & 0xff;
      BAsmCode[2] = (Addr >> 8) & 0xff;
      CodeLen = 3;
      if (((Addr >> 16) & 0xff) != (LongWord)Reg_PCB)
        WrError(ErrNum_InAccSegment);
    }
  }
}

static void DecodeJmp24(Word Index)
{
  LongWord Addr;
  Boolean OK;

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str == '@')
  {
    tStrComp Arg1;

    SetOpSize(2);
    StrCompRefRight(&Arg1, &ArgStr[1], 1);
    if (DecodeAdr(&Arg1, MModReg | MModMem))
    {
      BAsmCode[0] = 0x71;
      BAsmCode[1] = (Index << 4) | AdrPart;
      memcpy(BAsmCode + 2, AdrVals, AdrCnt);
      CodeLen = 2 + AdrCnt;
    }
  }
  else
  {
    Addr = EvalStrIntExpression(&ArgStr[1], UInt24, &OK);
    if (OK)
    {
      BAsmCode[0] = 0x63 + Index;
      BAsmCode[1] = Addr & 0xff;
      BAsmCode[2] = (Addr >> 8) & 0xff;
      BAsmCode[3] = (Addr >> 16) & 0xff;
      CodeLen = 4;
    }
  }
}

static void DecodeCALLV(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str != '#') WrError(ErrNum_OnlyImmAddr);
  else
  {
    BAsmCode[0] = 0xe0 + EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt4, &OK);
    if (OK) CodeLen = 1;
  }
}

static void DecodeCmpBranch(Word Index)
{
  LongInt Addr;
  int HCnt;
  Boolean OK;

  if (ChkArgCnt(3, 3))
  {
    SetOpSize(Index); HCnt = 0;
    if (DecodeAdr(&ArgStr[1], MModMem | MModReg | MModAcc))
    {
      OK = TRUE;
      switch (AdrMode)
      {
        case ModAcc:
          BAsmCode[HCnt++] = 0x2a + (Index << 4);
          break;
        case ModReg:
        case ModMem:
          if ((AdrPart >= 0x0c) && (AdrPart <= 0x0f))
          {
            WrError(ErrNum_InvAddrMode); OK = FALSE;
          }
          BAsmCode[HCnt++] = 0x70;
          BAsmCode[HCnt++] = 0xe0 - (Index * 0xa0) + AdrPart;
          memcpy(BAsmCode + HCnt, AdrVals, AdrCnt);
          HCnt += AdrCnt;
          break;
      }
      if ((OK) && (DecodeAdr(&ArgStr[2], MModImm)))
      {
        tSymbolFlags Flags;

        memcpy(BAsmCode + HCnt, AdrVals, AdrCnt);
        HCnt += AdrCnt;
        Addr = EvalStrIntExpressionWithFlags(&ArgStr[3], UInt24, &OK, &Flags) - (EProgCounter() + HCnt + 1);
        if (OK)
        {
          if (!mSymbolQuestionable(Flags) && ((Addr > 127) || (Addr < -128))) WrError(ErrNum_JmpDistTooBig);
          else
          {
            BAsmCode[HCnt++] = Addr & 0xff;
            CodeLen = HCnt;
          }
        }
      }
    }
  }
}

static void DecodeBit(Word Index)
{
  Byte BitPos;

  if ((ChkArgCnt(1, 1))
   && (SplitBit(&ArgStr[1], &BitPos)))
  {
    DecodeAdr(&ArgStr[1], MModMem | MModDir | MModIO);
    if (AdrMode != ModNone)
    {
      BAsmCode[CodeLen++] = 0x6c;
      switch (AdrMode)
      {
        case ModDir:
          BAsmCode[CodeLen++] = Index + 8 + BitPos;
          BAsmCode[CodeLen++] = AdrVals[0];
          break;
        case ModIO:
          BAsmCode[CodeLen++] = Index + BitPos;
          BAsmCode[CodeLen++] = AdrVals[0];
          break;
        case ModMem:
          if (AdrPart != ABSMODE) WrError(ErrNum_InvAddrMode);
          else
          {
            BAsmCode[CodeLen++] = Index + 16 + BitPos;
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
          }
          break;
      }
    }
  }
}

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

  if (ChkArgCnt(1, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    if (ArgCnt == 1)
    {
      BAsmCode[0] = 0x23;
      CodeLen = 1;
    }
    else
    {
      SetOpSize(0);
      DecodeAdr(&ArgStr[2], MModMem | MModReg | MModImm);
      switch (AdrMode)
      {
        case ModMem:
        case ModReg:
          BAsmCode[0] = 0x74;
          BAsmCode[1] = AdrPart | 0x40;
          memcpy(BAsmCode + 2, AdrVals, AdrCnt);
          CodeLen = 2 + AdrCnt;
          break;
        case ModImm:
          BAsmCode[0] = 0x33;
          BAsmCode[1] = AdrVals[0];
          CodeLen = 2;
          break;
      }
    }
  }
}

static void DecodeDBNZ(Word Index)
{
  LongInt Addr;
  Boolean OK;

  if (ChkArgCnt(2, 2))
  {
    SetOpSize(Index);
    if (DecodeAdr(&ArgStr[1], MModReg | MModMem))
    {
      tSymbolFlags Flags;

      Addr = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt16, &OK, &Flags) - (EProgCounter() + 3 + AdrCnt);
      if (OK)
      {
        if (!mSymbolQuestionable(Flags) && ((Addr < -128) || (Addr > 127))) WrError(ErrNum_JmpDistTooBig);
        else
        {
          BAsmCode[0] = 0x74 + (Index << 1);
          BAsmCode[1] = 0xe0 | AdrPart;
          memcpy(BAsmCode + 2, AdrVals, AdrCnt);
          BAsmCode[2 + AdrCnt] = Addr & 0xff;
          CodeLen = 3 + AdrCnt;
        }
      }
    }
  }
}

static void DecodeIncDec(Word Code)
{
  static Byte Sizes[3] = {2, 0, 1};

  if (ChkArgCnt(1, 1))
  {
    SetOpSize(Sizes[(Code & 3) - 1]);
    if (DecodeAdr(&ArgStr[1], MModMem | MModReg))
    {
      BAsmCode[0] = 0x70 | (Code & 15);
      BAsmCode[1] = (Code & 0xf0) | AdrPart;
      memcpy(BAsmCode + 2, AdrVals, AdrCnt);
      CodeLen = 2 + AdrCnt;
    }
  }
}

static void DecodeMulDiv(Word Index)
{
  MulDivOrder *POrder = MulDivOrders + Index;

  if (ChkArgCnt(1, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    if (ArgCnt == 1)
    {
      if (POrder->AccCode == 0xfff) WrError(ErrNum_InvAddrMode);
      else
      {
        BAsmCode[CodeLen++] = Lo(POrder->AccCode);
        if (Hi(POrder->AccCode) != 0)
         BAsmCode[CodeLen++] = Hi(POrder->AccCode);
      }
    }
    else
    {
      SetOpSize((POrder->Code >> 5) & 1);
      if (DecodeAdr(&ArgStr[2], MModMem | MModReg))
      {
        BAsmCode[0] = 0x78;
        BAsmCode[1] = POrder->Code | AdrPart;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        CodeLen = 2 + AdrCnt;
      }
    }
  }
}

static void DecodeSeg(Word Code)
{
  if (ChkArgCnt(1, 1)
   && DecodeAdr(&ArgStr[1], MModSeg))
  {
    BAsmCode[0] = 0x6e;
    BAsmCode[1] = Code + AdrPart;
    CodeLen = 2;
  }
}

static void DecodeString(Word Code)
{
  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModSeg))
  {
    BAsmCode[1] = AdrPart << 2;
    if (DecodeAdr(&ArgStr[2], MModSeg))
    {
      BAsmCode[1] += Code + AdrPart;
      BAsmCode[0] = 0x6e;
      CodeLen = 2;
    }
  }
}

static void DecodeINT(Word Index)
{
  Boolean OK;
  LongWord Addr;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str == '#')
  {
    BAsmCode[1] = EvalStrIntExpressionOffs(&ArgStr[1], 1, UInt8, &OK);
    if (OK)
    {
      BAsmCode[0] = 0x68;
      CodeLen = 2;
    }
  }
  else
  {
    tSymbolFlags Flags;

    Addr = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt24, &OK, &Flags);
    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && ((Addr & 0xff0000) != 0xff0000))
        WrError(ErrNum_InAccPage);
      BAsmCode[0] = 0x69;
      BAsmCode[1] = Addr & 0xff;
      BAsmCode[2] = (Addr >> 8) & 0xff;
      CodeLen = 3;
    }
  }
}

static void DecodeINTP(Word Index)
{
  Boolean OK;
  LongWord Addr;
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
  {
    Addr = EvalStrIntExpression(&ArgStr[1], UInt24, &OK);
    if (OK)
    {
      BAsmCode[0] = 0x6a;
      BAsmCode[1] = Addr & 0xff;
      BAsmCode[2] = (Addr >> 8) & 0xff;
      BAsmCode[3] = (Addr >> 16) & 0xff;
      CodeLen = 4;
    }
  }
}

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

  if (!ChkArgCnt(1, 1));
  else if (*ArgStr[1].str.p_str != '@') WrError(ErrNum_InvAddrMode);
  else
  {
    tStrComp Arg1;

    StrCompRefRight(&Arg1, &ArgStr[1], 1);
    if (DecodeAdr(&Arg1, MModAcc))
    {
      BAsmCode[0] = 0x13;
      CodeLen = 1;
    }
  }
}

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

  if (ChkArgCnt(1, 1))
  {
    SetOpSize(0);
    if (DecodeAdr(&ArgStr[1], MModImm))
    {
      BAsmCode[0] = 0x08;
      BAsmCode[1] = AdrVals[0];
      CodeLen = 2;
    }
  }
}

static void DecodeMOV(Word Index)
{
  Byte HPart, HCnt;
  UNUSED(Index);

  if (!ChkArgCnt(2, 2));
  else if (((!as_strcasecmp(ArgStr[1].str.p_str, "@AL")) || (!as_strcasecmp(ArgStr[1].str.p_str, "@A")))
       && ((!as_strcasecmp(ArgStr[2].str.p_str, "AH" )) || (!as_strcasecmp(ArgStr[2].str.p_str, "T" ))))
  {
    BAsmCode[0] = 0x6f; BAsmCode[1] = 0x15;
    CodeLen = 2;
  }
  else
  {
    SetOpSize(0);
    DecodeAdr(&ArgStr[1], MModRP | MModILM | MModAcc | MModDir | MModRDisp | MModIO | MModSpec | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModRP:
      {
        if (DecodeAdr(&ArgStr[2], MModImm))
        {
          BAsmCode[0] = 0x0a;
          BAsmCode[1] = AdrVals[0];
          CodeLen = 2;
        }
        break;
      } /* 1 = ModRP */
      case ModILM:
      {
        if (DecodeAdr(&ArgStr[2], MModImm))
        {
          BAsmCode[0] = 0x1a;
          BAsmCode[1] = AdrVals[0];
          CodeLen = 2;
        }
        break;
      } /* 1 = ModILM */
      case ModAcc:
      {
        DecodeAdr(&ArgStr[2], MModImm | MModIAcc | MModRDisp | MModIO | MModMem | MModReg | MModDir | MModSpec);
        switch (AdrMode)
        {
          case ModImm:
            BAsmCode[0] = 0x42;
            BAsmCode[1] = AdrVals[0];
            CodeLen = 2;
            break;
          case ModIAcc:
            BAsmCode[0] = 0x6f;
            BAsmCode[1] = 0x05;
            CodeLen = 2;
            break;
          case ModRDisp:
            BAsmCode[0] = 0x6f;
            BAsmCode[1] = 0x40 | (AdrPart << 1);
            BAsmCode[2] = AdrVals[0];
            CodeLen = 3;
            break;
          case ModIO:
            BAsmCode[0] = 0x50;
            BAsmCode[1] = AdrVals[0];
            CodeLen = 2;
            break;
          case ModMem:
            if (AdrPart == ABSMODE) /* 16 bit absolute */
            {
              BAsmCode[0] = 0x52;
              CodeLen = 1;
            }
            else
            {
              BAsmCode[0] = 0x72;
              BAsmCode[1] = 0x80 + AdrPart;
              CodeLen = 2;
            }
            memcpy(BAsmCode + CodeLen, AdrVals, AdrCnt);
            CodeLen += AdrCnt;
            break;
          case ModReg:
            BAsmCode[0] = 0x80 | AdrPart;
            CodeLen = 1;
            break;
          case ModDir:
            BAsmCode[0] = 0x40;
            BAsmCode[1] = AdrVals[0];
            CodeLen = 2;
            break;
          case ModSpec:
            BAsmCode[0] = 0x6f;
            BAsmCode[1] = 0x00 + AdrPart;
            CodeLen = 2;
            break;
        }
        break;
      } /* 1 = ModAcc */
      case ModDir:
      {
        BAsmCode[1] = AdrVals[0];
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x41;
            CodeLen = 2;
            break;
          case ModImm:
            BAsmCode[0] = 0x44;
            BAsmCode[2] = AdrVals[0];
            CodeLen = 3;
            break;
          case ModReg:           /* extend to 16 bits */
            BAsmCode[0] = 0x7c;
            BAsmCode[2] = BAsmCode[1];
            BAsmCode[1] = (AdrPart << 5) | ABSMODE;
            BAsmCode[3] = Reg_DPR;
            CodeLen = 4;
            break;
        }
        break;
      } /* 1 = ModDir */
      case ModRDisp:
      {
        BAsmCode[2] = AdrVals[0];
        DecodeAdr(&ArgStr[2], MModAcc);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x6f;
            BAsmCode[1] = 0x30 | (AdrPart << 1);
            CodeLen = 3;
            break;
        }
        break;
      } /* 1 = ModRDisp */
      case ModIO:
      {
        BAsmCode[1] = AdrVals[0];
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x51;
            CodeLen = 2;
            break;
          case ModImm:
            BAsmCode[0] = 0x54;
            BAsmCode[2] = AdrVals[0];
            CodeLen = 3;
            break;
          case ModReg:           /* extend to 16 bits - will only work when in Bank 0 */
            BAsmCode[0] = 0x7c;
            BAsmCode[2] = BAsmCode[1];
            BAsmCode[1] = (AdrPart << 5) | ABSMODE;
            BAsmCode[3] = 0;
            if (CurrBank != 0) WrError(ErrNum_InAccPage);
            CodeLen = 4;
            break;
        }
        break;
      } /* 1 = ModIO */
      case ModSpec:
        if (AdrPart == 6) WrError(ErrNum_InvAddrMode);
        else
        {
          BAsmCode[1] = 0x10 + AdrPart;
          DecodeAdr(&ArgStr[2], MModAcc);
          switch (AdrMode)
          {
            case ModAcc:
              BAsmCode[0] = 0x6f;
              CodeLen = 2;
              break;
          }
        } /* 1 = ModSpec */
        break;
      case ModReg:
      {
        BAsmCode[0] = AdrPart;
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg | MModMem);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] += 0x90;
            CodeLen = 1;
            break;
          case ModImm:
            BAsmCode[0] += 0xa0;
            BAsmCode[1] = AdrVals[0];
            CodeLen = 2;
            break;
          case ModReg:
          case ModMem:
            BAsmCode[1] = (BAsmCode[0] << 5) | AdrPart;
            BAsmCode[0] = 0x7a;
            memcpy(BAsmCode + 2, AdrVals, AdrCnt);
            CodeLen = 2 + AdrCnt;
            break;
        }
        break;
      } /* 1 = ModReg */
      case ModMem:
      {
        HPart = AdrPart; HCnt = AdrCnt;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            if (HPart == ABSMODE)
            {
              memmove(BAsmCode + 1, BAsmCode + 2, 2);
              BAsmCode[0] = 0x53;
              CodeLen = 3;
            }
            else
            {
              BAsmCode[0] = 0x72;
              BAsmCode[1] = 0xa0 | HPart;
              CodeLen = 2 + HCnt;
            }
            break;
          case ModImm:
            BAsmCode[0] = 0x71;
            BAsmCode[1] = 0xc0 | HPart;
            BAsmCode[2 + HCnt] = AdrVals[0];
            CodeLen = 3 + HCnt;
            break;
          case ModReg:
            BAsmCode[0] = 0x7c;
            BAsmCode[1] = (AdrPart << 5) | HPart;
            CodeLen = 2 + HCnt;
        }
        break;
      } /* 1 = ModMem */
    }
  }
}

static void DecodeMOVB(Word Index)
{
  if (ChkArgCnt(2, 2))
  {
    if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
      Index = 2;
    else if (!as_strcasecmp(ArgStr[2].str.p_str, "A"))
      Index = 1;
    else
      WrError(ErrNum_InvAddrMode);
    if ((Index > 0)
     && SplitBit(&ArgStr[Index], BAsmCode + 1)
     && DecodeAdr(&ArgStr[Index], MModDir | MModIO | MModMem))
    {
      BAsmCode[0] = 0x6c;
      BAsmCode[1] += (2 - Index) << 5;
      switch (AdrMode)
      {
        case ModDir:
          BAsmCode[1] += 0x08;
          break;
        case ModMem:
          BAsmCode[1] += 0x18;
          if (AdrPart != ABSMODE)
          {
            WrError(ErrNum_InvAddrMode);
            AdrCnt = 0;
          }
          break;
      }
      memcpy(BAsmCode + 2, AdrVals, AdrCnt);
      CodeLen = 2 + AdrCnt;
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    SetOpSize(1);
    DecodeAdr(&ArgStr[1], MModAcc | MModReg);
    switch (AdrMode)
    {
      case ModAcc:
        if (DecodeAdr(&ArgStr[2], MModMem | MModReg))
        {
          BAsmCode[0] = 0x71;
          BAsmCode[1] = 0xe0 | AdrPart;
          memcpy(BAsmCode + 2, AdrVals, AdrCnt);
          CodeLen = 2 + AdrCnt;
        }
        break;
      case ModReg:
        BAsmCode[1] = AdrPart << 5;
        if (DecodeAdr(&ArgStr[2], MModMem | MModReg))
        {
          BAsmCode[0] = 0x79;
          BAsmCode[1] += AdrPart;
          memcpy(BAsmCode + 2, AdrVals, AdrCnt);
          CodeLen = 2 + AdrCnt;
        }
        break;
    }
  }
}

static void DecodeMOVL(Word Index)
{
  Byte HCnt;
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
  {
    SetOpSize(2);
    DecodeAdr(&ArgStr[1], MModAcc | MModMem | MModReg);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModMem | MModReg | MModImm);
        switch (AdrMode)
        {
          case ModImm:
            BAsmCode[0] = 0x4b;
            CopyVals(1);
            break;
          case ModReg:
          case ModMem:
            BAsmCode[0] = 0x71;
            BAsmCode[1] = 0x80 | AdrPart;
            CopyVals(2);
        }
        break;
      case ModReg:
      case ModMem:
        BAsmCode[1] = 0xa0 | AdrPart;
        HCnt = AdrCnt;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        if (DecodeAdr(&ArgStr[2], MModAcc))
        {
          BAsmCode[0] = 0x71;
          CodeLen = 2 + HCnt;
        }
        break;
    }
  }
}

static void DecodeMOVN(Word Index)
{
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    if (*ArgStr[2].str.p_str != '#') WrError(ErrNum_OnlyImmAddr);
    else
    {
      BAsmCode[0] = 0xd0 + EvalStrIntExpressionOffs(&ArgStr[2], 1, UInt4, &OK);
      if (OK)
       CodeLen = 1;
    }
  }
}

static void DecodeMOVW(Word Index)
{
  Byte HPart, HCnt;
  UNUSED(Index);

  if (!ChkArgCnt(2, 2));
  else if (((!as_strcasecmp(ArgStr[1].str.p_str, "@AL")) || (!as_strcasecmp(ArgStr[1].str.p_str, "@A")))
       && ((!as_strcasecmp(ArgStr[2].str.p_str, "AH" )) || (!as_strcasecmp(ArgStr[2].str.p_str, "T" ))))
  {
    BAsmCode[0] = 0x6f; BAsmCode[1] = 0x1d;
    CodeLen = 2;
  }
  else
  {
    SetOpSize(1);
    DecodeAdr(&ArgStr[1], MModAcc | MModRDisp | MModSP | MModDir | MModIO | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModAcc:
        DecodeAdr(&ArgStr[2], MModImm | MModIAcc | MModRDisp | MModSP | MModIO | MModMem | MModReg | MModDir);
        switch (AdrMode)
        {
          case ModImm:
            BAsmCode[0] = 0x4a;
            CopyVals(1);
            break;
          case ModIAcc:
            BAsmCode[0] = 0x6f;
            BAsmCode[1] = 0x0d;
            CodeLen = 2;
            break;
          case ModRDisp:
            BAsmCode[0] = 0x6f;
            BAsmCode[1] = 0x48 + (AdrPart << 1);
            CopyVals(2);
            break;
          case ModSP:
            BAsmCode[0] = 0x46;
            CodeLen = 1;
            break;
          case ModIO:
            BAsmCode[0] = 0x58;
            CopyVals(1);
            break;
          case ModDir:
            BAsmCode[0] = 0x48;
            CopyVals(1);
            break;
          case ModReg:
            BAsmCode[0] = 0x88 + AdrPart;
            CodeLen = 1;
            break;
          case ModMem:
            if (AdrPart == ABSMODE)
            {
              BAsmCode[0] = 0x5a;
              CopyVals(1);
            }
            else if ((AdrPart >= 0x10) && (AdrPart <= 0x17))
            {
              BAsmCode[0] = 0xa8 + AdrPart;
              CopyVals(1);
            }
            else
            {
              BAsmCode[0] = 0x73;
              BAsmCode[1] = 0x80 + AdrPart;
              CopyVals(2);
            }
            break;
        }
        break; /* 1 = ModAcc */
      case ModRDisp:
        BAsmCode[1] = 0x38 + (AdrPart << 1);
        BAsmCode[2] = AdrVals[0];
        if (DecodeAdr(&ArgStr[2], MModAcc))
        {
          BAsmCode[0] = 0x6f;
          CodeLen = 3;
        }
        break; /* 1 = ModRDisp */
      case ModSP:
        if (DecodeAdr(&ArgStr[2], MModAcc))
        {
          BAsmCode[0] = 0x47;
          CodeLen = 1;
        }
        break; /* 1 = ModSP */
      case ModDir:
        BAsmCode[1] = AdrVals[0];
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x49;
            CodeLen = 2;
            break;
          case ModImm:           /* extend to 16 bits */
            BAsmCode[0] = 0x73;
            BAsmCode[2] = BAsmCode[1];
            BAsmCode[1] = 0xc0 | ABSMODE;
            BAsmCode[3] = Reg_DPR;
            CopyVals(4);
            break;
          case ModReg:           /* extend to 16 bits */
            BAsmCode[0] = 0x7d;
            BAsmCode[2] = BAsmCode[1];
            BAsmCode[1] = (AdrPart << 5) | ABSMODE;
            BAsmCode[3] = Reg_DPR;
            CodeLen = 4;
            break;
        }
        break; /* 1 = ModDir */
      case ModIO:
        BAsmCode[1] = AdrVals[0];
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x59;
            CodeLen = 2;
            break;
          case ModImm:
            BAsmCode[0] = 0x56;
            CopyVals(1);
            break;
          case ModReg:           /* extend to 16 bits - will only work when in Bank 0 */
            BAsmCode[0] = 0x7d;
            BAsmCode[2] = BAsmCode[1];
            BAsmCode[1] = (AdrPart << 5) | ABSMODE;
            BAsmCode[3] = 0;
            if (CurrBank != 0) WrError(ErrNum_InAccPage);
            CodeLen = 4;
            break;
        }
        break; /* 1 = ModIO */
      case ModReg:
        HPart = AdrPart;
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg | MModMem);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x98 | HPart;
            CodeLen = 1;
            break;
          case ModImm:
            BAsmCode[0] = 0x98 | HPart;
            CopyVals(1);
            break;
          case ModReg:
          case ModMem:
            BAsmCode[0] = 0x7b;
            BAsmCode[1] = (HPart << 5) | AdrPart;
            CopyVals(2);
            break;
        }
        break; /* 1 = ModReg */
      case ModMem:
        HPart = AdrPart; HCnt = AdrCnt;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        DecodeAdr(&ArgStr[2], MModAcc | MModImm | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            if (HPart == ABSMODE)
            {
              BAsmCode[0] = 0x5b;
              memmove(BAsmCode + 1, BAsmCode + 2, HCnt);
              CodeLen = 1 + HCnt;
            }
            else if ((HPart >= 0x10) && (HPart <= 0x17))
            {
              BAsmCode[0] = 0xb8 + AdrPart;
              memmove(BAsmCode + 1, BAsmCode + 2, HCnt);
              CodeLen = 1 + HCnt;
            }
            else
            {
              BAsmCode[0] = 0x73;
              BAsmCode[1] = 0xa0 | AdrPart;
              CodeLen = 2 + HCnt;
            }
            break;
          case ModImm:
            BAsmCode[0] = 0x73;
            BAsmCode[1] = 0xc0 | HPart;
            CopyVals(2 + HCnt);
            break;
          case ModReg:
            BAsmCode[0] = 0x7d;
            BAsmCode[1] = (AdrPart << 5) | HPart;
            CodeLen = 2 + HCnt;
        }
        break; /* 1 = ModMem */
    }
  }
}

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

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    SetOpSize(0);
    DecodeAdr(&ArgStr[2], MModImm | MModIAcc | MModRDisp | MModDir | MModIO | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModImm:
        BAsmCode[0] = 0x43;
        CopyVals(1);
        break;
      case ModIAcc:
        BAsmCode[0] = 0x6f;
        BAsmCode[1] = 0x16;
        CodeLen = 2;
        break;
      case ModRDisp:
        BAsmCode[0] = 0x6f;
        BAsmCode[1] = 0x20 | (AdrPart << 1);
        CopyVals(2);
        break;
      case ModDir:
        BAsmCode[0] = 0x45;
        CopyVals(1);
        break;
      case ModIO:
        BAsmCode[0] = 0x55;
        CopyVals(1);
        break;
      case ModReg:
        BAsmCode[0] = 0xb0 + AdrPart;
        CodeLen = 1;
        break;
      case ModMem:
        if (AdrPart == ABSMODE)
        {
          BAsmCode[0] = 0x57;
          CopyVals(1);
        }
        else if ((AdrPart >= 0x10) && (AdrPart <= 0x17))
        {
          BAsmCode[0] = 0xb0 + AdrPart;
          CopyVals(1);
        }
        else
        {
          BAsmCode[0] = 0x72;
          BAsmCode[1] = 0xc0 | AdrPart;
          CopyVals(2);
        }
        break;
    }
  }
}

static void DecodeNEGNOT(Word Index)
{
  if (ChkArgCnt(1, 1))
  {
    SetOpSize((OpPart.str.p_str[3] == 'W') ? 1 : 0);
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModAcc:
        BAsmCode[0] = Lo(Index);
        CodeLen = 1;
        break;
      case ModReg:
      case ModMem:
        BAsmCode[0] = 0x75 + (OpSize << 1);
        BAsmCode[1] = Hi(Index) + AdrPart;
        CopyVals(2);
        break;
    }
  }
}

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

  if (ChkArgCnt(2, 2)
   && DecodeAdr(&ArgStr[1], MModAcc))
  {
    SetOpSize(0);
    if (DecodeAdr(&ArgStr[2], MModReg))
    {
      if (AdrPart != 0) WrError(ErrNum_InvAddrMode);
      else
      {
        BAsmCode[0] = 0x6f;
        BAsmCode[1] = 0x2d;
        CodeLen = 2;
      }
    }
  }
}

static void DecodeStack(Word Index)
{
  int z, z2;
  Byte HReg;
  char *p;

  if (!ChkArgCnt(1, ArgCntMax));
  else if ((ArgCnt == 1) && (!as_strcasecmp(ArgStr[1].str.p_str, "A")))
  {
    BAsmCode[0] = Index;
    CodeLen = 1;
  }
  else if ((ArgCnt == 1) && (!as_strcasecmp(ArgStr[1].str.p_str, "AH")))
  {
    BAsmCode[0] = Index + 1;
    CodeLen = 1;
  }
  else if ((ArgCnt == 1) && (!as_strcasecmp(ArgStr[1].str.p_str, "PS")))
  {
    BAsmCode[0] = Index + 2;
    CodeLen = 1;
  }
  else
  {
    tStrComp From, To;

    BAsmCode[1] = 0; SetOpSize(1);
    for (z = 1; z <= ArgCnt; z++)
     if ((p = strchr(ArgStr[z].str.p_str, '-')) != NULL)
     {
       StrCompSplitRef(&From, &To, &ArgStr[z], p);
       if (!DecodeAdr(&From, MModReg)) break;
       HReg = AdrPart;
       if (!DecodeAdr(&To, MModReg)) break;
       if (AdrPart >= HReg)
       {
         for (z2 = HReg; z2 <= AdrPart; z2++)
          BAsmCode[1] |= (1 << z2);
       }
       else
       {
         for (z2 = HReg; z2 <= 7; z2++)
          BAsmCode[1] |= (1 << z2);
         for (z2 = 0; z2 <= AdrPart; z2++)
          BAsmCode[1] |= (1 << z2);
       }
     }
     else
     {
       if (!DecodeAdr(&ArgStr[z], MModReg)) break;
       BAsmCode[1] |= (1 << AdrPart);
     }
    if (z > ArgCnt)
    {
      BAsmCode[0] = Index + 3;
      CodeLen = 2;
    }
  }
}

static void DecodeRotate(Word Index)
{
  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModAcc:
        BAsmCode[0] = 0x6f;
        BAsmCode[1] = 0x07 | (Index << 4);
        CodeLen = 2;
        break;
      case ModReg:
      case ModMem:
        BAsmCode[0] = 0x72;
        BAsmCode[1] = (Index << 5) | AdrPart;
        CopyVals(2);
        break;
    }
  }
}

static void DecodeSBBS(Word Index)
{
  LongInt Adr;
  Boolean OK;
  UNUSED(Index);

  if (ChkArgCnt(2, 2)
   && SplitBit(&ArgStr[1], BAsmCode + 1)
   && DecodeAdr(&ArgStr[1], MModMem))
  {
    if (AdrPart != ABSMODE) WrError(ErrNum_InvAddrMode);
    else
    {
      tSymbolFlags Flags;

      Adr = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt24, &OK, &Flags) - (EProgCounter() + 5);
      if (OK)
      {
        if (!mSymbolQuestionable(Flags) && ((Adr < -128) || (Adr > 127))) WrError(ErrNum_JmpDistTooBig);
        else
        {
          BAsmCode[0] = 0x6c;
          BAsmCode[1] += 0xf8;
          CopyVals(2);
          BAsmCode[CodeLen++] = Adr & 0xff;
        }
      }
    }
  }
}

static void DecodeWBit(Word Index)
{
  if (ChkArgCnt(1, 1)
   && SplitBit(&ArgStr[1], BAsmCode + 1)
   && DecodeAdr(&ArgStr[1], MModIO))
  {
    BAsmCode[0] = 0x6c;
    BAsmCode[1] += Index;
    CopyVals(2);
  }
}

static void DecodeExchange(Word Index)
{
  Byte HPart, HCnt;

  if (ChkArgCnt(2, 2))
  {
    SetOpSize(Index);
    DecodeAdr(&ArgStr[1], MModAcc | MModReg | MModMem);
    switch (AdrMode)
    {
      case ModAcc:
        if (DecodeAdr(&ArgStr[2], MModReg | MModMem))
        {
          BAsmCode[0] = 0x72 + Index;
          BAsmCode[1] = 0xe0 | AdrPart;
          CopyVals(2);
        }
        break;
      case ModReg:
        HPart = AdrPart;
        DecodeAdr(&ArgStr[2], MModAcc | MModReg | MModMem);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x72 + Index;
            BAsmCode[1] = 0xe0 | HPart;
            CodeLen = 2;
            break;
          case ModReg:
          case ModMem:
            BAsmCode[0] = 0x7e + Index;
            BAsmCode[1] = (HPart << 5) | AdrPart;
            CopyVals(2);
            break;
        }
        break;
      case ModMem:
        HPart = AdrPart; HCnt = AdrCnt;
        memcpy(BAsmCode + 2, AdrVals, AdrCnt);
        DecodeAdr(&ArgStr[2], MModAcc | MModReg);
        switch (AdrMode)
        {
          case ModAcc:
            BAsmCode[0] = 0x72 + Index;
            BAsmCode[1] = 0xe0 | HPart;
            CodeLen = 2 + HCnt;
            break;
         case ModReg:
            BAsmCode[0] = 0x7e + Index;
            BAsmCode[1] = (AdrPart << 5) | HPart;
            CodeLen = 2 + HCnt;
            break;
        }
        break;
    }
  }
}

static void DecodeBank(Word Index)
{
  if (ChkArgCnt(0, 0))
  {
    BAsmCode[0] = Index + 4;
    CodeLen = 1;
    NextDataSeg = Index;
  }
}

/*!------------------------------------------------------------------------
 * \fn     propagate_bank(Word index)
 * \brief  things to perform prior to machine instruction
 * ------------------------------------------------------------------------ */

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

  /* current data segment: */

  switch (NextDataSeg)
  {
    case 0:
      CurrBank = Reg_PCB;
      break;
    case 1:
      CurrBank = Reg_DTB;
      break;
    case 2:
      CurrBank = Reg_ADB;
      break;
    case 3:
      CurrBank = SupAllowed ? Reg_SSB : Reg_USB;
      break;
  }
  CurrBank <<= 16;
  NextDataSeg = 1; /* = DTB */
}

/*--------------------------------------------------------------------------*/
/* Codetabellen */

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

static void AddALU8(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeALU8);
}

static void AddLog8(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeLog8);
}

static void AddAcc(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeAcc);
}

static void AddShift(const char *NName, Word NCode, Word NMay)
{
  AddInstTable(InstTable, NName, NCode | (NMay << 8), DecodeShift);
}

static void AddBranch(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeBranch);
}

static void AddIncDec(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeIncDec);
}

static void AddMulDiv(const char *NName, Byte NCode, Word NAccCode)
{
  MulDivOrders[InstrZ].Code = NCode;
  MulDivOrders[InstrZ].AccCode = NAccCode;
  AddInstTable(InstTable, NName, InstrZ++, DecodeMulDiv);
}

static void AddSeg(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeSeg);
}

static void AddString(const char *NName, Byte NCode)
{
  AddInstTable(InstTable, NName, NCode, DecodeString);
}

static void InitFields(void)
{
  unsigned z;

  InstTable = CreateInstTable(201);

  add_null_pseudo(InstTable);

  inst_table_set_prefix_proc(InstTable, propagate_bank, 0);

  AddFixed("EXT"    , 0x14); AddFixed("EXTW"   , 0x1c);
  AddFixed("INT9"   , 0x01); AddFixed("NOP"    , 0x00);
  AddFixed("RET"    , 0x67); AddFixed("RETI"   , 0x6b);
  AddFixed("RETP"   , 0x66); AddFixed("SWAP"   , 0x16);
  AddFixed("SWAPW"  , 0x1e); AddFixed("UNLINK" , 0x09);
  AddFixed("ZEXT"   , 0x15); AddFixed("ZEXTW"  , 0x1d);
  AddFixed("CMR"    , 0x10); AddFixed("NCC"    , 0x11);

  AddALU8("ADD"  , 0); AddALU8("SUB"  , 1);

  AddLog8("AND"  , 4); AddLog8("OR"   , 5);
  AddLog8("XOR"  , 6);

  AddAcc("ADDDC"  , 0x02);
  AddAcc("SUBDC"  , 0x12);

  AddShift("ASR"  , 0x2e, FALSE); AddShift("ASRL" , 0x1e, FALSE);
  AddShift("ASRW" , 0x0e, TRUE ); AddShift("LSLW" , 0x0c, TRUE );
  AddShift("LSRW" , 0x0f, TRUE ); AddShift("LSL"  , 0x2c, FALSE);
  AddShift("LSR"  , 0x2f, FALSE); AddShift("LSLL" , 0x1c, FALSE);
  AddShift("LSRL" , 0x1f, FALSE); AddShift("SHLW" , 0x0c, TRUE );
  AddShift("SHRW" , 0x0f, TRUE );

  AddBranch("BZ"  , 0xf0); AddBranch("BEQ" , 0xf0); AddBranch("BNZ" , 0xf1);
  AddBranch("BNE" , 0xf1); AddBranch("BC"  , 0xf2); AddBranch("BLO" , 0xf2);
  AddBranch("BNC" , 0xf3); AddBranch("BHS" , 0xf3); AddBranch("BN"  , 0xf4);
  AddBranch("BP"  , 0xf5); AddBranch("BV"  , 0xf6); AddBranch("BNV" , 0xf7);
  AddBranch("BT"  , 0xf8); AddBranch("BNT" , 0xf9); AddBranch("BLT" , 0xfa);
  AddBranch("BGE" , 0xfb); AddBranch("BLE" , 0xfc); AddBranch("BGT" , 0xfd);
  AddBranch("BLS" , 0xfe); AddBranch("BHI" , 0xff); AddBranch("BRA" , 0x60);

  AddIncDec("INC"  , 0x42); AddIncDec("INCW" , 0x43); AddIncDec("INCL" , 0x41);
  AddIncDec("DEC"  , 0x62); AddIncDec("DECW" , 0x63); AddIncDec("DECL" , 0x61);

  MulDivOrders = (MulDivOrder*) malloc(sizeof(MulDivOrder) * MulDivOrderCnt);
  InstrZ = 0;
  AddMulDiv("MULU", 0x00, 0x0027); AddMulDiv("MULUW", 0x20, 0x002f);
  AddMulDiv("MUL" , 0x40, 0x786f); AddMulDiv("MULW" , 0x60, 0x796f);
  AddMulDiv("DIVU", 0x80, 0x0026); AddMulDiv("DIVUW", 0xa0, 0xffff);
  AddMulDiv("DIV" , 0xc0, 0x7a6f); AddMulDiv("DIVW" , 0xe0, 0xffff);

  AddSeg("SCEQI" , 0x80); AddSeg("SCEQD" , 0x90);
  AddSeg("SCWEQI", 0xa0); AddSeg("SCWEQD", 0xb0);
  AddSeg("FILSI" , 0xc0); AddSeg("FILS"  , 0xc0);
  AddSeg("FILSWI", 0xe0); AddSeg("FILSW" , 0xe0);
  AddSeg("SCEQ"  , 0x80); AddSeg("SCWEQ" , 0xa0);

  AddString("MOVS" , 0x00); AddString("MOVSI" , 0x00); AddString("MOVSD" , 0x10);
  AddString("MOVSW", 0x20); AddString("MOVSWI", 0x20); AddString("MOVSWD", 0x30);

  for (z = 0; z < (int)sizeof(BankNames) / sizeof(*BankNames); z++)
    AddInstTable(InstTable, BankNames[z], z, DecodeBank);

  AddInstTable(InstTable, "ADDC", 0, DecodeCarry8);
  AddInstTable(InstTable, "SUBC", 1, DecodeCarry8);
  AddInstTable(InstTable, "ADDCW",0, DecodeCarry16);
  AddInstTable(InstTable, "SUBCW",1, DecodeCarry16);
  AddInstTable(InstTable, "ADDL", 0, DecodeAdd32);
  AddInstTable(InstTable, "SUBL", 1, DecodeAdd32);
  AddInstTable(InstTable, "CMPL", 3, DecodeAdd32);
  AddInstTable(InstTable, "ADDSP",0, DecodeADDSP);
  AddInstTable(InstTable, "ADDW", 0, DecodeAdd16);
  AddInstTable(InstTable, "SUBW", 1, DecodeAdd16);
  AddInstTable(InstTable, "CMPW", 3, DecodeAdd16);
  AddInstTable(InstTable, "ANDW", 4, DecodeAdd16);
  AddInstTable(InstTable, "ORW" , 5, DecodeAdd16);
  AddInstTable(InstTable, "XORW", 6, DecodeAdd16);
  AddInstTable(InstTable, "ANDL", 4, DecodeLog32);
  AddInstTable(InstTable, "ORL",  5, DecodeLog32);
  AddInstTable(InstTable, "XORL", 6, DecodeLog32);
  AddInstTable(InstTable, "BBC", 0x80, DecodeBBcc);
  AddInstTable(InstTable, "BBS", 0xa0, DecodeBBcc);
  AddInstTable(InstTable, "CALL", 2, DecodeJmp16);
  AddInstTable(InstTable, "JMP", 0, DecodeJmp16);
  AddInstTable(InstTable, "CALLP", 2, DecodeJmp24);
  AddInstTable(InstTable, "JMPP", 0, DecodeJmp24);
  AddInstTable(InstTable, "CALLV", 0, DecodeCALLV);
  AddInstTable(InstTable, "CBNE", 0, DecodeCmpBranch);
  AddInstTable(InstTable, "CWBNE", 1, DecodeCmpBranch);
  AddInstTable(InstTable, "CLRB", 0x40, DecodeBit);
  AddInstTable(InstTable, "SETB", 0x60, DecodeBit);
  AddInstTable(InstTable, "CMP" , 0, DecodeCMP);
  AddInstTable(InstTable, "DBNZ" , 0, DecodeDBNZ);
  AddInstTable(InstTable, "DWBNZ" , 1, DecodeDBNZ);
  AddInstTable(InstTable, "INT", 0, DecodeINT);
  AddInstTable(InstTable, "INTP", 0, DecodeINTP);
  AddInstTable(InstTable, "JCTX", 0, DecodeJCTX);
  AddInstTable(InstTable, "LINK", 0, DecodeLINK);
  AddInstTable(InstTable, "MOV", 0, DecodeMOV);
  AddInstTable(InstTable, "MOVB", 0, DecodeMOVB);
  AddInstTable(InstTable, "MOVEA", 0, DecodeMOVEA);
  AddInstTable(InstTable, "MOVL", 0, DecodeMOVL);
  AddInstTable(InstTable, "MOVN", 0, DecodeMOVN);
  AddInstTable(InstTable, "MOVW", 0, DecodeMOVW);
  AddInstTable(InstTable, "MOVX", 0, DecodeMOVX);
  AddInstTable(InstTable, "NOT" , 0xe037, DecodeNEGNOT);
  AddInstTable(InstTable, "NEG" , 0x6003, DecodeNEGNOT);
  AddInstTable(InstTable, "NOTW", 0xe03f, DecodeNEGNOT);
  AddInstTable(InstTable, "NEGW", 0x600b, DecodeNEGNOT);
  AddInstTable(InstTable, "NRML", 0, DecodeNRML);
  AddInstTable(InstTable, "PUSHW", 0x40, DecodeStack);
  AddInstTable(InstTable, "POPW", 0x50, DecodeStack);
  AddInstTable(InstTable, "ROLC", 0, DecodeRotate);
  AddInstTable(InstTable, "RORC", 1, DecodeRotate);
  AddInstTable(InstTable, "SBBS", 1, DecodeSBBS);
  AddInstTable(InstTable, "WBTS", 0xc0, DecodeWBit);
  AddInstTable(InstTable, "WBTC", 0xe0, DecodeWBit);
  AddInstTable(InstTable, "XCH", 0, DecodeExchange);
  AddInstTable(InstTable, "XCHW", 1, DecodeExchange);

  inst_table_set_prefix_proc(InstTable, NULL, 0);
  AddIntelPseudo(InstTable, eIntPseudoFlag_LittleEndian);
}

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

/*--------------------------------------------------------------------------*/
/* Interface zu AS */

static void MakeCode_F2MC16(void)
{
  OpSize = eSymbolSizeUnknown;

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

static Boolean IsDef_F2MC16(void)
{
  return FALSE;
}

static void InitCode_F2MC16(void)
{
  Reg_PCB = 0xff;
  Reg_DTB = 0x00;
  Reg_USB = 0x00;
  Reg_SSB = 0x00;
  Reg_ADB = 0x00;
  Reg_DPR = 0x01;
}

static void SwitchTo_F2MC16(void)
{
  const TFamilyDescr *FoundDescr;

  FoundDescr = FindFamilyByName("F2MC16");

  TurnWords = False;
  SetIntConstMode(eIntConstModeIntel);

  PCSymbol = "$";
  HeaderID = FoundDescr->Id;
  NOPCode=0x00;
  DivideChars = ",";
  HasAttrs = False;

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

  MakeCode = MakeCode_F2MC16;
  IsDef = IsDef_F2MC16;
  SwitchFrom = DeinitFields;
  InitFields();

  onoff_supmode_add();

  assume_set(ASSUMEF2MC16s, as_array_size(ASSUMEF2MC16s));

  NextDataSeg = 1; /* DTB */
}

/*--------------------------------------------------------------------------*/
/* Initialisierung */

void codef2mc16_init(void)
{
  CPU90500 = AddCPU("MB90500", SwitchTo_F2MC16);

  AddInitPassProc(InitCode_F2MC16);
}
