Top secrets sources NedoPC pentevo

Rev

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

/* code85.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator 8080/8085                                                   */
/*                                                                           */
/*****************************************************************************/

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

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

#include "code85.h"

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

typedef enum
{
  ModNone = 0xff,
  ModReg8 = 0,
  ModReg16 = 1,
  ModIReg16 = 2,
  ModAbs = 3,
  ModImm = 4,
  ModIM = 5
} tAdrMode;

#define MModReg8 (1 << ModReg8)
#define MModReg16 (1 << ModReg16)
#define MModIReg16 (1 << ModIReg16)
#define MModAbs (1 << ModAbs)
#define MModImm (1 << ModImm)
#define MModIM (1 << ModIM)

static CPUVar CPU8080, CPUV30EMU, CPU8085, CPU8085U;
static tAdrMode AdrMode;
static Byte AdrVals[2], OpSize;

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

static const Byte AccReg = 7;

static Boolean DecodeReg8(const char *Asc, tZ80Syntax Syntax, Byte *Erg)
{
  static const char RegNames[] = "BCDEHLMA";
  const char *p;

  if (strlen(Asc) != 1) return False;
  else
  {
    p = strchr(RegNames, as_toupper(*Asc));
    if (!p) return False;
    else
    {
      *Erg = p - RegNames;
      if ((!(Syntax & eSyntax808x)) && (*Erg == 6))
        return False;
      return True;
    }
  }
}

static const Byte BCReg = 0;
static const Byte DEReg = 1;
static const Byte HLReg = 2;
static const Byte SPReg = 3;

static Boolean DecodeReg16(char *pAsc, tZ80Syntax Syntax, Byte *pResult)
{
  static const char RegNames[8][3] = { "B", "D", "H", "SP", "BC", "DE", "HL", "SP" };

  for (*pResult = (Syntax & eSyntax808x) ? 0 : 4;
       *pResult < ((Syntax & eSyntaxZ80) ? 8 : 4);
       (*pResult)++)
    if (!as_strcasecmp(pAsc, RegNames[*pResult]))
    {
      *pResult &= 3;
      break;
    }

  return ((*pResult) < 4);
}

static const char Conditions[][4] =
{
  "NZ", "Z", "NC", "C", "PO", "PE", "P", "M", "NX5", "X5"
};

static Boolean DecodeCondition(const char *pAsc, Byte *pResult, Boolean WithX5)
{
  int ConditionCnt = sizeof(Conditions) / sizeof(*Conditions);

  if (!WithX5 || (MomCPU!= CPU8085U))
    ConditionCnt -= 2;
  for (*pResult = 0; *pResult < ConditionCnt; (*pResult)++)
    if (!as_strcasecmp(pAsc, Conditions[*pResult]))
    {
      *pResult = (*pResult < 8) ? (*pResult << 3) : (0x1b + ((*pResult & 1) << 5));
      return True;
    }
  return False;
}

static void DecodeAdr_Z80(tStrComp *pArg, Word Mask)
{
  Boolean OK;
  int ArgLen = strlen(pArg->str.p_str);

  AdrMode = ModNone; AdrCnt = 0;

  if (DecodeReg8(pArg->str.p_str, eSyntaxZ80, &AdrVals[0]))
  {
    AdrMode = ModReg8;
    goto AdrFound;
  }

  if ((Mask & MModIM) && !as_strcasecmp(pArg->str.p_str, "IM"))
  {
    AdrMode = ModIM;
    goto AdrFound;
  }

  if ((ArgLen == 2) && DecodeReg16(pArg->str.p_str, eSyntaxZ80, &AdrVals[0]))
  {
    AdrMode = ModReg16;
    OpSize = 1;
    goto AdrFound;
  }

  if (IsIndirect(pArg->str.p_str))
  {
    tStrComp IArg;

    StrCompRefRight(&IArg, pArg, 1);
    StrCompShorten(&IArg, 1);

    if (DecodeReg16(IArg.str.p_str, eSyntaxZ80, &AdrVals[0]))
    {
      AdrMode = ModIReg16;
      goto AdrFound;
    }
    else
    {
      Word Addr = EvalStrIntExpression(&IArg, UInt16, &OK);

      if (OK)
      {
        AdrVals[0] = Lo(Addr);
        AdrVals[1] = Hi(Addr);
        AdrMode = ModAbs;
      }
    }
  }
  else if (OpSize)
  {
    Word Val = EvalStrIntExpression(pArg, Int16, &OK);

    if (OK)
    {
      AdrVals[0] = Lo(Val);
      AdrVals[1] = Hi(Val);
      AdrMode = ModImm;
    }
  }
  else
  {
    AdrVals[0] = EvalStrIntExpression(pArg, Int8, &OK);
    if (OK)
      AdrMode = ModImm;
  }

AdrFound:

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

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

/* Anweisungen ohne Operanden */

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

/* ein 16-Bit-Operand */

static void DecodeOp16(Word Code)
{
  if (ChkArgCnt(1, 1)
   && ChkZ80Syntax((tZ80Syntax)Hi(Code)))
  {
    tEvalResult EvalResult;
    Word AdrWord = EvalStrIntExpressionWithResult(&ArgStr[1], Int16, &EvalResult);

    if (EvalResult.OK)
    {
      CodeLen = 3;
      BAsmCode[0] = Lo(Code);
      BAsmCode[1] = Lo(AdrWord);
      BAsmCode[2] = Hi(AdrWord);
      ChkSpace(SegCode, EvalResult.AddrSpaceMask);
    }
  }
}

static void DecodeOp8(Word Code)
{
  Boolean OK;
  Byte AdrByte;

  if (ChkArgCnt(1, 1)
   && ChkZ80Syntax((tZ80Syntax)Hi(Code)))
  {
    AdrByte = EvalStrIntExpression(&ArgStr[1], Int8, &OK);
    if (OK)
    {
      CodeLen = 2;
      BAsmCode[0] = Lo(Code);
      BAsmCode[1] = AdrByte;
    }
  }
}

static void DecodeALU(Word Code)
{
  Byte Reg;

  if (!ChkArgCnt(1, 1));
  else if (!ChkZ80Syntax((tZ80Syntax)Hi(Code)));
  else if (!DecodeReg8(ArgStr[1].str.p_str, (tZ80Syntax)Hi(Code), &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
  else
  {
    CodeLen = 1;
    BAsmCode[0] = Code + Reg;
  }
}

static void DecodeMOV(Word Index)
{
  Byte Dest;

  UNUSED(Index);

  if (!ChkArgCnt(2,  2));
  else if (!ChkZ80Syntax(eSyntax808x));
  else if (!DecodeReg8(ArgStr[1].str.p_str, eSyntax808x, &Dest)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
  else if (!DecodeReg8(ArgStr[2].str.p_str, eSyntax808x, BAsmCode + 0)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[2]);
  else
  {
    BAsmCode[0] += 0x40 + (Dest << 3);
    if (BAsmCode[0] == 0x76)
      WrError(ErrNum_InvRegPair);
    else
      CodeLen = 1;
  }
}

static void DecodeMVI(Word Index)
{
  Boolean OK;
  Byte Reg;

  UNUSED(Index);

  if (ChkArgCnt(2, 2)
   && ChkZ80Syntax(eSyntax808x))
  {
    BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
    if (OK)
    {
      if (!DecodeReg8(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
      else
      {
        BAsmCode[0] = 0x06 + (Reg << 3);
        CodeLen = 2;
      }
    }
  }
}

static void DecodeLXI(Word Index)
{
  Boolean OK;
  Word AdrWord;
  Byte Reg;

  UNUSED(Index);

  if (ChkArgCnt(2, 2)
   && ChkZ80Syntax(eSyntax808x))
  {
    AdrWord = EvalStrIntExpression(&ArgStr[2], Int16, &OK);
    if (OK)
    {
      if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
      else
      {
        BAsmCode[0] = 0x01 + (Reg << 4);
        BAsmCode[1] = Lo(AdrWord);
        BAsmCode[2] = Hi(AdrWord);
        CodeLen = 3;
      }
    }
  }
}

static void DecodeLDAX_STAX(Word Index)
{
  Byte Reg;

  if (!ChkArgCnt(1, 1));
  else if (!ChkZ80Syntax(eSyntax808x));
  else if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
  else
  {
    switch (Reg)
    {
      case 3:                             /* SP */
        WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
        break;
      case 2:                             /* H --> MOV A,M oder M,A */
        CodeLen = 1;
        BAsmCode[0] = 0x77 + (Index * 7);
        break;
      default:
        CodeLen = 1;
        BAsmCode[0] = 0x02 + (Reg << 4) + (Index << 3);
        break;
    }
  }
}

static void DecodePUSH_POP(Word Index)
{
  Byte Reg = 0;
  Boolean OK = False;

  if (ChkArgCnt(1, 1))
  {
    if (!as_strcasecmp(ArgStr[1].str.p_str, "PSW"))
    {
      if (ChkZ80Syntax(eSyntax808x))
      {
        Reg = 3;
        OK = True;
      }
    }
    else if (!as_strcasecmp(ArgStr[1].str.p_str, "AF"))
    {
      if (ChkZ80Syntax(eSyntaxZ80))
      {
        Reg = 3;
        OK = True;
      }
    }
    else if (DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg))
      OK = (Reg != 3);
    else
      OK = False;
    if (!OK) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
    else
    {
      CodeLen = 1;
      BAsmCode[0] = 0xc1 + (Reg << 4) + Index;
    }
  }
}

static void DecodeRST(Word Index)
{
  Byte AdrByte;
  Boolean OK;

  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if ((MomCPU >= CPU8085U) && (!as_strcasecmp(ArgStr[1].str.p_str, "V")))
  {
    if (ChkZ80Syntax(eSyntaxZ80))
    {
      CodeLen = 1;
      BAsmCode[0] = 0xcb;
    }
  }
  else
  {
    tSymbolFlags Flags;

    AdrByte = EvalStrIntExpressionWithFlags(&ArgStr[1], (CurrZ80Syntax & eSyntaxZ80) ? UInt6 : UInt3, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      AdrByte = 0;
    if (OK)
    {
      tZ80Syntax Syntax = (CurrZ80Syntax == eSyntaxBoth) ? ((AdrByte < 8) ? eSyntax808x : eSyntaxZ80): CurrZ80Syntax;

      if (Syntax == eSyntax808x)
        BAsmCode[CodeLen++] = 0xc7 + (AdrByte << 3);
      else if (AdrByte & 7)
        WrStrErrorPos(ErrNum_NotAligned, &ArgStr[1]);
      else
        BAsmCode[CodeLen++] = 0xc7 + (AdrByte & 0x38);
    }
  }
}

static void DecodeINR_DCR(Word Index)
{
  Byte Reg;

  if (!ChkArgCnt(1, 1));
  else if (!ChkZ80Syntax(eSyntax808x));
  else if (!DecodeReg8(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
  else
  {
    CodeLen = 1;
    BAsmCode[0] = 0x04 + (Reg << 3) + Index;
  }
}

static void DecodeINX_DCX(Word Index)
{
  Byte Reg;

  if (!ChkArgCnt(1, 1));
  else if (!ChkZ80Syntax(eSyntax808x));
  else if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
  else
  {
    CodeLen = 1;
    BAsmCode[0] = 0x03 + (Reg << 4) + Index;
  }
}

static void DecodeDAD(Word Index)
{
  Byte Reg;

  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (!ChkZ80Syntax(eSyntax808x));
  else if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
  else
  {
    CodeLen = 1;
    BAsmCode[0] = 0x09 + (Reg << 4);
  }
}

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

  if (ChkArgCnt(0, 1) && ChkMinCPU(CPU8085U) && ChkZ80Syntax(eSyntax808x))
  {
    Byte Reg;

    if ((ArgCnt == 1)
     && (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg) || (Reg != BCReg))) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
    else
    {
      CodeLen = 1;
      BAsmCode[0] = 0x08;
    }
  }
}

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

  if (ChkArgCnt(0, 1) && ChkMinCPU(CPU8085U) && ChkZ80Syntax(eSyntax808x))
  {
    Byte Reg;

    if ((ArgCnt == 1)
     && (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg) || (Reg != DEReg))) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
    else
    {
      CodeLen = 1;
      BAsmCode[0] = Index ? 0xed: 0xd9;
    }
  }
}

static void DecodeLD(Word Code)
{
  Byte HVals[2];
  Word Mask;
  UNUSED(Code);

  if (ChkArgCnt(2, 2)
   && ChkZ80Syntax(eSyntaxZ80))
  {
    Mask = MModReg8 | MModIReg16 | MModAbs | MModReg16;
    if (MomCPU >= CPU8085)
      Mask |= MModIM;
    DecodeAdr_Z80(&ArgStr[1], Mask);
    switch (AdrMode)
    {
      case ModReg8:
        HVals[0] = AdrVals[0];
        Mask = MModReg8 | MModIReg16 | MModImm;
        if (HVals[0] == AccReg)
        {
          Mask |= MModAbs;
          if (MomCPU >= CPU8085)
            Mask |= MModIM;
        }
        DecodeAdr_Z80(&ArgStr[2], Mask);
        switch (AdrMode)
        {
          case ModReg8:
            BAsmCode[CodeLen++] = 0x40 | (HVals[0] << 3) | AdrVals[0];
            break;
          case ModIReg16:
            if (AdrVals[0] == HLReg)
              BAsmCode[CodeLen++] = 0x46 | (HVals[0] << 3);
            else if ((HVals[0] == AccReg) && (AdrVals[0] != SPReg))
              BAsmCode[CodeLen++] = 0x0a | (AdrVals[0] << 4);
            else
              WrError(ErrNum_InvAddrMode);
            break;
          case ModAbs:
            BAsmCode[CodeLen++] = 0x3a;
            BAsmCode[CodeLen++] = AdrVals[0];
            BAsmCode[CodeLen++] = AdrVals[1];
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0x06 | (HVals[0] << 3);
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModIM:
            BAsmCode[CodeLen++] = 0x20;
            break;
          default:
            break;
        }
        break;
      case ModReg16:
      {
        Byte Dest = AdrVals[0];
        Word Mask = MModImm;

        if (Dest == HLReg)
        {
          Mask |= MModAbs;
          if (MomCPU == CPU8085U)
            Mask |= MModIReg16;
        }
        if (Dest == SPReg)
          Mask |= MModReg16;
        DecodeAdr_Z80(&ArgStr[2], Mask);
        switch (AdrMode)
        {
          case ModImm:
            BAsmCode[CodeLen++] = 0x01 | (Dest << 4);
            BAsmCode[CodeLen++] = AdrVals[0];
            BAsmCode[CodeLen++] = AdrVals[1];
            break;
          case ModAbs:
            BAsmCode[CodeLen++] = 0x2a;
            BAsmCode[CodeLen++] = AdrVals[0];
            BAsmCode[CodeLen++] = AdrVals[1];
            break;
          case ModReg16:
            if (AdrVals[0] == HLReg)
              BAsmCode[CodeLen++] = 0xf9;
            else
              WrError(ErrNum_InvAddrMode);
            break;
          case ModIReg16:
            if (AdrVals[0] == DEReg)
              BAsmCode[CodeLen++] = 0xed;
            else
              WrError(ErrNum_InvAddrMode);
            break;
          default:
            break;
        }
        break;
      }
      case ModIReg16:
      {
        Byte Dest = AdrVals[0];
        Word Mask = MModReg8;

        if (Dest == HLReg)
          Mask |= MModImm;
        if ((Dest == DEReg) && (MomCPU == CPU8085U))
          Mask |= MModReg16;
        DecodeAdr_Z80(&ArgStr[2], Mask);
        switch (AdrMode)
        {
          case ModReg8:
            if (Dest == HLReg)
              BAsmCode[CodeLen++] = 0x70 | AdrVals[0];
            else if ((AdrVals[0] == AccReg) && (Dest != SPReg))
              BAsmCode[CodeLen++] = 0x02 | (Dest << 4);
            else
              WrError(ErrNum_InvAddrMode);
            break;
          case ModImm:
            BAsmCode[CodeLen++] = 0x36;
            BAsmCode[CodeLen++] = AdrVals[0];
            break;
          case ModReg16:
            if (AdrVals[0] == HLReg)
              BAsmCode[CodeLen++] = 0xd9;
            else
              WrError(ErrNum_InvAddrMode);
            break;
          default:
            break;
        }
        break;
      }
      case ModAbs:
        HVals[0] = AdrVals[0];
        HVals[1] = AdrVals[1];
        DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModReg16);
        switch (AdrMode)
        {
          case ModReg8:
            if (AdrVals[0] != AccReg) WrError(ErrNum_InvAddrMode);
            else
            {
              BAsmCode[CodeLen++] = 0x32;
              BAsmCode[CodeLen++] = HVals[0];
              BAsmCode[CodeLen++] = HVals[1];
            }
            break;
          case ModReg16:
            if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
            else
            {
              BAsmCode[CodeLen++] = 0x22;
              BAsmCode[CodeLen++] = HVals[0];
              BAsmCode[CodeLen++] = HVals[1];
            }
            break;
          default:
            break;
        }
        break;
      case ModIM:
        DecodeAdr_Z80(&ArgStr[2], MModReg8);
        switch (AdrMode)
        {
          case ModReg8:
            if (AdrVals[0] != AccReg) WrError(ErrNum_InvAddrMode);
            else
              BAsmCode[CodeLen++] = 0x30;
            break;
          default:
            break;
        }
        break;
      default:
        break;
    }
  }
}

static void DecodeEX(Word Code)
{
  Byte HVal;

  UNUSED(Code);

  if (ChkArgCnt(2, 2)
   && ChkZ80Syntax(eSyntaxZ80))
  {
    DecodeAdr_Z80(&ArgStr[1], MModReg16 | MModIReg16);
    switch (AdrMode)
    {
      case ModReg16:
        HVal = AdrVals[0];
        DecodeAdr_Z80(&ArgStr[2], MModReg16 | MModIReg16);
        switch (AdrMode)
        {
          case ModReg16:
            if (((HVal == DEReg) && (AdrVals[0] == HLReg))
             || ((HVal == HLReg) && (AdrVals[0] == DEReg)))
              BAsmCode[CodeLen++] = 0xeb;
            else
              WrError(ErrNum_InvAddrMode);
            break;
          case ModIReg16:
            if ((HVal == HLReg) && (AdrVals[0] == SPReg))
              BAsmCode[CodeLen++] = 0xe3;
            else
              WrError(ErrNum_InvAddrMode);
            break;
          default:
            break;
        }
        break;
      case ModIReg16:
        HVal = AdrVals[0];
        DecodeAdr_Z80(&ArgStr[2], MModReg16);
        switch (AdrMode)
        {
          case ModReg16:
            if ((HVal == SPReg) && (AdrVals[0] == HLReg))
              BAsmCode[CodeLen++] = 0xe3;
            else
              WrError(ErrNum_InvAddrMode);
            break;
          default:
            break;
        }
        break;
      default:
        break;
    }
  }
}

static void DecodeADD(Word Code)
{
  int MinArg, MaxArg;

  UNUSED(Code);

  MinArg = (CurrZ80Syntax & eSyntax808x) ? 1 : 2;
  if (CurrZ80Syntax & eSyntaxZ80)
    MaxArg = (MomCPU == CPU8085U) ? 3 : 2;
  else
    MaxArg = 1;
  if (!ChkArgCnt(MinArg, MaxArg))
    return;

  switch (ArgCnt)
  {
    case 1: /* 8080 style - 8 bit register src only, dst is implicitly ACC */
    {
      Byte Reg;

      if (!DecodeReg8(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
      else
        BAsmCode[CodeLen++] = 0x80 | Reg;
      break;
    }
    case 2: /* Z80 style - dst may be HL or A and is first arg */
    {
      DecodeAdr_Z80(&ArgStr[1], MModReg8 | MModReg16);
      switch (AdrMode)
      {
        case ModReg8:
          if (AdrVals[0] != AccReg) WrError(ErrNum_InvAddrMode);
          else
          {
            DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModIReg16 | MModImm);
            switch (AdrMode)
            {
              case ModReg8:
                BAsmCode[CodeLen++] = 0x80 | AdrVals[0];
                break;
              case ModIReg16:
                if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
                else
                  BAsmCode[CodeLen++] = 0x86;
                break;
              case ModImm:
                BAsmCode[CodeLen++] = 0xc6;
                BAsmCode[CodeLen++] = AdrVals[0];
                break;
              default:
                break;
            }
          }
          break;
        case ModReg16:
          if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
          else
          {
            DecodeAdr_Z80(&ArgStr[2], MModReg16);
            switch (AdrMode)
            {
              case ModReg16:
                BAsmCode[CodeLen++] = 0x09 | (AdrVals[0] << 4);
                break;
              default:
                break;
            }
          }
          break;
        default:
          break;
      }
      break;
    }
    case 3: /* Z80 style of undoc 8085 : DE <- (HL,SP) + m */
    {
      Byte Reg;

      if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg) || (Reg != DEReg)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
      else if (!DecodeReg16(ArgStr[2].str.p_str, CurrZ80Syntax, &Reg) || (Reg < 2)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
      else
      {
        Boolean OK;

        BAsmCode[1] = EvalStrIntExpression(&ArgStr[3], UInt8, &OK);
        if (OK)
        {
          BAsmCode[0] = 0x08 | (Reg << 4);
          CodeLen = 2;
        }
      }
      break;
    }
  }
}

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

  if (!ChkArgCnt((CurrZ80Syntax & eSyntax808x) ? 1 : 2, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
      return;

  switch (ArgCnt)
  {
    case 1: /* 8080 style - 8 bit register src only */
    {
      Byte Reg;

      if (!DecodeReg8(ArgStr[1].str.p_str, eSyntax808x, &Reg)) WrStrErrorPos(ErrNum_InvRegName, &ArgStr[1]);
      else
        BAsmCode[CodeLen++] = 0x88 | Reg;
      break;
    }
    case 2:
    {
      DecodeAdr_Z80(&ArgStr[1], MModReg8);
      switch (AdrMode)
      {
        case ModReg8:
          if (AdrVals[0] != AccReg) WrError(ErrNum_InvAddrMode);
          else
          {
            DecodeAdr_Z80(&ArgStr[2], MModReg8 | MModIReg16 | MModImm);
            switch (AdrMode)
            {
              case ModReg8:
                BAsmCode[CodeLen++] = 0x88 | AdrVals[0];
                break;
              case ModIReg16:
                if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
                else
                  BAsmCode[CodeLen++] = 0x8e;
                break;
              case ModImm:
                BAsmCode[CodeLen++] = 0xce;
                BAsmCode[CodeLen++] = AdrVals[0];
                break;
              default:
                break;
            }
          }
          break;
        default:
          break;
      }
      break;
    }
  }
}

static void DecodeSUB(Word Code)
{
  Byte Reg;

  UNUSED(Code);

  /* dest operand is always A and also optional for Z80 mode, so min arg cnt is always 1! */

  if (!ChkArgCnt(1, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
    return;

  /* For Z80, optionally allow A as dest */

  if (ArgCnt == 2)
  {
    DecodeAdr_Z80(&ArgStr[1], MModReg8 | ((MomCPU == CPU8085U) ? MModReg16 : 0));

    switch (AdrMode)
    {
      case ModNone:
        return;
      case ModReg8:
        if (AdrVals[0] != AccReg)
          goto error;
        break;
      case ModReg16:
        if (AdrVals[0] != HLReg)
          goto error;
        break;
      default:
      error:
        WrError(ErrNum_InvAddrMode);
        return;
    }
  }
  else
    AdrMode = ModReg8;

  if (DecodeReg8(ArgStr[ArgCnt].str.p_str, CurrZ80Syntax, &Reg)) /* 808x style incl. M, Z80 style excl. (HL) */
  {
    BAsmCode[CodeLen++] = 0x90 | Reg;
    return;
  }

  /* rest is Z80 style ( (HL) or immediate) */

  if (!(CurrZ80Syntax & eSyntaxZ80))
  {
    WrError(ErrNum_InvAddrMode);
    return;
  }

  DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | MModIReg16 | ((AdrMode == ModReg16) ? MModReg16 : 0));
  switch (AdrMode)
  {
    case ModReg16:
      if (AdrVals[0] != BCReg) WrError(ErrNum_InvAddrMode);
      else
        BAsmCode[CodeLen++] = 0x08;
      break;
    case ModIReg16:
      if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
      else
        BAsmCode[CodeLen++] = 0x96;
      break;
    case ModImm:
      BAsmCode[CodeLen++] = 0xd6;
      BAsmCode[CodeLen++] = AdrVals[0];
      break;
    default:
      break;
  }
}

static void DecodeALU8_Z80(Word Code)
{
  if (!ChkZ80Syntax(eSyntaxZ80)
   || !ChkArgCnt(1, 2))
    return;

  if (ArgCnt == 2) /* A as dest */
  {
    DecodeAdr_Z80(&ArgStr[1], MModReg8);

    switch (AdrMode)
    {
      case ModNone:
        return;
      case ModReg8:
        if (AdrVals[0] == AccReg)
          break;
        /* else fall-through */
      default:
        WrError(ErrNum_InvAddrMode);
        return;
    }
  }

  DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | MModIReg16 | MModReg8);
  switch (AdrMode)
  {
    case ModReg8:
      BAsmCode[CodeLen++] = 0x80 | (Code << 3) | AdrVals[0];
      break;
    case ModIReg16:
      if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
      else
        BAsmCode[CodeLen++] = 0x86 | (Code << 3);
      break;
    case ModImm:
      BAsmCode[CodeLen++] = 0xc6 | (Code << 3);
      BAsmCode[CodeLen++] = AdrVals[0];
      break;
    default:
      break;
  }
}

static void DecodeINCDEC(Word Code)
{
  if (ChkZ80Syntax(eSyntaxZ80)
   && ChkArgCnt(1, 1))
  {
    DecodeAdr_Z80(&ArgStr[1], MModReg8 | MModReg16 | MModIReg16);
    switch (AdrMode)
    {
      case ModReg8:
        BAsmCode[CodeLen++] = 0x04 | Code | (AdrVals[0] << 3);
        break;
      case ModReg16:
        BAsmCode[CodeLen++] = 0x03 | (Code << 3) | (AdrVals[0] << 4);
        break;
      case ModIReg16:
        if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
        else
          BAsmCode[CodeLen++] = 0x34 | Code;
      default:
        break;
    }
  }
}

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

  if (!ChkArgCnt(1, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
    return;

  /* 2 arguments -> check for A as dest, and compare is meant
     (syntax is either Z80 or Z80+808x implicitly due to previous check) */


  if (ArgCnt == 2) /* A as dest */
  {
    DecodeAdr_Z80(&ArgStr[1], MModReg8);

    switch (AdrMode)
    {
      case ModNone:
        return;
      case ModReg8:
        if (AdrVals[0] == AccReg)
          break;
        /* else fall-through */
      default:
        WrError(ErrNum_InvAddrMode);
        return;
    }
    OpSize = 0;
  }

  /* 1 argument -> must be compare anyway in pure Z80 syntax mode, otherwise assume 808x call-on-positive */

  else
    OpSize = (CurrZ80Syntax == eSyntaxZ80) ? 0 : 1;

  DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | ((CurrZ80Syntax & eSyntaxZ80) ? (MModIReg16 | MModReg8) : 0));
  switch (AdrMode)
  {
    case ModReg8:
      BAsmCode[CodeLen++] = 0xb8 | AdrVals[0];
      break;
    case ModIReg16:
      if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
      else
        BAsmCode[CodeLen++] = 0xbe;
      break;
    case ModImm:
      if (1 == OpSize) /* see comment above */
      {
        BAsmCode[CodeLen++] = 0xf4;
        BAsmCode[CodeLen++] = AdrVals[0];
        BAsmCode[CodeLen++] = AdrVals[1];
      }
      else
      {
        BAsmCode[CodeLen++] = 0xfe;
        BAsmCode[CodeLen++] = AdrVals[0];
      }
      break;
    default:
      break;
  }
}

static void DecodeJP(Word Code)
{
  Byte Condition;
  UNUSED(Code);

  if (!ChkArgCnt(1, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
    return;

  /* if two arguments, first one is (Z80) condition */

  if (ArgCnt == 2)
  {
    if (!DecodeCondition(ArgStr[1].str.p_str, &Condition, True))
    {
      WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
      return;
    }
  }

  /* if one argument, it's unconditional JP in Z80 mode, or jump-if positive */

  else
    Condition = (CurrZ80Syntax == eSyntaxZ80) ? 0xff : 6 << 3;

  OpSize = 1;
  DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm | (((ArgCnt == 1) && (CurrZ80Syntax & eSyntaxZ80)) ? MModIReg16 : 0));
  switch (AdrMode)
  {
    case ModIReg16:
      if (AdrVals[0] != HLReg) WrError(ErrNum_InvAddrMode);
      else
        BAsmCode[CodeLen++] = 0xe9;
      break;
    case ModImm:
      BAsmCode[CodeLen++] = (0xff == Condition) ? 0xc3 : 0xc2 + Condition;
      BAsmCode[CodeLen++] = AdrVals[0];
      BAsmCode[CodeLen++] = AdrVals[1];
    default:
      break;
  }
}

static void DecodeCALL(Word Code)
{
  Byte Condition;
  UNUSED(Code);

  if (!ChkArgCnt(1, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
    return;

  if (ArgCnt == 2) /* Z80-style with condition */
  {
    if (!DecodeCondition(ArgStr[1].str.p_str, &Condition, False))
    {
      WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
      return;
    }
  }
  else
    Condition = 0xff;

  OpSize = 1;
  DecodeAdr_Z80(&ArgStr[ArgCnt], MModImm);
  switch (AdrMode)
  {
    case ModImm:
      BAsmCode[CodeLen++] = (1 == ArgCnt) ? 0xcd : 0xc4 | Condition;
      BAsmCode[CodeLen++] = AdrVals[0];
      BAsmCode[CodeLen++] = AdrVals[1];
    default:
      break;
  }
}

static void DecodeRET(Word Code)
{
  Byte Condition;
  UNUSED(Code);

  if (!ChkArgCnt(0, (CurrZ80Syntax & eSyntaxZ80) ? 1 : 0))
    return;

  if (ArgCnt == 1) /* Z80-style with condition */
  {
    if (!DecodeCondition(ArgStr[1].str.p_str, &Condition, False)) WrStrErrorPos(ErrNum_UndefCond, &ArgStr[1]);
    else
      BAsmCode[CodeLen++] = 0xc0 | Condition;
  }
  else
   BAsmCode[CodeLen++] = 0xc9;
}

static void DecodeINOUT(Word Code)
{
  tEvalResult EvalResult;

  if (!ChkArgCnt((CurrZ80Syntax & eSyntax808x) ? 1 : 2, (CurrZ80Syntax & eSyntaxZ80) ? 2 : 1))
    return;

  if (ArgCnt == 2) /* Z80-style with A */
  {
    DecodeAdr_Z80(&ArgStr[Code == 0xdb ? 1 : 2], MModReg8);
    if ((AdrMode != ModNone) && (AdrVals[0] != AccReg))
    {
      WrError(ErrNum_InvAddrMode);
      AdrMode = ModNone;
    }
    if (AdrMode == ModNone)
      return;
  }
  BAsmCode[1] = EvalStrIntExpressionWithResult(&ArgStr[((Code == 0xdb) && (ArgCnt == 2)) ? 2 : 1], UInt8, &EvalResult);
  if (EvalResult.OK)
  {
    ChkSpace(SegIO, EvalResult.AddrSpaceMask);
    BAsmCode[0] = Lo(Code);
    CodeLen = 2;
  }
}

static void DecodeSRA(Word Code)
{
  Byte Reg;

  if (!ChkArgCnt(1, 1));
  else if (!ChkMinCPU(CPU8085U));
  else if (!ChkZ80Syntax(eSyntaxZ80));
  else if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg) || (Reg != HLReg)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
  else
   BAsmCode[CodeLen++] = Lo(Code);
}

static void DecodeRLC(Word Code)
{
  if (!ChkArgCnt((CurrZ80Syntax & eSyntax808x) ? 0 : 1, (CurrZ80Syntax & eSyntaxZ80) ? 1 : 0))
    return;

  switch (ArgCnt)
  {
    case 0:
      BAsmCode[CodeLen++] = Code;
      break;
    case 1:
    {
      Byte Reg;

      if (!DecodeReg16(ArgStr[1].str.p_str, CurrZ80Syntax, &Reg) || (Reg != DEReg)) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
      else
        BAsmCode[CodeLen++] = 0x18;
      break;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeCALLN(Word code)
 * \brief  handle CALLN instruction
 * \param  code machine code
 * ------------------------------------------------------------------------ */


static void DecodeCALLN(Word code)
{
  if (ChkArgCnt(1, 1) && ChkExactCPU(CPUV30EMU))
  {
    Boolean ok;

    BAsmCode[2] = EvalStrIntExpression(&ArgStr[1], UInt8, &ok);
    if (ok)
    {
      BAsmCode[0] = Hi(code);
      BAsmCode[1] = Lo(code);
      CodeLen = 3;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     DecodeRETEM(Word code)
 * \brief  handle RETEM instruction
 * \param  code machine code
 * ------------------------------------------------------------------------ */


static void DecodeRETEM(Word code)
{
  if (ChkArgCnt(0, 0) && ChkExactCPU(CPUV30EMU))
  {
    BAsmCode[0] = Hi(code);
    BAsmCode[1] = Lo(code);
    CodeLen = 2;
  }
}

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

  CodeEquate(SegIO, 0, 0xff);
}

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

static void AddFixed(const char *NName, CPUVar NMinCPU, Byte NCode, Word SyntaxMask)
{
  if (MomCPU >= NMinCPU)
    AddInstTable(InstTable, NName, (SyntaxMask << 8) | NCode, DecodeFixed);
}

static void AddOp16(const char *NName, CPUVar NMinCPU, Byte NCode, Word SyntaxMask)
{
  if (MomCPU >= NMinCPU)
    AddInstTable(InstTable, NName, (SyntaxMask << 8) | NCode, DecodeOp16);
}

static void AddOp8(const char *NName, CPUVar NMinCPU, Word NCode, Word SyntaxMask)
{
  if (MomCPU >= NMinCPU)
    AddInstTable(InstTable, NName, (SyntaxMask << 8) | NCode, DecodeOp8);
}

static void AddALU(const char *NName, Byte NCode, Word SyntaxMask)
{
  AddInstTable(InstTable, NName, (SyntaxMask << 8) | NCode, DecodeALU);
}

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

  AddInstTable(InstTable, "MOV" , 0, DecodeMOV);
  AddInstTable(InstTable, "MVI" , 0, DecodeMVI);
  AddInstTable(InstTable, "LXI" , 0, DecodeLXI);
  AddInstTable(InstTable, "STAX", 0, DecodeLDAX_STAX);
  AddInstTable(InstTable, "LDAX", 1, DecodeLDAX_STAX);
  AddInstTable(InstTable, "SHLX", 0, DecodeLHLX_SHLX);
  AddInstTable(InstTable, "LHLX", 1, DecodeLHLX_SHLX);
  AddInstTable(InstTable, "PUSH", 4, DecodePUSH_POP);
  AddInstTable(InstTable, "POP" , 0, DecodePUSH_POP);
  AddInstTable(InstTable, "RST" , 0, DecodeRST);
  AddInstTable(InstTable, "INR" , 0, DecodeINR_DCR);
  AddInstTable(InstTable, "DCR" , 1, DecodeINR_DCR);
  AddInstTable(InstTable, "INX" , 0, DecodeINX_DCX);
  AddInstTable(InstTable, "DCX" , 8, DecodeINX_DCX);
  AddInstTable(InstTable, "DAD" , 0, DecodeDAD);
  AddInstTable(InstTable, "DSUB", 0, DecodeDSUB);
  AddInstTable(InstTable, "PORT", 0, DecodePORT);

  AddFixed("XCHG", CPU8080 , 0xeb, eSyntax808x);
  AddFixed("XTHL", CPU8080 , 0xe3, eSyntax808x);
  AddFixed("SPHL", CPU8080 , 0xf9, eSyntax808x);
  AddFixed("PCHL", CPU8080 , 0xe9, eSyntax808x);
  AddFixed("RC"  , CPU8080 , 0xd8, eSyntax808x);
  AddFixed("RNC" , CPU8080 , 0xd0, eSyntax808x);
  AddFixed("RZ"  , CPU8080 , 0xc8, eSyntax808x);
  AddFixed("RNZ" , CPU8080 , 0xc0, eSyntax808x);
  AddFixed("RP"  , CPU8080 , 0xf0, eSyntax808x);
  AddFixed("RM"  , CPU8080 , 0xf8, eSyntax808x);
  AddFixed("RPE" , CPU8080 , 0xe8, eSyntax808x);
  AddFixed("RPO" , CPU8080 , 0xe0, eSyntax808x);
  /* RLC needs special handling */
  AddFixed("RLCA", CPU8080 , 0x07, eSyntaxZ80);
  AddFixed("RRC" , CPU8080 , 0x0f, eSyntax808x);
  AddFixed("RRCA", CPU8080 , 0x0f, eSyntaxZ80);
  AddFixed("RAL" , CPU8080 , 0x17, eSyntax808x);
  AddFixed("RLA" , CPU8080 , 0x17, eSyntaxZ80);
  AddFixed("RAR" , CPU8080 , 0x1f, eSyntax808x);
  AddFixed("RRA" , CPU8080 , 0x1f, eSyntaxZ80);
  AddFixed("CMA" , CPU8080 , 0x2f, eSyntax808x);
  AddFixed("CPL" , CPU8080 , 0x2f, eSyntaxZ80);
  AddFixed("STC" , CPU8080 , 0x37, eSyntax808x);
  AddFixed("SCF" , CPU8080 , 0x37, eSyntaxZ80);
  AddFixed("CMC" , CPU8080 , 0x3f, eSyntax808x);
  AddFixed("CCF" , CPU8080 , 0x3f, eSyntaxZ80);
  AddFixed("DAA" , CPU8080 , 0x27, eSyntax808x | eSyntaxZ80);
  AddFixed("EI"  , CPU8080 , 0xfb, eSyntax808x | eSyntaxZ80);
  AddFixed("DI"  , CPU8080 , 0xf3, eSyntax808x | eSyntaxZ80);
  AddFixed("NOP" , CPU8080 , 0x00, eSyntax808x | eSyntaxZ80);
  AddFixed("HLT" , CPU8080 , 0x76, eSyntax808x);
  AddFixed("HALT", CPU8080 , 0x76, eSyntaxZ80);
  AddFixed("RIM" , CPU8085 , 0x20, eSyntax808x);
  AddFixed("SIM" , CPU8085 , 0x30, eSyntax808x);
  AddFixed("ARHL", CPU8085U, 0x10, eSyntax808x);
  AddFixed("RDEL", CPU8085U, 0x18, eSyntax808x | eSyntaxZ80); /* TODO: find LD equivalent */
  AddFixed("RSTV", CPU8085U, 0xcb, eSyntax808x);


  AddOp16("STA" , CPU8080 , 0x32, eSyntax808x);
  AddOp16("LDA" , CPU8080 , 0x3a, eSyntax808x);
  AddOp16("SHLD", CPU8080 , 0x22, eSyntax808x);
  AddOp16("LHLD", CPU8080 , 0x2a, eSyntax808x);
  AddOp16("JMP" , CPU8080 , 0xc3, eSyntax808x);
  AddOp16("JC"  , CPU8080 , 0xda, eSyntax808x);
  AddOp16("JNC" , CPU8080 , 0xd2, eSyntax808x);
  AddOp16("JZ"  , CPU8080 , 0xca, eSyntax808x);
  AddOp16("JNZ" , CPU8080 , 0xc2, eSyntax808x);
  /* JP needs special handling */
  AddOp16("JM"  , CPU8080 , 0xfa, eSyntax808x);
  AddOp16("JPE" , CPU8080 , 0xea, eSyntax808x);
  AddOp16("JPO" , CPU8080 , 0xe2, eSyntax808x);
  /* CALL needs special handling */
  AddOp16("CC"  , CPU8080 , 0xdc, eSyntax808x);
  AddOp16("CNC" , CPU8080 , 0xd4, eSyntax808x);
  AddOp16("CZ"  , CPU8080 , 0xcc, eSyntax808x);
  AddOp16("CNZ" , CPU8080 , 0xc4, eSyntax808x);
  /* CP needs special handling */
  AddOp16("CM"  , CPU8080 , 0xfc, eSyntax808x);
  AddOp16("CPE" , CPU8080 , 0xec, eSyntax808x);
  AddOp16("CPO" , CPU8080 , 0xe4, eSyntax808x);
  AddOp16("JNX5", CPU8085U, 0xdd, eSyntax808x);
  AddOp16("JX5" , CPU8085U, 0xfd, eSyntax808x);

  AddOp8("ADI" , CPU8080 , 0xc6, eSyntax808x);
  AddOp8("ACI" , CPU8080 , 0xce, eSyntax808x);
  AddOp8("SUI" , CPU8080 , 0xd6, eSyntax808x);
  AddOp8("SBI" , CPU8080 , 0xde, eSyntax808x);
  AddOp8("ANI" , CPU8080 , 0xe6, eSyntax808x);
  AddOp8("XRI" , CPU8080 , 0xee, eSyntax808x);
  AddOp8("ORI" , CPU8080 , 0xf6, eSyntax808x);
  AddOp8("CPI" , CPU8080 , 0xfe, eSyntax808x);
  AddOp8("LDHI", CPU8085U, 0x28, eSyntax808x | eSyntaxZ80); /* TODO: find LD equivalent */
  AddOp8("LDSI", CPU8085U, 0x38, eSyntax808x | eSyntaxZ80);

  AddALU("SBB" , 0x98, eSyntax808x);
  AddALU("ANA" , 0xa0, eSyntax808x);
  AddALU("XRA" , 0xa8, eSyntax808x);
  AddALU("ORA" , 0xb0, eSyntax808x);
  AddALU("CMP" , 0xb8, eSyntax808x);

  AddInstTable(InstTable, "LD", 0, DecodeLD);
  AddInstTable(InstTable, "EX", 0, DecodeEX);
  AddInstTable(InstTable, "ADD", 0, DecodeADD);
  AddInstTable(InstTable, "ADC", 0, DecodeADC);
  AddInstTable(InstTable, "SUB", 0, DecodeSUB);
  AddInstTable(InstTable, "SBC", 3, DecodeALU8_Z80);
  AddInstTable(InstTable, "INC", 0, DecodeINCDEC);
  AddInstTable(InstTable, "DEC", 1, DecodeINCDEC);
  AddInstTable(InstTable, "AND", 4, DecodeALU8_Z80);
  AddInstTable(InstTable, "XOR", 5, DecodeALU8_Z80);
  AddInstTable(InstTable, "OR" , 6, DecodeALU8_Z80);
  AddInstTable(InstTable, "CP" , 0, DecodeCP);
  AddInstTable(InstTable, "JP" , 0, DecodeJP);
  AddInstTable(InstTable, "CALL", 0, DecodeCALL);
  AddInstTable(InstTable, "RET", 0, DecodeRET);
  AddInstTable(InstTable, "IN", 0xdb, DecodeINOUT);
  AddInstTable(InstTable, "OUT", 0xd3, DecodeINOUT);
  AddInstTable(InstTable, "SRA", 0x10, DecodeSRA);
  AddInstTable(InstTable, "RLC", 0x07, DecodeRLC);

  AddInstTable(InstTable, "CALLN", 0xeded, DecodeCALLN);
  AddInstTable(InstTable, "RETEM", 0xedfd, DecodeRETEM);

  AddZ80Syntax(InstTable);
}

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

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

static void MakeCode_85(void)
{
  CodeLen = 0;
  DontPrint = False;
  OpSize = 0;

  /* zu ignorierendes */

  if (Memo("")) return;

  /* Pseudoanweisungen */

  if (DecodeIntelPseudo(False)) return;

  /* suchen */

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

static Boolean IsDef_85(void)
{
  return Memo("PORT");
}

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

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

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

  ValidSegs = (1 << SegCode) | (1 << SegIO);
  Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  SegLimits[SegCode] = 0xffff;
  Grans[SegIO  ] = 1; ListGrans[SegIO  ] = 1; SegInits[SegIO  ] = 0;
  SegLimits[SegIO  ] = 0xff;

  MakeCode = MakeCode_85;
  IsDef = IsDef_85;
  SwitchFrom = SwitchFrom_85;
  InitFields();
}

void code85_init(void)
{
  CPU8080 = AddCPU("8080", SwitchTo_85);
  CPUV30EMU = AddCPU("V30EMU", SwitchTo_85);
  CPU8085 = AddCPU("8085", SwitchTo_85);
  CPU8085U = AddCPU("8085UNDOC", SwitchTo_85);
}