Top secrets sources NedoPC pentevo

Rev

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

/* code96.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator MCS/96-Familie                                              */
/*                                                                           */
/*****************************************************************************/

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

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

#include "code96.h"

typedef enum
{
  ModNone = -1,
  ModDir = 0,
  ModInd = 1,
  ModPost = 2,
  ModIdx = 3,
  ModImm = 4
} tAdrMode;

#define ModNone (-1)
#define MModDir (1 << ModDir)
#define MModInd (1 << ModInd)
#define MModPost (1 << ModPost)
#define MModIdx (1 << ModIdx)
#define MModMem (MModInd | MModPost | MModIdx)
#define MModImm (1 << ModImm)

#define SFRStart 2
#define SFRStop 0x17

typedef enum
{
  eForceNone = 0,
  eForceShort = 1,
  eForceLong = 2
} tForceSize;

static CPUVar CPU8096, CPU80196, CPU80196N, CPU80296;

static Byte AdrMode;
static ShortInt AdrType;
static Byte AdrVals[4];
static ShortInt OpSize;

static LongInt WSRVal, WSR1Val;
static Word WinStart, WinStop, WinEnd, WinBegin;
static Word Win1Start, Win1Stop, Win1Begin, Win1End;

static IntType MemInt;

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

static void ChkSFR(Word Adr, const tStrComp *pArg)
{
  if ((Adr >= SFRStart) && (Adr <= SFRStop))
    WrStrErrorPos(ErrNum_IOAddrNotAllowed, pArg);
}

static void Chk296(Word Adr, const tStrComp *pArg)
{
  if ((MomCPU == CPU80296) && (Adr <= 1))
    WrStrErrorPos(ErrNum_IOAddrNotAllowed, pArg);
}

static Boolean ChkWork(Word *Adr)
{
  /* Registeradresse, die von Fenstern ueberdeckt wird ? */

  if ((*Adr >= WinBegin) && (*Adr <= WinEnd))
    return False;

  else if ((*Adr >= Win1Begin) && (*Adr <= Win1End))
    return False;

  /* Speicheradresse in Fenster ? */

  else if ((*Adr >= WinStart) && (*Adr <= WinStop))
  {
    *Adr = (*Adr) - WinStart + WinBegin;
    return True;
  }

  else if ((*Adr >= Win1Start) && (*Adr <= Win1Stop))
  {
    *Adr = (*Adr) - Win1Start + Win1Begin;
    return True;
  }

  /* Default */

  else
    return (*Adr <= 0xff);
}

static void ChkAdr(Byte Mask, const tStrComp *pArg)
{
  if ((AdrType == ModDir) && (!(Mask & MModDir)))
  {
    AdrType = ModInd; /* not exactly right, but AdrMode counts */
    AdrMode = 0;
  }

  if ((AdrType != ModNone) && (!(Mask & (1 << AdrType))))
  {
    WrStrErrorPos(ErrNum_InvAddrMode, pArg);
    AdrType = ModNone;
    AdrCnt = 0;
  }
}

static int SplitForceSize(const char *pArg, tForceSize *pForceSize)
{
  switch (*pArg)
  {
    case '>': *pForceSize = eForceLong; return 1;
    case '<': *pForceSize = eForceShort; return 1;
    default: return 0;
  }
}

static void DecodeAdr(const tStrComp *pArg, Byte Mask, Boolean AddrWide)
{
  LongInt AdrInt;
  LongWord AdrWord;
  Word BReg;
  Boolean OK;
  tSymbolFlags Flags;
  char *p, *p2;
  int ArgLen;
  Byte Reg;
  LongWord OMask;

  AdrType = ModNone;
  AdrCnt = 0;
  OMask = (1 << OpSize) - 1;

  if (*pArg->str.p_str == '#')
  {
    switch (OpSize)
    {
      case -1:
        WrStrErrorPos(ErrNum_UndefOpSizes, pArg);
        break;
      case 0:
        AdrVals[0] = EvalStrIntExpressionOffs(pArg, 1, Int8, &OK);
        if (OK)
        {
          AdrType = ModImm;
          AdrCnt = 1;
          AdrMode = 1;
        }
        break;
      case 1:
        AdrWord = EvalStrIntExpressionOffs(pArg, 1, Int16, &OK);
        if (OK)
        {
          AdrType = ModImm;
          AdrCnt = 2;
          AdrMode = 1;
          AdrVals[0] = Lo(AdrWord);
          AdrVals[1] = Hi(AdrWord);
        }
        break;
    }
    goto chk;
  }

  p = QuotPos(pArg->str.p_str, '[');
  if (p)
  {
    tStrComp Left, Mid, Right;

    StrCompSplitRef(&Left, &Mid, pArg, p);
    p2 = RQuotPos(Mid.str.p_str, ']');
    ArgLen = strlen(Mid.str.p_str);
    if (!p2 || (p2 > Mid.str.p_str + ArgLen - 1) || (p2 < Mid.str.p_str + ArgLen - 2)) WrStrErrorPos(ErrNum_InvAddrMode, pArg);
    else
    {
      StrCompSplitRef(&Mid, &Right, &Mid, p2);
      BReg = EvalStrIntExpressionWithFlags(&Mid, Int16, &OK, &Flags);
      if (mFirstPassUnknown(Flags))
        BReg = 0;
      if (OK)
      {
        if (!ChkWork(&BReg)) WrStrErrorPos(ErrNum_OverRange, &Mid);
        else
        {
          Reg = Lo(BReg);
          ChkSFR(Reg, &Mid);
          if (Reg & 1) WrStrErrorPos(ErrNum_AddrMustBeEven, &Mid);
          else if ((strlen(Left.str.p_str) == 0) && !strcmp(Right.str.p_str, "+"))
          {
            AdrType = ModPost;
            AdrMode = 2;
            AdrCnt = 1;
            AdrVals[0] = Reg + 1;
          }
          else if (strlen(Right.str.p_str) != 0) WrStrErrorPos(ErrNum_InvAddrMode, pArg);
          else if (strlen(Left.str.p_str) == 0)
          {
            AdrVals[0] = Reg;
            AdrCnt = 1;
            if (Mask & MModInd)
            {
              AdrType = ModInd;
              AdrMode = 2;
              AdrCnt = 1;
            }
            else
            {
              WrStrErrorPos(ErrNum_IndexedForIndirect, pArg);
              AdrType = ModIdx;
              AdrMode = 3;
              AdrVals[AdrCnt++] = 0;
            }
          }
          else
          {
            tForceSize ForceSize = eForceNone;
            int Offset = SplitForceSize(Left.str.p_str, &ForceSize);

            AdrInt = EvalStrIntExpressionOffsWithFlags(&Left, Offset, AddrWide ? Int24 : Int16, &OK, &Flags);
            if (OK)
            {
              if ((AdrInt == 0) && (Mask & MModInd) && !ForceSize)
              {
                AdrType = ModInd;
                AdrMode = 2;
                AdrCnt = 1;
                AdrVals[0] = Reg;
              }
              else if (AddrWide)
              {
                AdrType = ModIdx;
                AdrMode= 3;
                AdrCnt = 4;
                AdrVals[0] = Reg;
                AdrVals[1] = AdrInt & 0xff;
                AdrVals[2] = (AdrInt >> 8) & 0xff;
                AdrVals[3] = (AdrInt >> 16) & 0xff;
              }
              else
              {
                Boolean IsShort = (AdrInt >= -128) && (AdrInt <= 127);

                if (!ForceSize)
                  ForceSize = IsShort ? eForceShort : eForceLong;
                if (ForceSize == eForceShort)
                {
                  if ((AdrInt > 127) && !mSymbolQuestionable(Flags)) WrStrErrorPos(ErrNum_OverRange, &Left);
                  else if ((AdrInt < -128) && !mSymbolQuestionable(Flags)) WrStrErrorPos(ErrNum_UnderRange, &Left);
                  else
                  {
                    AdrType = ModIdx;
                    AdrMode = 3;
                    AdrCnt = 2;
                    AdrVals[0] = Reg;
                    AdrVals[1] = Lo(AdrInt);
                  }
                }
                else
                {
                  AdrType = ModIdx;
                  AdrMode = 3;
                  AdrCnt = 3;
                  AdrVals[0] = Reg + 1;
                  AdrVals[1] = Lo(AdrInt);
                  AdrVals[2] = Hi(AdrInt);
                }
              }
            }
          }
        }
      }
    }
  }
  else
  {
    tForceSize ForceSize = eForceNone;
    int Offset = SplitForceSize(pArg->str.p_str, &ForceSize);

    AdrWord = EvalStrIntExpressionOffsWithFlags(pArg, Offset, MemInt, &OK, &Flags);
    if (mFirstPassUnknown(Flags))
      AdrWord &= (0xffffffff - OMask);
    if (OK)
    {
      if (AdrWord & OMask) WrStrErrorPos(ErrNum_NotAligned, pArg);
      else
      {
        BReg = AdrWord & 0xffff;
        if ((!(BReg & 0xffff0000)) && ChkWork(&BReg) && !ForceSize)
        {
          AdrType = ModDir;
          AdrCnt = 1;
          AdrVals[0] = Lo(BReg);
        }
        else if (AddrWide)
        {
          AdrType = ModIdx;
          AdrMode = 3;
          AdrCnt = 4;
          AdrVals[0] = 0;
          AdrVals[1] = AdrWord & 0xff;
          AdrVals[2] = (AdrWord >> 8) & 0xff;
          AdrVals[3] = (AdrWord >> 16) & 0xff;
        }
        else
        {
          Boolean IsShort = AdrWord >= 0xff80;

          if (!ForceSize)
            ForceSize = IsShort ? eForceShort : eForceLong;
          if (ForceSize == eForceShort)
          {
            if (!IsShort) WrStrErrorPos(ErrNum_UnderRange, pArg);
            else
            {
              AdrType = ModIdx;
              AdrMode = 3;
              AdrCnt = 2;
              AdrVals[0] = 0;
              AdrVals[1] = Lo(AdrWord);
            }
          }
          else
          {
            AdrType = ModIdx;
            AdrMode = 3;
            AdrCnt = 3;
            AdrVals[0] = 1;
            AdrVals[1] = Lo(AdrWord);
            AdrVals[2] = Hi(AdrWord);
          }
        }
      }
    }
  }

chk:
  ChkAdr(Mask, pArg);
}

static void CalcWSRWindow(void)
{
  WSRVal &= 0x7f;
  if (WSRVal <= 0x0f)
  {
    WinStart = 0xffff;
    WinStop = 0;
    WinBegin = 0xff;
    WinEnd = 0;
  }
  else if (WSRVal <= 0x1f)
  {
    WinBegin = 0x80;
    WinEnd = 0xff;
    WinStart = (WSRVal < 0x18) ? ((WSRVal - 0x10) << 7) : ((WSRVal + 0x20) << 7);
    WinStop = WinStart + 0x7f;
  }
  else if (WSRVal <= 0x3f)
  {
    WinBegin = 0xc0;
    WinEnd = 0xff;
    WinStart = (WSRVal < 0x30) ? ((WSRVal - 0x20) << 6) : ((WSRVal + 0x40) << 6);
    WinStop = WinStart + 0x3f;
  }
  else if (WSRVal <= 0x7f)
  {
    WinBegin = 0xe0;
    WinEnd = 0xff;
    WinStart = (WSRVal < 0x60) ? ((WSRVal - 0x40) << 5) : ((WSRVal + 0x80) << 5);
    WinStop = WinStart + 0x1f;
  }
  if ((WinStop > 0x1fdf) && (MomCPU < CPU80296))
    WinStop = 0x1fdf;
}

static void CalcWSR1Window(void)
{
  if (WSR1Val <= 0x1f)
  {
    Win1Start = 0xffff;
    Win1Stop = 0;
    Win1Begin = 0xff;
    Win1End = 0;
  }
  else if (WSR1Val <= 0x3f)
  {
    Win1Begin = 0x40;
    Win1End = 0x7f;
    Win1Start = (WSR1Val < 0x30) ? ((WSR1Val - 0x20) << 6) : ((WSR1Val + 0x40) << 6);
    Win1Stop = Win1Start + 0x3f;
  }
  else if (WSR1Val <= 0x7f)
  {
    Win1Begin = 0x60;
    Win1End = 0x7f;
    Win1Start = (WSR1Val < 0x60) ? ((WSR1Val - 0x40) << 5) : ((WSR1Val + 0x80) << 5);
    Win1Stop = Win1Start + 0x1f;
  }
  else
  {
    Win1Begin = 0x40;
    Win1End = 0x7f;
    Win1Start = (WSR1Val + 0x340) << 6;
    Win1Stop = Win1Start + 0x3f;
  }
}

static Boolean IsShortBranch(LongInt Dist)
{
  return (Dist >= -1024) && (Dist <= 1023);
}

static Boolean IsByteBranch(LongInt Dist)
{
  return (Dist >= -128) && (Dist <= 127);
}

static Boolean GetShort(Word Code, LongInt Dist)
{
  switch (Code)
  {
    case 0: return True;
    case 1: return False;
    default: return IsShortBranch(Dist);
  }
}

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

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

static void DecodeALU3(Word Code)
{
  if (ChkArgCnt(2, 3))
  {
    int Start = 0;
    Boolean Special = (Hi(Code) & 0x40) || False,
            DoubleDest = (Hi(Code) & 0x08) || False;

    OpSize = Hi(Code) & 3;
    if (Hi(Code) & 0x80)
      BAsmCode[Start++] = 0xfe;
    BAsmCode[Start++] = 0x40 + (Ord(ArgCnt==2) << 5)
                      + ((1 - OpSize) << 4)
                      + (Lo(Code) << 2);
    DecodeAdr(&ArgStr[ArgCnt], MModImm | MModMem, False);
    if (AdrType != ModNone)
    {
      Boolean OK;

      BAsmCode[Start - 1] += AdrMode;
      memcpy(BAsmCode + Start, AdrVals, AdrCnt);
      Start += AdrCnt;
      if ((Special) && (AdrMode == 0))
        ChkSFR(AdrVals[0], &ArgStr[ArgCnt]);
      if (ArgCnt == 3)
      {
        DecodeAdr(&ArgStr[2], MModDir, False);
        OK = (AdrType != ModNone);
        if (OK)
        {
          BAsmCode[Start++] = AdrVals[0];
          if (Special)
            ChkSFR(AdrVals[0], &ArgStr[2]);
        }
      }
      else
        OK = True;
      if (OK)
      {
        OpSize += DoubleDest;
        DecodeAdr(&ArgStr[1], MModDir, False);
        if (AdrType != ModNone)
        {
          BAsmCode[Start] = AdrVals[0];
          CodeLen = Start + 1;
          if (Special)
          {
            ChkSFR(AdrVals[0], &ArgStr[1]);
            Chk296(AdrVals[0], &ArgStr[1]);
          }
        }
      }
    }
  }
}

static void DecodeALU2(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    int Start = 0;
    Boolean Special = (Hi(Code) & 0x40) || False,
            DoubleDest = (Hi(Code) & 0x08) || False;
    Byte HReg, Mask;

    OpSize = Hi(Code) & 3;

    if (Hi(Code) & 0x80)
      BAsmCode[Start++] = 0xfe;
    HReg = ((Hi(Code) & 0x20) ? 2 : 1) << 1;
    BAsmCode[Start++] = Lo(Code) + ((1 - OpSize) << HReg);
    Mask = MModMem | ((Hi(Code) & 0x20) ? MModImm : 0);
    DecodeAdr(&ArgStr[2], Mask, False);
    if (AdrType != ModNone)
    {
      BAsmCode[Start - 1] += AdrMode;
      memcpy(BAsmCode + Start, AdrVals, AdrCnt);
      Start += AdrCnt;
      if ((Special) && (AdrMode == 0))
        ChkSFR(AdrVals[0], &ArgStr[2]);
      OpSize += DoubleDest;
      DecodeAdr(&ArgStr[1], MModDir, False);
      if (AdrType != ModNone)
      {
        BAsmCode[Start] = AdrVals[0];
        CodeLen = 1 + Start;
        if (Special)
        {
          ChkSFR(AdrVals[0], &ArgStr[1]);
        }
      }
    }
  }
}

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

  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80196))
  {
    OpSize = 2;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      BAsmCode[2] = AdrVals[0];
      DecodeAdr(&ArgStr[2], MModDir, False);
      if (AdrType != ModNone)
      {
        BAsmCode[1] = AdrVals[0];
        BAsmCode[0] = 0xc5;
        CodeLen = 3;
      }
    }
  }
}

static void DecodePUSH_POP(Word IsPOP)
{
  OpSize = 1;

  if (ChkArgCnt(1, 1))
  {
    DecodeAdr(&ArgStr[1], MModMem | (IsPOP ? 0 : MModImm), False);
    if (AdrType != ModNone)
    {
      CodeLen = 1 + AdrCnt;
      BAsmCode[0] = 0xc8 + AdrMode + (IsPOP << 2);
      memcpy(BAsmCode + 1, AdrVals, AdrCnt);
    }
  }
}

static void DecodeBMOV(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    OpSize = 2;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      BAsmCode[2] = AdrVals[0];
      OpSize = 1;
      DecodeAdr(&ArgStr[2], MModDir, False);
      if (AdrType != ModNone)
      {
        BAsmCode[1] = AdrVals[0];
        BAsmCode[0] = Code;
        CodeLen = 3;
      }
    }
  }
}

static void DecodeALU1(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean DoubleDest = (Hi(Code) & 0x08) || False;
    OpSize = (Hi(Code) & 3) + DoubleDest;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      CodeLen = 1 + AdrCnt;
      OpSize -= DoubleDest;
      BAsmCode[0] = Code + ((1 - OpSize) << 4);
      memcpy(BAsmCode + 1, AdrVals, AdrCnt);
    }
  }
}

static void DecodeXCH(Word Code)
{
  Byte HReg;

  OpSize = Hi(Code) & 3;

  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80196))
  {
    DecodeAdr(&ArgStr[1], MModIdx | MModDir, False);
    switch (AdrType)
    {
      case ModIdx:
        memcpy(BAsmCode + 1, AdrVals, AdrCnt);
        HReg = AdrCnt;
        BAsmCode[0] = (AdrMode ? 0x0b : 0x04) + ((1 - OpSize) << 4);
        DecodeAdr(&ArgStr[2], MModDir, False);
        if (AdrType != ModNone)
        {
          BAsmCode[1 + HReg] = AdrVals[0];
          CodeLen = 2 + HReg;
        }
        break;
      case ModDir:
        HReg = AdrVals[0];
        DecodeAdr(&ArgStr[2], MModDir | MModIdx, False);
        if (AdrType != ModNone)
        {
          BAsmCode[0] = ((AdrType == ModIdx) ? 0x0b : 0x04) + ((1 - OpSize) << 4);
          memcpy(BAsmCode + 1, AdrVals, AdrCnt);
          BAsmCode[1 + AdrCnt] = HReg;
          CodeLen = 2 + AdrCnt;
        }
        break;
    }
  }
}

static void DecodeLDBZE_LDBSE(Word Code)
{
  if (ChkArgCnt(2, 2))
  {
    OpSize = 0;
    DecodeAdr(&ArgStr[2], MModMem | MModImm, False);
    if (AdrType != ModNone)
    {
      int Start;

      BAsmCode[0] = Code + AdrMode;
      memcpy(BAsmCode + 1, AdrVals, AdrCnt);
      Start = 1 + AdrCnt;
      OpSize = 1;
      DecodeAdr(&ArgStr[1], MModDir, False);
      if (AdrType != ModNone)
      {
        BAsmCode[Start] = AdrVals[0];
        CodeLen = 1 + Start;
      }
    }
  }
}

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

  if (ChkArgCnt(2, 2))
  {
    OpSize = eSymbolSize8Bit;
    DecodeAdr(&ArgStr[2], MModDir, False);
    if (AdrType != ModNone)
    {
      BAsmCode[1] = AdrVals[0];
      OpSize = eSymbolSize32Bit;
      DecodeAdr(&ArgStr[1], MModDir, False);
      if (AdrType != ModNone)
      {
        CodeLen = 3;
        BAsmCode[0] = 0x0f;
        BAsmCode[2] = AdrVals[0];
      }
    }
  }
}

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

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU80196))
  {
    OpSize = 0;
    DecodeAdr(&ArgStr[1], MModImm, False);
    if (AdrType != ModNone)
    {
      CodeLen = 2;
      BAsmCode[0] = 0xf6;
      BAsmCode[1] = AdrVals[0];
    }
  }
}

static void DecodeShift(Word Code)
{
  OpSize = Hi(Code) & 3;

  if (ChkArgCnt(2, 2))
  {
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      BAsmCode[0] = 0x08 + Lo(Code) + (Ord(OpSize == 0) << 4) + (Ord(OpSize == 2) << 2);
      BAsmCode[2] = AdrVals[0];
      OpSize = 0;
      DecodeAdr(&ArgStr[2], MModDir | MModImm, False);
      if (AdrType != ModNone)
      {
        if ((AdrType == ModImm) && (AdrVals[0] > 15)) WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
        else if ((AdrType == ModDir) && (AdrVals[0] < 16)) WrStrErrorPos(ErrNum_UnderRange, &ArgStr[2]);
        else
        {
          BAsmCode[1] = AdrVals[0];
          CodeLen = 3;
        }
      }
    }
  }
}

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

  if (ChkArgCnt(1, 1))
  {
    OpSize = 0;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      CodeLen = 2;
      BAsmCode[0] = 0;
      BAsmCode[1] = AdrVals[0];
    }
  }
}

static void DecodeELD_EST(Word Code)
{
  OpSize = Hi(Code) & 3;

  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80196N))
  {
    DecodeAdr(&ArgStr[2], MModInd | MModIdx, True);
    if (AdrType != ModNone)
    {
      Byte HReg;

      BAsmCode[0] = Code + (AdrMode & 1) + ((1 - OpSize) << 1);
      memcpy(BAsmCode + 1, AdrVals, AdrCnt);
      HReg = 1 + AdrCnt;
      DecodeAdr(&ArgStr[1], MModDir, False);
      if (AdrType == ModDir)
      {
        BAsmCode[HReg] = AdrVals[0];
        CodeLen = HReg + 1;
      }
    }
  }
}

static void DecodeMac(Word Code)
{
  if (ChkArgCnt(1, 2)
   && ChkMinCPU(CPU80296))
  {
    OpSize = 1;
    BAsmCode[0] = 0x4c + (Ord(ArgCnt == 1) << 5);
    DecodeAdr(&ArgStr[ArgCnt], MModMem | (Hi(Code) ? 0 : MModImm), False);
    if (AdrType != ModNone)
    {
      int HReg;

      BAsmCode[0] += AdrMode;
      memcpy(BAsmCode + 1, AdrVals, AdrCnt);
      HReg = 1 + AdrCnt;
      if (ArgCnt == 2)
      {
        DecodeAdr(&ArgStr[1], MModDir, False);
        if (AdrType == ModDir)
        {
          BAsmCode[HReg] = AdrVals[0];
          HReg++;
        }
      }
      if (AdrType != ModNone)
      {
        BAsmCode[HReg] = Lo(Code);
        CodeLen = 1 + HReg;
      }
    }
  }
}

static void DecodeMVAC_MSAC(Word Code)
{
  if (ChkArgCnt(2, 2)
   && ChkMinCPU(CPU80296))
  {
    OpSize = 2;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType == ModDir)
    {
      BAsmCode[0] = 0x0d;
      BAsmCode[2] = AdrVals[0] + Code;
      OpSize = 0;
      DecodeAdr(&ArgStr[2], MModImm | MModDir, False);
      BAsmCode[1] = AdrVals[0];
      switch (AdrType)
      {
        case ModImm:
          if (AdrVals[0] > 31) WrStrErrorPos(ErrNum_OverRange, &ArgStr[2]);
          else CodeLen = 3;
          break;
        case ModDir:
          if (AdrVals[0] < 32) WrStrErrorPos(ErrNum_UnderRange, &ArgStr[2]);
          else CodeLen = 3;
      }
    }
  }
}

static void DecodeRpt(Word Code)
{
  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU80296))
  {
    OpSize = 1;
    DecodeAdr(&ArgStr[1], MModImm | MModPost | MModInd, False);
    if (AdrType != ModNone)
    {
      BAsmCode[0] = 0x40 + AdrMode;
      memcpy(BAsmCode + 1, AdrVals, AdrCnt);
      BAsmCode[1 + AdrCnt] = Code;
      BAsmCode[2 + AdrCnt] = 4;
      CodeLen = 3 + AdrCnt;
    }
  }
}

static void DecodeRel(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongInt AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], MemInt, &OK, &Flags) - (EProgCounter() + 2);

    if (OK)
    {
      if (!mSymbolQuestionable(Flags) && !IsByteBranch(AdrInt)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
      else
      {
        CodeLen = 2;
        BAsmCode[0] = Code;
        BAsmCode[1] = AdrInt & 0xff;
      }
    }
  }
}

static void DecodeSCALL_LCALL_CALL(Word Code)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongWord AdrWord = EvalStrIntExpressionWithFlags(&ArgStr[1], MemInt, &OK, &Flags);

    if (OK)
    {
      LongInt AdrInt = AdrWord - (EProgCounter() + 2);
      Boolean IsShort = GetShort(Code, AdrInt);

      if (IsShort)
      {
        if (!mSymbolQuestionable(Flags) && !IsShortBranch(AdrInt)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
        else
        {
          CodeLen = 2;
          BAsmCode[1] = AdrInt & 0xff;
          BAsmCode[0] = 0x28 + ((AdrInt & 0x700) >> 8);
        }
      }
      else
      {
        CodeLen = 3;
        BAsmCode[0] = 0xef;
        AdrInt--;
        BAsmCode[1] = Lo(AdrInt);
        BAsmCode[2] = Hi(AdrInt);
        if (!mSymbolQuestionable(Flags) && IsShortBranch(AdrInt))
          WrStrErrorPos(ErrNum_ShortJumpPossible, &ArgStr[1]);
      }
    }
  }
}

static void DecodeBR_LJMP_SJMP(Word Code)
{
  OpSize = 1;
  if (!ChkArgCnt(1, 1));
  else if ((Code == 0xff) && (QuotPos(ArgStr[1].str.p_str, '[')))
  {
    DecodeAdr(&ArgStr[1], MModInd, False);
    if (AdrType != ModNone)
    {
      CodeLen = 2;
      BAsmCode[0] = 0xe3;
      BAsmCode[1] = AdrVals[0];
    }
  }
  else
  {
    Boolean OK;
    tSymbolFlags Flags;
    LongWord AdrWord = EvalStrIntExpressionWithFlags(&ArgStr[1], MemInt, &OK, &Flags);

    if (OK)
    {
      LongInt AdrInt = AdrWord - (EProgCounter() + 2);
      Boolean IsShort = GetShort(Code, AdrInt);

      if (IsShort)
      {
        if (!mSymbolQuestionable(Flags) && !IsShortBranch(AdrInt)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
        else
        {
          CodeLen = 2;
          BAsmCode[1] = AdrInt & 0xff;
          BAsmCode[0] = 0x20 + ((AdrInt & 0x700) >> 8);
        }
      }
      else
      {
        CodeLen = 3;
        BAsmCode[0] = 0xe7;
        AdrInt--;
        BAsmCode[1] = Lo(AdrInt);
        BAsmCode[2] = Hi(AdrInt);
        if (!mSymbolQuestionable(Flags) && IsShortBranch(AdrInt))
          WrStrErrorPos(ErrNum_ShortJumpPossible, &ArgStr[1]);
      }
    }
  }
}

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

  if (ChkArgCnt(3, 3)
   && ChkMinCPU(CPU80196))
  {
    OpSize = 1;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      BAsmCode[3] = AdrVals[0];
      DecodeAdr(&ArgStr[2], MModDir, False);
      if (AdrType != ModNone)
      {
        BAsmCode[1] = AdrVals[0];
        OpSize = 0;
        DecodeAdr(&ArgStr[3], MModImm, False);
        if (AdrType != ModNone)
        {
          BAsmCode[2] = AdrVals[0];
          BAsmCode[0] = 0xe2;
          CodeLen = 4;
        }
      }
    }
  }
}

static void DecodeDJNZ_DJNZW(Word Size)
{
  if (ChkArgCnt(2, 2)
   && (!Size || ChkMinCPU(CPU80196)))
  {
    OpSize = Size;
    DecodeAdr(&ArgStr[1], MModDir, False);
    if (AdrType != ModNone)
    {
      Boolean OK;
      tSymbolFlags Flags;
      LongInt AdrInt;

      BAsmCode[0] = 0xe0 + OpSize;
      BAsmCode[1] = AdrVals[0];
      AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[2], MemInt, &OK, &Flags) - (EProgCounter() + 3);
      if (OK)
      {
        if (!mSymbolQuestionable(Flags) && !IsByteBranch(AdrInt)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[2]);
        else
        {
          CodeLen = 3;
          BAsmCode[2] = AdrInt & 0xff;
        }
      }
    }
  }
}

static void DecodeJBC_JBS(Word Code)
{
  if (ChkArgCnt(3, 3))
  {
    Boolean OK;

    BAsmCode[0] = Code + EvalStrIntExpression(&ArgStr[2], UInt3, &OK);
    if (OK)
    {
      OpSize = 0;
      DecodeAdr(&ArgStr[1], MModDir, False);
      if (AdrType != ModNone)
      {
        LongInt AdrInt;
        tSymbolFlags Flags;

        BAsmCode[1] = AdrVals[0];
        AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[3], MemInt, &OK, &Flags) - (EProgCounter() + 3);
        if (OK)
        {
          if (!mSymbolQuestionable(Flags) && !IsByteBranch(AdrInt)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[3]);
          else
          {
            CodeLen = 3;
            BAsmCode[2] = AdrInt & 0xff;
          }
        }
      }
    }
  }
}

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

  if (ChkArgCnt(1, 1)
   && ChkMinCPU(CPU80196N))
  {
    Boolean OK;
    LongInt AdrInt = EvalStrIntExpression(&ArgStr[1], MemInt, &OK) - (EProgCounter() + 4);
    if (OK)
    {
      BAsmCode[0] = 0xf1;
      BAsmCode[1] = AdrInt & 0xff;
      BAsmCode[2] = (AdrInt >> 8) & 0xff;
      BAsmCode[3] = (AdrInt >> 16) & 0xff;
      CodeLen = 4;
    }
  }
}

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

  OpSize = 1;
  if (!ChkArgCnt(1, 1));
  else if (!ChkMinCPU(CPU80196N));
  else if (*ArgStr[1].str.p_str == '[')
  {
    DecodeAdr(&ArgStr[1], MModInd, False);
    if (AdrType != ModNone)
    {
      BAsmCode[0] = 0xe3;
      BAsmCode[1] = AdrVals[0] + 1;
      CodeLen = 2;
    }
  }
  else
  {
    Boolean OK;
    LongInt AdrInt = EvalStrIntExpression(&ArgStr[1], MemInt, &OK) - (EProgCounter() + 4);
    if (OK)
    {
      BAsmCode[0] = 0xe6;
      BAsmCode[1] = AdrInt & 0xff;
      BAsmCode[2] = (AdrInt >> 8) & 0xff;
      BAsmCode[3] = (AdrInt >> 16) & 0xff;
      CodeLen = 4;
    }
  }
}

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

static void AddSize(const char *NName, Word NCode, InstProc Proc, Word SizeMask)
{
  int l;
  char SizeName[20];

  if (SizeMask & 2)
    AddInstTable(InstTable, NName, 0x0100 | NCode, Proc);

  l = as_snprintf(SizeName, sizeof(SizeName), "%sB", NName);
  if (SizeMask & 1)
    AddInstTable(InstTable, SizeName, 0x0000 | NCode, Proc);

  if (SizeMask & 4)
  {
    SizeName[l - 1] = 'L';
    AddInstTable(InstTable, SizeName, 0x0200 | NCode, Proc);
  }
}

static void AddFixed(const char *NName, Byte NCode, CPUVar NMin, CPUVar NMax)
{
  if ((MomCPU >= NMin) && (MomCPU <= NMax))
    AddInstTable(InstTable, NName, NCode, DecodeFixed);
}

static void AddALU3(const char *NName, Word NCode)
{
  AddSize(NName, NCode, DecodeALU3, 3);
}

static void AddALU2(const char *NName, Word NCode)
{
  AddSize(NName, NCode, DecodeALU2, 3);
}

static void AddALU1(const char *NName, Word NCode)
{
  AddSize(NName, NCode, DecodeALU1, 3);
}

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

static void AddMac(const char *NName, Word NCode, Boolean NRel)
{
  AddInstTable(InstTable, NName, NCode | (NRel ? 0x100 : 0), DecodeMac);
}

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

static void InitFields(void)
{
  InstTable = CreateInstTable(207);
  SetDynamicInstTable(InstTable);
  AddInstTable(InstTable, "CMPL", 0, DecodeCMPL);
  AddInstTable(InstTable, "PUSH", 0, DecodePUSH_POP);
  AddInstTable(InstTable, "POP" , 1, DecodePUSH_POP);
  if (MomCPU >= CPU80196)
  {
    AddInstTable(InstTable, "BMOV", 0xc1, DecodeBMOV);
    AddInstTable(InstTable, "BMOVI", 0xcd, DecodeBMOV);
  }
  if (MomCPU >= CPU80196N)
    AddInstTable(InstTable, "EBMOVI", 0xe4, DecodeBMOV);
  AddSize("XCH", 0, DecodeXCH, 3);
  AddInstTable(InstTable, "LDBZE", 0xac, DecodeLDBZE_LDBSE);
  AddInstTable(InstTable, "LDBSE", 0xbc, DecodeLDBZE_LDBSE);
  AddInstTable(InstTable, "NORML", 0, DecodeNORML);
  AddInstTable(InstTable, "IDLPD", 0, DecodeIDLPD);
  AddSize("SHR", 0, DecodeShift, 7);
  AddSize("SHL", 1, DecodeShift, 7);
  AddSize("SHRA", 2, DecodeShift, 7);
  AddInstTable(InstTable, "SKIP", 0, DecodeSKIP);
  AddSize("ELD", 0xe8, DecodeELD_EST, 3);
  AddSize("EST", 0x1c, DecodeELD_EST, 3);
  AddInstTable(InstTable, "MVAC", 1, DecodeMVAC_MSAC);
  AddInstTable(InstTable, "MSAC", 3, DecodeMVAC_MSAC);
  AddInstTable(InstTable, "CALL", 0xff, DecodeSCALL_LCALL_CALL);
  AddInstTable(InstTable, "LCALL", 1, DecodeSCALL_LCALL_CALL);
  AddInstTable(InstTable, "SCALL", 0, DecodeSCALL_LCALL_CALL);
  AddInstTable(InstTable, "BR", 0xff, DecodeBR_LJMP_SJMP);
  AddInstTable(InstTable, "LJMP", 1, DecodeBR_LJMP_SJMP);
  AddInstTable(InstTable, "SJMP", 0, DecodeBR_LJMP_SJMP);
  AddInstTable(InstTable, "TIJMP", 0, DecodeTIJMP);
  AddInstTable(InstTable, "DJNZ", 0, DecodeDJNZ_DJNZW);
  AddInstTable(InstTable, "DJNZW", 1, DecodeDJNZ_DJNZW);
  AddInstTable(InstTable, "JBC", 0x30, DecodeJBC_JBS);
  AddInstTable(InstTable, "JBS", 0x38, DecodeJBC_JBS);
  AddInstTable(InstTable, "ECALL", 0, DecodeECALL);
  AddInstTable(InstTable, "EJMP", 0, DecodeEJMP_EBR);
  AddInstTable(InstTable, "EBR", 0, DecodeEJMP_EBR);

  AddFixed("CLRC" , 0xf8, CPU8096  , CPU80296 );
  AddFixed("CLRVT", 0xfc, CPU8096  , CPU80296 );
  AddFixed("DI"   , 0xfa, CPU8096  , CPU80296 );
  AddFixed("DPTS" , 0xec, CPU80196 , CPU80196N);
  AddFixed("EI"   , 0xfb, CPU8096  , CPU80296 );
  AddFixed("EPTS" , 0xed, CPU80196 , CPU80196N);
  AddFixed("NOP"  , 0xfd, CPU8096  , CPU80296 );
  AddFixed("POPA" , 0xf5, CPU80196 , CPU80296 );
  AddFixed("POPF" , 0xf3, CPU8096  , CPU80296 );
  AddFixed("PUSHA", 0xf4, CPU80196 , CPU80296 );
  AddFixed("PUSHF", 0xf2, CPU8096  , CPU80296 );
  AddFixed("RET"  , 0xf0, CPU8096  , CPU80296 );
  AddFixed("RST"  , 0xff, CPU8096  , CPU80296 );
  AddFixed("SETC" , 0xf9, CPU8096  , CPU80296 );
  AddFixed("TRAP" , 0xf7, CPU8096  , CPU80296 );
  AddFixed("RETI" , 0xe5, CPU80196N, CPU80296 );

  AddALU3("ADD" , 0x0001);
  AddALU3("AND" , 0x0000);
  AddALU3("MUL" , 0xc803);
  AddALU3("MULU", 0x4803);
  AddALU3("SUB" , 0x0002);

  AddALU2("ADDC", 0x20a4);
  AddALU2("CMP" , 0x2088);
  AddALU2("DIV" , 0xe88c);
  AddALU2("DIVU", 0x688c);
  AddALU2("LD"  , 0x20a0);
  AddALU2("OR"  , 0x2080);
  AddALU2("ST"  , 0x00c0);
  AddALU2("SUBC", 0x20a8);
  AddALU2("XOR" , 0x2084);

  AddALU1("CLR", 0x0001);
  AddALU1("DEC", 0x0005);
  AddALU1("EXT", 0x8806);
  AddALU1("INC", 0x0007);
  AddALU1("NEG", 0x0003);
  AddALU1("NOT", 0x0002);

  AddRel("JC"   , 0xdb);
  AddRel("JE"   , 0xdf);
  AddRel("JGE"  , 0xd6);
  AddRel("JGT"  , 0xd2);
  AddRel("JH"   , 0xd9);
  AddRel("JLE"  , 0xda);
  AddRel("JLT"  , 0xde);
  AddRel("JNC"  , 0xd3);
  AddRel("JNE"  , 0xd7);
  AddRel("JNH"  , 0xd1);
  AddRel("JNST" , 0xd0);
  AddRel("JNV"  , 0xd5);
  AddRel("JNVT" , 0xd4);
  AddRel("JST"  , 0xd8);
  AddRel("JV"   , 0xdd);
  AddRel("JVT"  , 0xdc);

  AddMac("MAC"   , 0x00, False); AddMac("SMAC"  , 0x01, False);
  AddMac("MACR"  , 0x04, True ); AddMac("SMACR" , 0x05, True );
  AddMac("MACZ"  , 0x08, False); AddMac("SMACZ" , 0x09, False);
  AddMac("MACRZ" , 0x0c, True ); AddMac("SMACRZ", 0x0d, True );

  AddRpt("RPT"    , 0x00); AddRpt("RPTNST" , 0x10); AddRpt("RPTNH"  , 0x11);
  AddRpt("RPTGT"  , 0x12); AddRpt("RPTNC"  , 0x13); AddRpt("RPTNVT" , 0x14);
  AddRpt("RPTNV"  , 0x15); AddRpt("RPTGE"  , 0x16); AddRpt("RPTNE"  , 0x17);
  AddRpt("RPTST"  , 0x18); AddRpt("RPTH"   , 0x19); AddRpt("RPTLE"  , 0x1a);
  AddRpt("RPTC"   , 0x1b); AddRpt("RPTVT"  , 0x1c); AddRpt("RPTV"   , 0x1d);
  AddRpt("RPTLT"  , 0x1e); AddRpt("RPTE"   , 0x1f); AddRpt("RPTI"   , 0x20);
  AddRpt("RPTINST", 0x30); AddRpt("RPTINH" , 0x31); AddRpt("RPTIGT" , 0x32);
  AddRpt("RPTINC" , 0x33); AddRpt("RPTINVT", 0x34); AddRpt("RPTINV" , 0x35);
  AddRpt("RPTIGE" , 0x36); AddRpt("RPTINE" , 0x37); AddRpt("RPTIST" , 0x38);
  AddRpt("RPTIH"  , 0x39); AddRpt("RPTILE" , 0x3a); AddRpt("RPTIC"  , 0x3b);
  AddRpt("RPTIVT" , 0x3c); AddRpt("RPTIV"  , 0x3d); AddRpt("RPTILT" , 0x3e);
  AddRpt("RPTIE"  , 0x3f);
}

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

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

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

  /* zu ignorierendes */

  if (Memo(""))
    return;

  /* Pseudoanweisungen */

  if (DecodeIntelPseudo(False))
    return;

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

static void InitCode_96(void)
{
  WSRVal  = 0; CalcWSRWindow();
  WSR1Val = 0; CalcWSR1Window();
}

static Boolean IsDef_96(void)
{
  return False;
}

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

static ASSUMERec ASSUME96s[] =
{
  {"WSR" , &WSRVal , 0, 0xff, 0x00, CalcWSRWindow  },
  {"WSR1", &WSR1Val, 0, 0xbf, 0x00, CalcWSR1Window },
};

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

  PCSymbol = "$";
  HeaderID = 0x39;
  NOPCode = 0xfd;
  DivideChars = ",";
  HasAttrs = False;

  ValidSegs = 1 << SegCode;
  Grans[SegCode ] = 1;
  ListGrans[SegCode ] = 1;
  SegInits[SegCode ] = 0;
  SegLimits[SegCode] = (MomCPU >= CPU80196N) ? 0xffffffl : 0xffff;

  MakeCode = MakeCode_96;
  IsDef = IsDef_96;
  SwitchFrom = SwitchFrom_96;

  MemInt = (MomCPU >= CPU80196N) ? UInt24 : UInt16;

  if (MomCPU >= CPU80196)
  {
    pASSUMERecs = ASSUME96s;
    ASSUMERecCnt = (MomCPU >= CPU80296) ? (sizeof(ASSUME96s) / sizeof(*ASSUME96s)) : 1;
  }

  InitFields();
}

void code96_init(void)
{
  CPU8096   = AddCPU("8096"  , SwitchTo_96);
  CPU80196  = AddCPU("80196" , SwitchTo_96);
  CPU80196N = AddCPU("80196N", SwitchTo_96);
  CPU80296  = AddCPU("80296" , SwitchTo_96);

  AddInitPassProc(InitCode_96);
}